Compare commits

...

1917 Commits

Author SHA1 Message Date
he bcfa22a818 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 Details
2025-12-11 17:19:47 +08:00
he 0840d57689 修改计算 2025-12-11 17:19:45 +08:00
hang deb7e77263 项目文档默认禁用
continuous-integration/drone/push Build is passing Details
2025-12-11 10:26:16 +08:00
hang aba477a49c 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 Details
2025-12-11 09:37:45 +08:00
hang a9e5a7754e 数据统计修改 2025-12-11 09:37:43 +08:00
he a2d4d100d3 修改邮件
continuous-integration/drone/push Build is passing Details
2025-12-10 16:36:24 +08:00
he 7f4f5e9d08 修改邮件发送
continuous-integration/drone/push Build is passing Details
2025-12-10 15:24:57 +08:00
he 55a2301bb5 稽查翻译修改 OCT06
continuous-integration/drone/push Build is passing Details
2025-12-10 13:59:18 +08:00
he 14ac852eee 修改
continuous-integration/drone/push Build is passing Details
2025-12-10 13:16:36 +08:00
he d2e53c7b8c 修改
continuous-integration/drone/push Build is passing Details
2025-12-10 13:11:45 +08:00
he 4a335d2a28 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 Details
2025-12-10 10:43:22 +08:00
he 999fde1f5c 仲裁验证修改 2025-12-10 10:43:19 +08:00
hang 024e62103a ivus-oct-导表修改-uat-4
continuous-integration/drone/push Build is failing Details
2025-12-09 17:49:13 +08:00
hang 73889c51ae ivus-oct-导表修改-uat-3 2025-12-09 17:49:10 +08:00
hang 7a0b29bda6 ivus-oct-导表修改-uat-2
continuous-integration/drone/push Build is failing Details
2025-12-09 17:32:43 +08:00
hang a592a39fae ivus-oct-导表修改-uat-1 2025-12-09 17:32:40 +08:00
hang aa96ef66c6 修改多选导表
continuous-integration/drone/push Build is failing Details
2025-12-09 13:10:46 +08:00
he 2b24ce723e OCT05
continuous-integration/drone/push Build is failing Details
2025-12-09 10:02:44 +08:00
he 867ee32f91 稽查修改 OCT4
continuous-integration/drone/push Build is failing Details
2025-12-08 17:48:12 +08:00
he 662001accd 稽查修改 OCT4
continuous-integration/drone/push Build is failing Details
2025-12-08 17:17:57 +08:00
he 334b2fe440 OCT修改3
continuous-integration/drone/push Build is failing Details
2025-12-08 16:55:47 +08:00
he 2f728629f3 OCT 修改2
continuous-integration/drone/push Build is failing Details
2025-12-08 16:15:29 +08:00
he eb8628da5b OCT 添加1
continuous-integration/drone/push Build is failing Details
2025-12-08 15:41:09 +08:00
he 1427940224 邮件日志修改
continuous-integration/drone/push Build is failing Details
2025-12-08 13:36:41 +08:00
he 06f10e38f5 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 Details
2025-12-08 13:13:51 +08:00
he 5092f5204f 去除多余的逻辑 2025-12-08 13:13:50 +08:00
hang 13f4420e42 修改项目文档过滤
continuous-integration/drone/push Build is passing Details
2025-12-08 10:38:23 +08:00
he e0e6e60ae0 邮件端口移动到配置文件
continuous-integration/drone/push Build is passing Details
2025-12-08 10:14:21 +08:00
he 9cac49d539 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 Details
2025-12-05 14:54:24 +08:00
he 97d9aefbeb 项目邮件改为项目的发件信息 2025-12-05 14:54:22 +08:00
hang 340119f697 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 Details
2025-12-05 14:13:30 +08:00
hang a075eb34cd 修改签署文档查看 2025-12-05 14:13:30 +08:00
he 53913d3777 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 Details
2025-12-05 14:02:35 +08:00
he c1d79a7e9f 修改邮件中时间的问题 2025-12-05 14:02:33 +08:00
hang 3ee6f0ceaa 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 Details
2025-12-05 14:01:57 +08:00
hang 1821d82ded 中心调研默认配置 2025-12-05 14:01:56 +08:00
hang 476ca95aa3 uat-项目影像下载-dir
continuous-integration/drone/push Build is passing Details
2025-12-05 13:50:11 +08:00
hang d8b799f057 uat-发布导表-1 2025-12-05 13:50:05 +08:00
he 4c4807c22e 添加字段
continuous-integration/drone/push Build is passing Details
2025-12-04 17:24:04 +08:00
he 8a9afc2d9a 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 Details
2025-12-04 14:16:50 +08:00
he 6fcb670a89 OCT导入修改1 2025-12-04 14:16:47 +08:00
hang d224b519f7 修改中心调研返回配置对象bug
continuous-integration/drone/push Build is passing Details
2025-12-04 10:19:23 +08:00
hang b382595767 修改EA 下拉框返回数据
continuous-integration/drone/push Build is passing Details
2025-12-03 17:53:43 +08:00
hang 64ff6f73d4 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 failing Details
2025-12-03 16:21:29 +08:00
hang e1632b58ac lugano 长短经导表修改 2025-12-03 16:21:26 +08:00
he 7e39692cc4 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 failing Details
2025-12-03 15:13:41 +08:00
he 8de44fb7b3 添加重阅复制的逻辑 2025-12-03 15:13:38 +08:00
hang 647aee010a 赋值拷贝表单
continuous-integration/drone/push Build is running Details
2025-12-03 15:12:04 +08:00
hang 296459d38a 全量一致性核查默认排序
continuous-integration/drone/push Build is passing Details
2025-12-03 13:55:12 +08:00
hang 7941328a29 CDISC followUp
continuous-integration/drone/push Build is passing Details
2025-12-03 13:29:27 +08:00
hang 38d9a21a5d lugano 整体肿瘤pd
continuous-integration/drone/push Build is passing Details
2025-12-03 11:33:11 +08:00
he 7d88f49e68 修改被评估为NE的单个靶病灶
continuous-integration/drone/push Build is passing Details
2025-12-03 10:39:15 +08:00
he 3c46215a3c 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 Details
2025-12-03 10:19:36 +08:00
he 137ed07b2b 修改 2025-12-03 10:19:33 +08:00
hang 6f05850fbc 全量一致性核查增加列
continuous-integration/drone/push Build is passing Details
2025-12-02 18:04:38 +08:00
hang 80447f5c7a 修改参数名
continuous-integration/drone/push Build is passing Details
2025-12-02 17:42:06 +08:00
hang 971d94495a 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 Details
2025-12-02 17:30:05 +08:00
hang 77790a1cb2 中心调研增加字段 2025-12-02 17:30:02 +08:00
he ecfadcb5a3 查询基线病灶
continuous-integration/drone/push Build is passing Details
2025-12-02 17:24:32 +08:00
he d9e3b642a5 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 Details
2025-12-02 16:32:00 +08:00
he e56e269f2e 修改 2025-12-02 16:31:59 +08:00
hang 98f7ab8c02 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 Details
2025-12-02 15:35:16 +08:00
hang 5d33bd03a7 修改lugano rs导表肿瘤学 2025-12-02 15:35:13 +08:00
he 55882aa0ba 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 Details
2025-12-02 11:27:15 +08:00
he 43d1a94f22 添加字段 2025-12-02 11:27:11 +08:00
hang 53b2b9156f 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 Details
2025-12-02 10:54:31 +08:00
hang fafc075735 uat-lugano NA% 2025-12-02 10:54:28 +08:00
hang 09ee238e50 uat-ivus-增加标识-31
continuous-integration/drone/push Build is passing Details
2025-12-02 09:18:21 +08:00
hang 7be3813527 CDISC-lugano
continuous-integration/drone/push Build is passing Details
2025-12-01 14:38:11 +08:00
hang e6491a6203 修改导表错误-uat
continuous-integration/drone/push Build is passing Details
2025-12-01 13:21:40 +08:00
he 4955a24d6f 修改
continuous-integration/drone/push Build is passing Details
2025-12-01 10:52:14 +08:00
he 425f53b74c 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 Details
2025-11-28 17:27:13 +08:00
he 2ed9595186 修改 2025-11-28 17:27:12 +08:00
hang 4d1e3beda6 uat-标注-30
continuous-integration/drone/push Build is passing Details
2025-11-28 16:47:08 +08:00
hang 8b0e1b8988 uat-标注-29 2025-11-28 16:47:04 +08:00
he c77682a9ad 修改
continuous-integration/drone/push Build is passing Details
2025-11-28 16:15:58 +08:00
he 8e0ff1f2b2 修改
continuous-integration/drone/push Build is passing Details
2025-11-28 15:31:23 +08:00
he b5e027a553 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 Details
2025-11-28 15:28:16 +08:00
he ef712949ad 修改 2025-11-28 15:28:14 +08:00
hang b429b2cf8c uat-标注-28
continuous-integration/drone/push Build is passing Details
2025-11-28 14:19:24 +08:00
hang 9fb95c3030 uat-标注-27 2025-11-28 14:19:21 +08:00
hang 6883d47508 uat-标注-26 2025-11-28 14:19:19 +08:00
hang dae44745ca uat-标注-25 2025-11-28 14:19:16 +08:00
hang 24b7d2e1b9 uat-标注-24 2025-11-28 14:19:13 +08:00
hang 21ac6850d2 uat-标注-23 2025-11-28 14:19:10 +08:00
hang 8b69a07b93 uat-标注-22 2025-11-28 14:19:07 +08:00
hang f92bf347e3 uat-标注-21 2025-11-28 14:18:51 +08:00
hang 78669051de uat-标注-20 2025-11-28 14:18:05 +08:00
hang ea90b2b38b uat-标注-19 2025-11-28 14:18:02 +08:00
hang bd61a0f2e9 uat-标注-18 2025-11-28 14:17:59 +08:00
hang 888ad8897e uat-标注-17 2025-11-28 14:17:56 +08:00
hang eb18021988 uat-标注-16 2025-11-28 14:17:53 +08:00
he 7b243a9615 修改
continuous-integration/drone/push Build is passing Details
2025-11-28 14:07:54 +08:00
he 5716c4169a 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 failing Details
2025-11-28 11:36:49 +08:00
he abb9f47646 邮件临时修改 2025-11-28 11:36:47 +08:00
hang 9a5221ef7d 调整ivus导表位置
continuous-integration/drone/push Build is failing Details
2025-11-27 17:31:56 +08:00
hang d9eaa06de3 中心调研返回空对象,方便前端渲染
continuous-integration/drone/push Build is failing Details
2025-11-27 15:20:56 +08:00
hang 4f91874b82 uat-标注-15
continuous-integration/drone/push Build is passing Details
2025-11-27 10:57:51 +08:00
hang 139438133d uat-标注-14 2025-11-27 10:57:48 +08:00
hang 6705cf0fc0 uat-标注-13 2025-11-27 10:57:46 +08:00
hang 00255e902c uat-标注-12 2025-11-27 10:57:43 +08:00
hang 71e867156f uat-标注-11 2025-11-27 10:57:41 +08:00
hang 658f437f73 uat-标注-10 2025-11-27 10:57:39 +08:00
hang 95bf613263 非dicom检查预览 2025-11-27 10:57:36 +08:00
hang 03d61347ca uat-标注-8 2025-11-27 10:57:32 +08:00
hang 050a0875fe uat-标注-7 2025-11-27 10:57:30 +08:00
hang d9c46acb03 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 Details
2025-11-27 10:56:07 +08:00
hang f19fc0e92f ivus-导表修改 2025-11-27 10:56:05 +08:00
he 3bc4b86749 ExtImaging 修改
continuous-integration/drone/push Build is passing Details
2025-11-26 16:55:05 +08:00
he 43455da7bc 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 Details
2025-11-26 11:37:05 +08:00
he 0030eac22e 修改 2025-11-26 11:37:00 +08:00
hang 671c071a45 uat-标注增加访视Id-6
continuous-integration/drone/push Build is passing Details
2025-11-25 18:01:23 +08:00
hang 3419015542 uat-标注增加访视Id-5 2025-11-25 18:01:20 +08:00
hang 3eea6cf8b7 uat-标注增加访视Id-4 2025-11-25 18:01:17 +08:00
hang 2c407c6e4e uat-标注增加访视Id-3 2025-11-25 18:01:15 +08:00
hang ab90591e7c uat-标注增加访视Id-2 2025-11-25 18:01:12 +08:00
hang 33a2b7f373 uat-标注增加访视Id-1 2025-11-25 18:01:09 +08:00
hang 9158f28998 医学审核对话导表 2025-11-25 09:56:51 +08:00
hang 680a6cb437 非dicom bodyPart 修改
continuous-integration/drone/push Build is passing Details
2025-11-24 15:40:12 +08:00
hang 21c19f4b6d 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 Details
2025-11-24 14:29:32 +08:00
hang 8c03167f7e 修改检查部位bug 2025-11-24 14:29:24 +08:00
he b629b2eec4 修改报告图表
continuous-integration/drone/push Build is passing Details
2025-11-24 13:37:09 +08:00
he 01af8f72d3 修改
continuous-integration/drone/push Build is passing Details
2025-11-21 11:35:42 +08:00
he 4d10db054c 修改
continuous-integration/drone/push Build is passing Details
2025-11-21 11:17:54 +08:00
he a019a542b0 修改
continuous-integration/drone/push Build is passing Details
2025-11-21 11:12:11 +08:00
he b42325337e 修改
continuous-integration/drone/push Build is passing Details
2025-11-20 14:28:54 +08:00
he a3152bb6e1 页面修改
continuous-integration/drone/push Build is passing Details
2025-11-20 13:34:02 +08:00
he 4ec0441d28 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 Details
2025-11-20 10:34:16 +08:00
he 9adc8a93b1 修改 2025-11-20 10:34:15 +08:00
hang 3f3d1a562b 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 Details
2025-11-19 17:41:05 +08:00
hang 1b6ba91240 修改肿瘤CDISC 部位 2025-11-19 17:41:01 +08:00
he c406976a6d 修改
continuous-integration/drone/push Build is passing Details
2025-11-19 16:30:13 +08:00
he d213fa7a99 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 Details
2025-11-19 16:29:16 +08:00
he 60707150a6 对话拼接 2025-11-19 16:29:09 +08:00
hang 008906d245 subjectcode 查询掉了
continuous-integration/drone/push Build is passing Details
2025-11-19 14:23:43 +08:00
hang 762b8b7425 分页处理
continuous-integration/drone/push Build is passing Details
2025-11-19 14:05:08 +08:00
hang 24228428fa 返回subject 标注的非dicom检查数量
continuous-integration/drone/push Build is passing Details
2025-11-19 13:59:19 +08:00
he 9148651556 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 Details
2025-11-19 10:33:49 +08:00
he 1c9c3eb893 修改 2025-11-19 10:33:48 +08:00
hang 17e0517e5b 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 Details
2025-11-19 10:24:46 +08:00
hang 7662880352 oct-ivus-修改1 2025-11-19 10:24:43 +08:00
he c3c433244e 报告修改
continuous-integration/drone/push Build is passing Details
2025-11-18 17:25:07 +08:00
he df65d592ad 添加ShowChartTypeEnum
continuous-integration/drone/push Build is passing Details
2025-11-18 16:18:59 +08:00
he 7873523c1b 修改
continuous-integration/drone/push Build is passing Details
2025-11-18 15:48:36 +08:00
he 8b5800b32e 新增受试者需要确认基线计划
continuous-integration/drone/push Build is passing Details
2025-11-18 11:43:53 +08:00
he 2e46791466 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 Details
2025-11-18 10:40:10 +08:00
he fc0ef2e89f 修改授权 2025-11-18 10:40:08 +08:00
hang 1de687cbf3 放开lugano CDISC 导表
continuous-integration/drone/push Build is passing Details
2025-11-17 13:39:04 +08:00
he 3a017dbfa3 修改发件人名称
continuous-integration/drone/push Build is passing Details
2025-11-17 11:09:17 +08:00
he 1f828b403b 发送邮件的时候 替换项目发件人姓名
continuous-integration/drone/push Build is failing Details
2025-11-17 09:20:55 +08:00
he f75fafaa42 修改路径
continuous-integration/drone/push Build is passing Details
2025-11-14 15:59:13 +08:00
he 7c561a4656 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 Details
2025-11-14 14:52:54 +08:00
he 033b849bdc 添加字段 2025-11-14 14:52:53 +08:00
hang 8ae0b0d621 提交后允许删除检查特殊逻辑修改
continuous-integration/drone/push Build is passing Details
2025-11-14 13:26:33 +08:00
he b6bad061b7 修改
continuous-integration/drone/push Build is passing Details
2025-11-14 11:41:36 +08:00
he 1dd8515ac2 修改
continuous-integration/drone/push Build is passing Details
2025-11-13 11:30:42 +08:00
he 9f3bb29004 添加 获取报告图表
continuous-integration/drone/push Build is passing Details
2025-11-13 10:15:43 +08:00
he 52dd676cf9 修改
continuous-integration/drone/push Build is passing Details
2025-11-13 09:25:03 +08:00
he 342b567e2c 修改
continuous-integration/drone/push Build is passing Details
2025-11-12 17:00:25 +08:00
he 35ee76be0b 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 Details
2025-11-12 16:39:04 +08:00
he b4d40a4770 修改映射 2025-11-12 16:39:03 +08:00
hang 84bfcb4d3e 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 Details
2025-11-12 16:32:35 +08:00
hang f030ed9b66 修改访视点备注赋值日期 2025-11-12 16:32:33 +08:00
he c6920a1995 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 Details
2025-11-12 16:19:15 +08:00
he 2d681ce6bc 修改 2025-11-12 16:19:14 +08:00
hang 3981f2cd50 百分比处理
continuous-integration/drone/push Build is passing Details
2025-11-12 16:15:05 +08:00
hang 2b961c7985 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 Details
2025-11-12 15:47:50 +08:00
hang fb2fdd2c27 导表修改排序 2025-11-12 15:47:47 +08:00
he f6bcefd1e8 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 Details
2025-11-12 15:21:34 +08:00
he 1d7b28e7f9 新加阅片关键点 2025-11-12 15:21:31 +08:00
hang 3ea2bdfc92 修改裁判备注
continuous-integration/drone/push Build is passing Details
2025-11-12 15:14:29 +08:00
hang 4aa0161c41 co表 导出质量评估,备注是空那么就忽略
continuous-integration/drone/push Build is passing Details
2025-11-12 14:29:14 +08:00
hang ff4ab39025 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 Details
2025-11-12 13:38:09 +08:00
hang bb35ae1b9a 修改输出日期bug 2025-11-12 13:38:08 +08:00
he 0e0ce59d74 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 Details
2025-11-12 11:45:05 +08:00
he 82d3157e2a 添加表 2025-11-12 11:45:03 +08:00
hang 12cb53b167 导表增加备注
continuous-integration/drone/push Build is passing Details
2025-11-12 11:35:36 +08:00
hang 5fc53a1999 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 Details
2025-11-11 16:37:08 +08:00
hang b712abd1d5 导表co表修改 2025-11-11 16:37:06 +08:00
he a1c13b5850 添加验证
continuous-integration/drone/push Build is passing Details
2025-11-11 16:30:39 +08:00
he a0fe7be308 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 Details
2025-11-11 14:08:57 +08:00
he bbfa966b57 修改 2025-11-11 14:08:54 +08:00
hang 6d11fc68b4 导出百分比修改
continuous-integration/drone/push Build is passing Details
2025-11-11 13:20:30 +08:00
hang eef764dd90 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 Details
2025-11-11 10:58:09 +08:00
hang 8423b00bec 修改导表报错 2025-11-11 10:58:07 +08:00
he dbaac006c7 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 Details
2025-11-11 10:45:18 +08:00
he 510c73dd24 修改复制病灶的逻辑 2025-11-11 10:45:16 +08:00
hang 41486798d2 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 Details
2025-11-11 09:58:34 +08:00
hang f40faa5519 修改病灶排序,和拍片日期以及PD 2025-11-11 09:58:32 +08:00
he eecfe6dcae 修改
continuous-integration/drone/push Build is passing Details
2025-11-10 18:06:53 +08:00
he 8a004ef35f 修改
continuous-integration/drone/push Build is passing Details
2025-11-10 18:01:48 +08:00
he 369805e6c6 修改
continuous-integration/drone/push Build is passing Details
2025-11-10 17:37:32 +08:00
he 93b93f6a3a 修改
continuous-integration/drone/push Build is passing Details
2025-11-10 16:08:12 +08:00
he 9fbee7e0c9 修改
continuous-integration/drone/push Build is passing Details
2025-11-10 14:16:06 +08:00
he 46704d5299 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 Details
2025-11-10 09:35:33 +08:00
he 4225014cdd 代码修改 2025-11-10 09:35:31 +08:00
hang ae36d4680a 分裂类型对应
continuous-integration/drone/push Build is passing Details
2025-11-07 15:07:27 +08:00
hang d48f736392 修改tu表bug
continuous-integration/drone/push Build is passing Details
2025-11-07 14:54:25 +08:00
hang b0d8a49929 分裂病灶加个判断
continuous-integration/drone/push Build is passing Details
2025-11-07 14:48:35 +08:00
hang e45791c676 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 Details
2025-11-07 14:41:03 +08:00
hang ca425c602b 修改病灶排序 2025-11-07 14:41:01 +08:00
he 44e7ffaeeb 修改筛选
continuous-integration/drone/push Build is passing Details
2025-11-07 14:31:29 +08:00
he cf42b2e57f 修改
continuous-integration/drone/push Build is passing Details
2025-11-07 14:20:14 +08:00
he 840de08e69 文档
continuous-integration/drone/push Build is passing Details
2025-11-07 13:40:25 +08:00
he 929903aa1b 修改
continuous-integration/drone/push Build is passing Details
2025-11-07 13:19:21 +08:00
he 5eafcc9c8c 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 Details
2025-11-07 11:47:59 +08:00
he a1657f5827 修改 2025-11-07 11:47:57 +08:00
hang dff2e712ad 中心调研发送邮件bug 修改
continuous-integration/drone/push Build is passing Details
2025-11-07 10:12:24 +08:00
hang a5f3430965 MFA bug 修改
continuous-integration/drone/push Build is passing Details
2025-11-07 09:19:52 +08:00
hang 5059d66aa1 修改传递参数
continuous-integration/drone/push Build is passing Details
2025-11-06 15:25:52 +08:00
hang 668af5ee0b 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 Details
2025-11-06 15:05:10 +08:00
hang a70caefe01 肿瘤CDISC 导出初步提交 2025-11-06 15:05:09 +08:00
he 64bd6a5604 修改
continuous-integration/drone/push Build is passing Details
2025-11-06 13:54:05 +08:00
he b68deafa82 修改
continuous-integration/drone/push Build is passing Details
2025-11-06 11:09:16 +08:00
he d29c150081 修改
continuous-integration/drone/push Build is passing Details
2025-11-06 10:47:57 +08:00
he 4d3ecd05dc 邮件修改
continuous-integration/drone/push Build is passing Details
2025-11-06 09:59:19 +08:00
he 143d7f0c4b 修改
continuous-integration/drone/push Build is passing Details
2025-11-05 17:05:09 +08:00
he 4d2f04b30e 邮件日志
continuous-integration/drone/push Build is passing Details
2025-11-05 16:58:02 +08:00
he 955ca4a1a6 添加双屏
continuous-integration/drone/push Build is passing Details
2025-11-05 13:23:30 +08:00
he 6e92895043 修改
continuous-integration/drone/push Build is passing Details
2025-11-05 11:46:32 +08:00
he 6102309828 修改
continuous-integration/drone/push Build is passing Details
2025-11-05 11:37:03 +08:00
he 8f34644d45 修改
continuous-integration/drone/push Build is passing Details
2025-11-04 16:08:57 +08:00
he f347b34f59 修改
continuous-integration/drone/push Build is passing Details
2025-11-04 11:11:37 +08:00
he dc7e71dc74 修改
continuous-integration/drone/push Build is passing Details
2025-11-04 10:48:43 +08:00
he 749bf95761 修改
continuous-integration/drone/push Build is passing Details
2025-11-04 10:38:05 +08:00
he a67472c9b4 阅片期修改
continuous-integration/drone/push Build is running Details
2025-11-04 10:37:15 +08:00
he 32c8d70179 修改bug
continuous-integration/drone/push Build is passing Details
2025-11-03 14:47:56 +08:00
he 510dfcac30 添加阅片期计划
continuous-integration/drone/push Build is passing Details
2025-11-03 14:22:41 +08:00
he 9b59a55423 添加 阅片期添加类型字段
continuous-integration/drone/push Build is passing Details
2025-10-31 18:16:14 +08:00
he 0bd269f93e 修改数据库可插入null
continuous-integration/drone/push Build is passing Details
2025-10-31 16:56:45 +08:00
he e55a13cfb1 修改
continuous-integration/drone/push Build is passing Details
2025-10-31 16:16:55 +08:00
he 1617de2fc1 修改
continuous-integration/drone/push Build is passing Details
2025-10-31 13:49:13 +08:00
he 40c3ea65ff 排序处理
continuous-integration/drone/push Build is passing Details
2025-10-30 14:19:47 +08:00
he 541e000183 PCWG修改
continuous-integration/drone/push Build is passing Details
2025-10-29 13:55:05 +08:00
he 0e93894ed8 修改
continuous-integration/drone/push Build is passing Details
2025-10-29 13:24:23 +08:00
he 7f1621915f 邮件修改
continuous-integration/drone/push Build is passing Details
2025-10-29 10:30:32 +08:00
he 70e4829f32 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 Details
2025-10-29 09:50:40 +08:00
he c77b3d74c8 代码修改 2025-10-29 09:50:37 +08:00
hang 1f4ea09bc6 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 Details
2025-10-28 15:15:21 +08:00
hang c45020f24f 修改数组默认值 2025-10-28 15:15:20 +08:00
he ca679057c4 邮件代码提交
continuous-integration/drone/push Build is passing Details
2025-10-28 14:35:43 +08:00
he 456793293b 添加实体
continuous-integration/drone/push Build is failing Details
2025-10-28 14:32:40 +08:00
he 75d3908911 添加邮件日志表
continuous-integration/drone/push Build is passing Details
2025-10-28 14:21:38 +08:00
he a7fbd00530 邮件日志
continuous-integration/drone/push Build is passing Details
2025-10-28 11:40:45 +08:00
he 785d5ec869 重置修改
continuous-integration/drone/push Build is passing Details
2025-10-28 09:38:34 +08:00
he c5feb98ed8 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 Details
2025-10-28 09:38:04 +08:00
he 121b1d4eb4 邮件 2025-10-28 09:37:49 +08:00
hang 8e2b99333c 中心调研邮件修改
continuous-integration/drone/push Build is passing Details
2025-10-28 09:27:12 +08:00
he 5bd055c77d 修改
continuous-integration/drone/push Build is passing Details
2025-10-27 13:22:05 +08:00
he 5ea9d63cb9 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 Details
2025-10-27 11:22:34 +08:00
he 0134d6c723 修改比例尺修改答案 2025-10-27 11:22:32 +08:00
hang a9c80a670b 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 Details
2025-10-27 10:48:35 +08:00
hang 998b92aa79 评估统计初步增加 2025-10-27 10:48:31 +08:00
he 60ce8c45b2 修改
continuous-integration/drone/push Build is passing Details
2025-10-24 16:26:41 +08:00
he a66d25f564 添加IsHaveBindingQuestion
continuous-integration/drone/push Build is passing Details
2025-10-24 16:11:16 +08:00
he 91b66660a6 修改答案
continuous-integration/drone/push Build is passing Details
2025-10-24 14:19:04 +08:00
he 1031222e47 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 Details
2025-10-24 10:45:12 +08:00
he 2005eacaa9 添加字段 2025-10-24 10:45:09 +08:00
hang b581afebe6 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 Details
2025-10-24 10:12:24 +08:00
hang 1532ac4a7e 修改一致性全量核查 2025-10-24 10:12:22 +08:00
he 231b3f71c5 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 Details
2025-10-23 16:58:05 +08:00
he 308f5140a1 修改比例尺 2025-10-23 16:58:03 +08:00
hang ef673fc44b 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 Details
2025-10-23 16:27:24 +08:00
hang f347b0cace 修改一致性核查bug 2025-10-23 16:27:23 +08:00
he 102cf5f6dc 修改
continuous-integration/drone/push Build is passing Details
2025-10-23 15:15:38 +08:00
he d9ca71009f 修改标记返回
continuous-integration/drone/push Build is passing Details
2025-10-23 14:59:50 +08:00
he 114ee50273 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 Details
2025-10-23 14:58:32 +08:00
he 54bb66f738 邮件添加 2025-10-23 14:58:28 +08:00
hang 19f52bc133 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 Details
2025-10-23 14:13:03 +08:00
hang 2439dec9fb 中心调研额外配置 2025-10-23 14:12:59 +08:00
he fb0fd7d91f 修改
continuous-integration/drone/push Build is passing Details
2025-10-22 17:39:54 +08:00
he 3765b390a6 添加字段
continuous-integration/drone/push Build is running Details
2025-10-22 17:38:35 +08:00
he f6be3186e7 修改非Dicom
continuous-integration/drone/push Build is passing Details
2025-10-22 15:12:37 +08:00
he 7399568e36 添加标记修改
continuous-integration/drone/push Build is passing Details
2025-10-22 14:14:36 +08:00
he 37d798627a 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 Details
2025-10-22 13:57:32 +08:00
he fe2a375b4e 标记代码修改 2025-10-22 13:57:29 +08:00
hang 70443b7b8d 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 Details
2025-10-22 10:25:13 +08:00
hang 7a37c01b7f 归档增加字段-三个影像层级表 2025-10-22 10:25:11 +08:00
he 7215c75f5a 修改
continuous-integration/drone/push Build is passing Details
2025-10-21 15:50:18 +08:00
he a34c47dc3c 获取当前版本的用户协议和隐私采集
continuous-integration/drone/push Build is passing Details
2025-10-21 15:40:42 +08:00
he 6fdad9a482 添加接口
continuous-integration/drone/push Build is passing Details
2025-10-21 14:34:20 +08:00
he 08e62e4500 修改
continuous-integration/drone/push Build is passing Details
2025-10-21 13:34:13 +08:00
he 3cfb4556f3 修改
continuous-integration/drone/push Build is running Details
2025-10-21 13:32:36 +08:00
he b8e3e83b80 修改
continuous-integration/drone/push Build is passing Details
2025-10-21 13:24:30 +08:00
he 7e9bf65f9f 修改
continuous-integration/drone/push Build is passing Details
2025-10-21 13:16:59 +08:00
he 5197e49c1f 添加适用的标准
continuous-integration/drone/push Build is failing Details
2025-10-21 13:09:53 +08:00
he 7880836f39 修改
continuous-integration/drone/push Build is passing Details
2025-10-21 11:39:29 +08:00
he 487eb9dca8 保存答案和非Dicom标记绑定关系
continuous-integration/drone/push Build is passing Details
2025-10-21 11:29:11 +08:00
he 473cee0e30 融合修改
continuous-integration/drone/push Build is passing Details
2025-10-21 10:40:03 +08:00
he 817cdcc8f7 修改
continuous-integration/drone/push Build is passing Details
2025-10-21 10:27:33 +08:00
he bf03430958 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 Details
2025-10-21 10:25:52 +08:00
he 58321c4c82 非Dicom标记绑定 2025-10-21 10:25:49 +08:00
hang 8cabc8c96a 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 Details
2025-10-20 17:41:02 +08:00
hang 7f050a1dd6 稽查通用缓存添加 2025-10-20 17:41:00 +08:00
he e5e2a0394b 用户隐私修改
continuous-integration/drone/push Build is passing Details
2025-10-20 17:34:34 +08:00
he a56ab0680b 修改自定义标准 病灶复制前值
continuous-integration/drone/push Build is passing Details
2025-10-20 17:15:08 +08:00
he ee13d0ae2e 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 Details
2025-10-20 17:05:38 +08:00
he ee2c66c8fb 预设和复制病灶修改 2025-10-20 17:05:37 +08:00
hang f1fb2068de 全量一致性核查初次提交
continuous-integration/drone/push Build is passing Details
2025-10-20 16:49:46 +08:00
he 95e0239e42 修改预设与复制的冲突
continuous-integration/drone/push Build is passing Details
2025-10-20 16:19:32 +08:00
he 0b28ef5461 添加字段
continuous-integration/drone/push Build is passing Details
2025-10-20 15:52:18 +08:00
he 68fe2b75dc 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 failing Details
2025-10-20 15:34:14 +08:00
he ecfeee1693 添加用户协议与隐私政策 2025-10-20 15:34:11 +08:00
hang 9cda4360ca MFA 需求修改
continuous-integration/drone/push Build is failing Details
2025-10-20 13:40:52 +08:00
hang 18b9c08101 修改项目编辑映射
continuous-integration/drone/push Build is passing Details
2025-10-17 16:04:31 +08:00
he d4e89aec20 Lugano 分裂修改
continuous-integration/drone/push Build is passing Details
2025-10-17 14:53:04 +08:00
he 01a3a9057b 异地登录修改
continuous-integration/drone/push Build is passing Details
2025-10-17 11:32:17 +08:00
he 2107a42e37 修改验证重复提交
continuous-integration/drone/push Build is passing Details
2025-10-17 09:40:36 +08:00
he d96e746db7 修改接口重复验证
continuous-integration/drone/push Build is passing Details
2025-10-16 14:53:43 +08:00
he be034d4d8b 修改
continuous-integration/drone/push Build is passing Details
2025-10-16 14:46:34 +08:00
he ca44b4786a 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 Details
2025-10-16 14:28:17 +08:00
he 74056167d6 重复请求拦截修改 2025-10-16 14:28:15 +08:00
hang e6aec6b559 MFA状态持久管理修改
continuous-integration/drone/push Build is passing Details
2025-10-16 14:10:11 +08:00
hang 9a488610da 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 Details
2025-10-16 13:16:34 +08:00
hang f82420b7ef 修改备注 2025-10-16 13:16:32 +08:00
he fbeaec2820 修改
continuous-integration/drone/push Build is passing Details
2025-10-16 09:23:10 +08:00
he b4907bfe9b 代码修改
continuous-integration/drone/push Build is passing Details
2025-10-15 17:41:43 +08:00
he 6e75e45942 修改
continuous-integration/drone/push Build is passing Details
2025-10-15 17:23:18 +08:00
he 3292b9f978 请求频繁验证
continuous-integration/drone/push Build is passing Details
2025-10-15 15:56:32 +08:00
he 1959045ab2 修改计算
continuous-integration/drone/push Build is passing Details
2025-10-15 10:12:46 +08:00
he 6a99e3104a 验证修改
continuous-integration/drone/push Build is passing Details
2025-10-14 14:28:06 +08:00
he ab91d360b1 服务修改
continuous-integration/drone/push Build is passing Details
2025-10-14 14:20:23 +08:00
he 50a4a82819 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 Details
2025-10-14 14:07:08 +08:00
he 498c02431b 修改luganno 2025-10-14 14:07:06 +08:00
hang fd54d64ae3 用户发送邮件-一致性分析导出代码删除了
continuous-integration/drone/push Build is passing Details
2025-10-14 10:44:48 +08:00
hang ac80e3a455 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 Details
2025-10-13 16:28:56 +08:00
hang c6a55949b3 增加查询条件修改 2025-10-13 16:28:53 +08:00
he 18547cdec1 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 Details
2025-10-13 16:19:19 +08:00
he d29707c8ee 修改 2025-10-13 16:19:17 +08:00
hang c7e29116dd 稽查记录管理修改-是否查看培训记录
continuous-integration/drone/push Build is passing Details
2025-10-13 16:01:21 +08:00
hang a85cc1236c 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 Details
2025-10-11 15:38:41 +08:00
hang 7b4c603fa6 修改访视计划确认 2025-10-11 15:38:34 +08:00
he 67c93e654e 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 Details
2025-10-10 15:49:31 +08:00
he 9b0c874314 添加表格预设 2025-10-10 15:49:29 +08:00
hang d172e48c79 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 Details
2025-10-10 14:24:08 +08:00
hang 2a2419af90 记录匿名登录,退出账号用户名 2025-10-10 14:24:04 +08:00
he 7e39094b13 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 Details
2025-10-09 15:38:32 +08:00
he 8936e9db99 PCWG LastTaskState 取值修改 2025-10-09 15:38:30 +08:00
hang bd92d48232 修改备注
continuous-integration/drone/push Build is passing Details
2025-10-09 10:54:55 +08:00
hang 57f7b29cc7 合并解决
continuous-integration/drone/push Build is passing Details
2025-09-30 10:02:33 +08:00
hang f55f498626 增加gpt 方法 2025-09-30 10:01:20 +08:00
he 955fe25d30 重新发布
continuous-integration/drone/push Build is passing Details
2025-09-29 15:19:34 +08:00
he 86c24e6002 修改
continuous-integration/drone/push Build is passing Details
2025-09-29 15:12:06 +08:00
hang b835a028ad 修改取消授权
continuous-integration/drone/push Build is passing Details
2025-09-29 13:58:33 +08:00
hang c8d5b94154 人员下拉框过滤
continuous-integration/drone/push Build is passing Details
2025-09-29 13:42:27 +08:00
hang d03d294e97 优化列表查询,以及稽查记录过滤
continuous-integration/drone/push Build is passing Details
2025-09-29 13:39:06 +08:00
he 28014139f5 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 Details
2025-09-29 11:01:48 +08:00
he b42a86922e 拷贝和移动 2025-09-29 11:01:46 +08:00
hang 09bf2b4d91 重建闭包表修改
continuous-integration/drone/push Build is passing Details
2025-09-29 10:44:40 +08:00
hang 3685686447 EA 查看记录 用户 文件级别修改
continuous-integration/drone/push Build is running Details
2025-09-29 10:42:41 +08:00
hang b6d2128034 编译错误
continuous-integration/drone/push Build is passing Details
2025-09-29 10:31:57 +08:00
hang 9545e699c2 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 Details
2025-09-29 10:30:10 +08:00
hang 87955d2ca0 修改用户列表选择 2025-09-29 10:30:09 +08:00
he 0a8573091e 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 failing Details
2025-09-29 10:21:46 +08:00
he a713ffdc61 移动文件夹修改 2025-09-29 10:21:44 +08:00
hang 406235cc03 修改稽查记录人员管理
continuous-integration/drone/push Build is failing Details
2025-09-29 10:17:22 +08:00
hang 1095e07f87 修改授权临时提交
continuous-integration/drone/push Build is passing Details
2025-09-29 10:09:47 +08:00
hang 14b8cbac23 移动到根目录打开测试
continuous-integration/drone/push Build is passing Details
2025-09-28 19:44:53 +08:00
hang 92063da2bf 测试拷贝到根目录
continuous-integration/drone/push Build is passing Details
2025-09-28 19:38:24 +08:00
hang 9c6b835800 修改过滤时间
continuous-integration/drone/push Build is passing Details
2025-09-28 17:36:33 +08:00
hang f71b71bb54 编译错误
continuous-integration/drone/push Build is passing Details
2025-09-28 17:19:33 +08:00
hang 6d39e72506 删除稽查记录用户
continuous-integration/drone/push Build is running Details
2025-09-28 17:18:25 +08:00
hang a90edaff51 修改稽查记录选择
continuous-integration/drone/push Build is failing Details
2025-09-28 16:54:13 +08:00
hang bb8fb0a968 管理和查看 bug
continuous-integration/drone/push Build is passing Details
2025-09-28 16:20:22 +08:00
hang 348ca93086 修改授权查询参数
continuous-integration/drone/push Build is passing Details
2025-09-28 15:49:38 +08:00
hang e3b2046cb8 修改稽查记录管理 默认列表
continuous-integration/drone/push Build is passing Details
2025-09-28 15:41:39 +08:00
hang 99350c3a17 修改提交事务位置
continuous-integration/drone/push Build is passing Details
2025-09-28 15:31:19 +08:00
hang 1523450b88 批量授权修改
continuous-integration/drone/push Build is running Details
2025-09-28 15:30:44 +08:00
hang fb20b1f1b2 修改稽查记录设置授权
continuous-integration/drone/push Build is passing Details
2025-09-28 15:22:52 +08:00
hang 5c90b66fc9 修改参数名字
continuous-integration/drone/push Build is passing Details
2025-09-28 15:07:04 +08:00
hang bc1a6562d5 修改编辑人员重复添加
continuous-integration/drone/push Build is passing Details
2025-09-28 14:58:35 +08:00
hang be1fbf2059 修改稽查文档闭包修改
continuous-integration/drone/push Build is passing Details
2025-09-28 14:25:05 +08:00
hang 7a3bbbeb19 修改稽查文档查询条件,和返回信息
continuous-integration/drone/push Build is passing Details
2025-09-28 10:17:49 +08:00
hang d263ecbe2a 闭包针对稽查的修改
continuous-integration/drone/push Build is passing Details
2025-09-27 23:35:22 +08:00
hang 447e916564 增加稽查记录修改
continuous-integration/drone/push Build is passing Details
2025-09-26 18:14:03 +08:00
hang 48c9721ab4 手动通过的时候设置时间
continuous-integration/drone/push Build is passing Details
2025-09-25 16:19:18 +08:00
he e641e78fb3 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 Details
2025-09-23 11:15:43 +08:00
he d37c1cb872 修改 2025-09-23 11:15:41 +08:00
hang da2afd0d5a 后处理检查bug修复2
continuous-integration/drone/push Build is passing Details
2025-09-22 15:14:07 +08:00
hang 09305928ed 后处理检查bug修复
continuous-integration/drone/push Build is passing Details
2025-09-22 14:58:08 +08:00
hang e16fd2f4de 后处理增加查询字段
continuous-integration/drone/push Build is passing Details
2025-09-22 11:53:09 +08:00
hang b2389403d9 推送记录增加监控字段
continuous-integration/drone/push Build is passing Details
2025-09-19 15:45:34 +08:00
hang 29c137a2c5 影像库增加新的字段,后处理上传、scp服务修改
continuous-integration/drone/push Build is running Details
2025-09-19 15:43:02 +08:00
hang 2e1a68fa14 修改存放日志路径
continuous-integration/drone/push Build is passing Details
2025-09-17 15:43:44 +08:00
hang 7ec76f6ce3 恢复数据测试
continuous-integration/drone/push Build is passing Details
2025-09-17 15:30:11 +08:00
hang 87e70447f3 修改检查数量
continuous-integration/drone/push Build is passing Details
2025-09-16 17:13:34 +08:00
hang f72e3f4300 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 Details
2025-09-16 17:03:45 +08:00
hang 7154196667 维护数据初步提交 2025-09-16 17:03:41 +08:00
he 0081cf16d0 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 Details
2025-09-16 16:00:56 +08:00
he 2eec5f02da 添加查看检查部位 2025-09-16 16:00:52 +08:00
hang 4b011ee727 修改下载的时候修改任务名字
continuous-integration/drone/push Build is passing Details
2025-09-16 14:07:35 +08:00
hang b115dd5253 下载过滤非dicom文件
continuous-integration/drone/push Build is passing Details
2025-09-16 10:35:22 +08:00
hang 84349c19e7 维护数据第二次提交
continuous-integration/drone/push Build is passing Details
2025-09-16 10:19:14 +08:00
hang 84d08c0378 下载删除标记方法提交 2025-09-16 10:19:11 +08:00
he 197aa9bf0a 排除访视问题必填验证
continuous-integration/drone/push Build is passing Details
2025-09-16 09:10:27 +08:00
he f83819d0c9 res 同步病灶调整
continuous-integration/drone/push Build is passing Details
2025-09-15 14:41:44 +08:00
he 43c0885e0a 修改 2025-09-15 14:41:41 +08:00
he 1cff4f7603 MRECISTHCC 同步病灶 2025-09-15 14:41:39 +08:00
hang 71f978609b 影像检查的部位 增加字段
continuous-integration/drone/push Build is passing Details
2025-09-15 13:24:13 +08:00
hang 774e7ccc25 受试者访视中止 增加原因
continuous-integration/drone/push Build is passing Details
2025-09-15 11:00:50 +08:00
he c89b65b550 修改bug
continuous-integration/drone/push Build is passing Details
2025-09-12 16:52:48 +08:00
hang a8800b01f3 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 Details
2025-09-12 16:14:57 +08:00
hang fcc2a68618 新增维护项目数据接口 2025-09-12 16:14:56 +08:00
he a353c90bf7 MRECISTHCCC 同步病灶修改
continuous-integration/drone/push Build is passing Details
2025-09-12 13:40:32 +08:00
he 8e730fc342 修改复制 recist1.1 淋巴结病灶状态
continuous-integration/drone/push Build is passing Details
2025-09-12 11:32:30 +08:00
he 53149bf8a0 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 pending Details
2025-09-12 11:31:32 +08:00
he b2d681da09 删除FristAddTaskNum 2025-09-12 11:31:26 +08:00
hang 49a36b8214 维护数据结束提交
continuous-integration/drone/push Build is passing Details
2025-09-10 15:43:04 +08:00
hang 270941431d 修改后处理上传统计instance数量 和series数量
continuous-integration/drone/push Build is passing Details
2025-09-09 09:04:43 +08:00
hang 2e3c209de2 修改后处理上传检查bug
continuous-integration/drone/push Build is passing Details
2025-09-08 10:40:54 +08:00
hang 0be5763ce3 IRC导出支持新标准
continuous-integration/drone/push Build is passing Details
2025-09-05 15:14:36 +08:00
hang 7f1232e2ff 修改输出日志展示具体出问题的
continuous-integration/drone/push Build is passing Details
2025-09-05 11:07:58 +08:00
hang 9669032e6c 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 Details
2025-09-05 10:51:44 +08:00
hang fd5711a31d 下载影像维护处理 2025-09-05 10:51:41 +08:00
he 25c5b32fa7 Revert "修改"
continuous-integration/drone/push Build is passing Details
This reverts commit 9fa73705ba.
2025-09-03 15:02:02 +08:00
he 5f75413c9c 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 Details
2025-09-03 14:54:30 +08:00
he 9fa73705ba 修改 2025-09-03 14:54:29 +08:00
hang 0f27e246a6 升级缺陷包
continuous-integration/drone/push Build is passing Details
2025-09-01 16:39:10 +08:00
he 0d26daa3b0 邮件修改
continuous-integration/drone/push Build is passing Details
2025-08-25 14:32:52 +08:00
he 8186ec1b02 修改病灶标记图像验证 可来自于后处理
continuous-integration/drone/push Build is passing Details
2025-08-19 15:29:55 +08:00
he 0f0967f893 修改稽查
continuous-integration/drone/push Build is passing Details
2025-08-15 11:26:27 +08:00
he 56165f5037 Revert "修改维护 文档的稽查"
This reverts commit 0b707117c6.
2025-08-15 11:24:46 +08:00
he 0b707117c6 修改维护 文档的稽查
continuous-integration/drone/push Build is passing Details
2025-08-15 11:16:47 +08:00
he 5186a530f8 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 Details
2025-08-12 16:19:12 +08:00
he b3ed2dd497 修改验证 2025-08-12 16:19:11 +08:00
hang 5cfa209cc2 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 Details
2025-08-12 13:59:45 +08:00
hang 7f6b6010f2 新增文档查询接口 2025-08-12 13:59:43 +08:00
he ca5accfaa0 裁判问题
continuous-integration/drone/push Build is passing Details
2025-08-12 11:10:41 +08:00
hang 12376a154e 返回IsEncapsulated 给前端
continuous-integration/drone/push Build is passing Details
2025-08-11 16:00:03 +08:00
hang 955ecb116b 修改编译错误
continuous-integration/drone/push Build is passing Details
2025-08-11 14:59:53 +08:00
hang 79f18826c5 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 Details
2025-08-11 11:08:13 +08:00
hang d756845953 修改生成DIR文件逻辑 2025-08-11 11:08:08 +08:00
he c01d3cbd14 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 Details
2025-08-11 10:37:33 +08:00
he d20b399b9c 配置说明添加 2025-08-11 10:37:30 +08:00
hang 21f549a2e4 文件名不带 Image
continuous-integration/drone/push Build is passing Details
2025-08-08 17:04:13 +08:00
hang b1e3290090 返回DownloadEndPoint
continuous-integration/drone/push Build is passing Details
2025-08-08 16:19:30 +08:00
hang 0f859c0251 修改下载
continuous-integration/drone/push Build is passing Details
2025-08-08 16:02:33 +08:00
hang 875a3668c1 dir 增加字段
continuous-integration/drone/push Build is passing Details
2025-08-08 14:29:29 +08:00
hang eafceeb5d1 dicom dir处理返回处理后的路径
continuous-integration/drone/push Build is passing Details
2025-08-08 10:58:21 +08:00
hang 44156a2e34 有传输语法的才生成DIR 文件
continuous-integration/drone/push Build is passing Details
2025-08-08 09:50:29 +08:00
hang 2ebf61220c 后处理DIR处理
continuous-integration/drone/push Build is passing Details
2025-08-08 09:20:00 +08:00
hang d10152b720 质控下载dir 文件处理
continuous-integration/drone/push Build is passing Details
2025-08-07 18:02:49 +08:00
hang 695de70894 后端批量上传修改
continuous-integration/drone/push Build is passing Details
2025-08-07 16:00:15 +08:00
hang 5956937476 影像汇总修改2
continuous-integration/drone/push Build is passing Details
2025-08-07 15:38:25 +08:00
hang 2c3f35c26b 影像汇总修改
continuous-integration/drone/push Build is running Details
2025-08-07 15:37:21 +08:00
hang a13917bded 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 Details
2025-08-07 15:10:54 +08:00
hang 48d48b343e dir 准备修改 2025-08-07 15:10:50 +08:00
he 6987dd075f 过滤修改
continuous-integration/drone/push Build is passing Details
2025-08-07 14:02:49 +08:00
he 8bc3d9b121 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 Details
2025-08-07 11:46:32 +08:00
he 90671b2c34 添加字段 2025-08-07 11:46:26 +08:00
hang 492312f595 修改日志级别
continuous-integration/drone/push Build is passing Details
2025-08-07 09:13:55 +08:00
hang 3215d68504 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 Details
2025-08-06 17:47:45 +08:00
hang f5a229c1d5 设置日志级别 2025-08-06 17:47:42 +08:00
he a267bc13b4 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 Details
2025-08-06 16:35:43 +08:00
he de976453f5 修改字段长度 2025-08-06 16:35:43 +08:00
hang 7ee821aebd 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 Details
2025-08-06 16:05:42 +08:00
hang 4fc60d03d4 质控问题导表项目名字没显示 2025-08-06 16:05:41 +08:00
he 02e9d1b7cd 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 Details
2025-08-06 15:06:41 +08:00
he 1050e988c3 仲裁问题排序修改 2025-08-06 15:04:18 +08:00
hang 5eb152a5af 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 Details
2025-08-06 13:46:59 +08:00
hang c8f9a0dcea 邮件正则返回给前端 2025-08-06 13:46:57 +08:00
he 75abc7834b 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 Details
2025-08-06 13:40:34 +08:00
he 12c242d340 代码修改 2025-08-06 13:40:33 +08:00
hang d95158913e 修改排序2
continuous-integration/drone/push Build is passing Details
2025-08-06 10:59:20 +08:00
hang 677a7f7bd7 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 Details
2025-08-06 10:56:08 +08:00
hang fcdee39356 修改文档排序 2025-08-06 10:56:06 +08:00
he 7e54b4fdd6 稽查修改
continuous-integration/drone/push Build is passing Details
2025-08-06 10:00:50 +08:00
he f69ce8b757 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 Details
2025-08-06 09:38:30 +08:00
he 24d1277b1c 排序修改 2025-08-06 09:38:28 +08:00
hang 71bedb5b5c 修改质控问题导出
continuous-integration/drone/push Build is passing Details
2025-08-05 19:59:03 +08:00
hang 5abc573e81 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 Details
2025-08-05 18:18:51 +08:00
hang 0c9f1f0191 质控问题导表bug 预先提交 2025-08-05 18:18:50 +08:00
he d4d70f4cff 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 Details
2025-08-05 16:56:10 +08:00
he 87035563fb 导入修改 2025-08-05 16:56:09 +08:00
hang 447d0149fd 质控复核问题答案导表
continuous-integration/drone/push Build is passing Details
2025-08-05 13:58:29 +08:00
hang 7f4c1b57b2 1.1任务PM申请重阅修改
continuous-integration/drone/push Build is passing Details
2025-08-05 10:15:59 +08:00
hang 688c1d195c PM 申请重阅 SPM 同意审批,除开1.1 附加评估
continuous-integration/drone/push Build is passing Details
2025-08-05 09:49:17 +08:00
hang 0e12f2cdac 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 Details
2025-08-04 18:03:57 +08:00
hang f2f8d00e31 退回影响列表和实际退回一致 2025-08-04 18:03:54 +08:00
he 935dafb917 修改
continuous-integration/drone/push Build is running Details
2025-08-04 18:03:33 +08:00
he b92c5c9ceb 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 Details
2025-08-04 17:43:30 +08:00
he 89ba8406a1 修改稽查 2025-08-04 17:43:28 +08:00
hang e4b06786de 一致性分析任务 导致退回生成任务bug
continuous-integration/drone/push Build is passing Details
2025-08-04 17:12:17 +08:00
hang 6e586fb6d3 修改CDISC 多表格导出
continuous-integration/drone/push Build is passing Details
2025-08-04 15:08:28 +08:00
hang cfd05cff36 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 Details
2025-08-04 13:34:53 +08:00
hang 2eb19a28b3 医学审核问题导表 2025-08-04 13:34:49 +08:00
he 21f70f4d79 报错修改
continuous-integration/drone/push Build is passing Details
2025-08-04 13:29:00 +08:00
he db8d13725e 稽查修改
continuous-integration/drone/push Build is passing Details
2025-08-04 11:38:35 +08:00
he e60f9eb689 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 Details
2025-08-04 11:30:40 +08:00
he 6461c64923 稽查修改 2025-08-04 11:30:37 +08:00
hang 0f3050b28d 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 Details
2025-08-04 11:15:02 +08:00
hang 6d298e775f 中止查询过滤+CDISC导出非肿瘤标准 2025-08-04 11:15:01 +08:00
he 83f9a66f7a 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 Details
2025-08-04 09:32:44 +08:00
he ed40a896f2 修改 2025-08-04 09:32:42 +08:00
hang 1c58ba7e28 非dicom上传bug
continuous-integration/drone/push Build is passing Details
2025-08-01 18:11:48 +08:00
hang 49e372d11d 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 Details
2025-08-01 17:49:09 +08:00
hang 1a6410e881 修改下一个任务bug5 2025-08-01 17:49:08 +08:00
he cf8b9706fc 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 Details
2025-08-01 17:42:11 +08:00
he 1fc92a12e4 阅片导入 2025-08-01 17:42:09 +08:00
hang ce3c4a893f 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 Details
2025-08-01 17:20:55 +08:00
hang f3613febb8 自动下一个任务去掉优先当前subject 2025-08-01 17:20:53 +08:00
he 9a1a4e3451 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 Details
2025-08-01 16:46:27 +08:00
he 752acd8d4d 导出修改 2025-08-01 16:46:25 +08:00
hang 73a1236a5f 一致性分析多标准插入临床数据bug
continuous-integration/drone/push Build is passing Details
2025-08-01 15:46:26 +08:00
hang 11c03576ea 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 Details
2025-08-01 15:32:33 +08:00
hang 836c7f7185 修改获取下一个任务-4 2025-08-01 15:32:31 +08:00
he 6355231e8b 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 Details
2025-08-01 15:30:46 +08:00
he 1b05055e3f 修改 2025-08-01 15:30:39 +08:00
hang a11edc3053 修改获取下一个任务-3
continuous-integration/drone/push Build is passing Details
2025-08-01 14:36:52 +08:00
hang 33e84a05ef 修改获取下一个任务-2
continuous-integration/drone/push Build is passing Details
2025-08-01 13:52:37 +08:00
hang 24a082c0f0 修改获取下一个任务
continuous-integration/drone/push Build is passing Details
2025-08-01 11:04:32 +08:00
hang e9bd228e09 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 Details
2025-08-01 09:15:36 +08:00
hang b0f4b6a3d5 修改编辑映射 2025-08-01 09:15:34 +08:00
he a001f5476f 修改
continuous-integration/drone/push Build is passing Details
2025-08-01 09:09:35 +08:00
he a51ced9c4e 修改
continuous-integration/drone/push Build is passing Details
2025-07-31 17:56:04 +08:00
he 1bcf8647ef 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 Details
2025-07-31 17:49:20 +08:00
he 832930a5d9 稽查修改 2025-07-31 17:49:19 +08:00
hang d4164f13dd 稽查增加原因
continuous-integration/drone/push Build is passing Details
2025-07-31 16:22:02 +08:00
hang d2b6a1dbe9 修改dicom 检查
continuous-integration/drone/push Build is passing Details
2025-07-31 16:15:38 +08:00
hang d1bf244135 去掉多余稽查代码
continuous-integration/drone/push Build is passing Details
2025-07-31 15:53:02 +08:00
hang 394e090029 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 Details
2025-07-31 15:07:43 +08:00
hang 7fc643bae1 修改非dicom dicom 质控完修改检查信息 2025-07-31 15:07:40 +08:00
he 4f1072e545 稽查修改
continuous-integration/drone/push Build is passing Details
2025-07-31 09:51:07 +08:00
he 59d5addf72 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 Details
2025-07-30 14:43:45 +08:00
he 034a0e8bbb 修改稽查 2025-07-30 14:43:44 +08:00
hang f32a66a89b 增加对话返回复核状态
continuous-integration/drone/push Build is passing Details
2025-07-30 14:08:01 +08:00
hang 84994e0d3c 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 Details
2025-07-30 14:05:17 +08:00
hang d193834e05 质疑记录返回复核状态 2025-07-30 14:05:08 +08:00
he fa9c7c8cf8 修改
continuous-integration/drone/push Build is passing Details
2025-07-30 11:46:05 +08:00
he 5ef075e4fe 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 Details
2025-07-30 11:31:13 +08:00
he c18c0aadd0 文件路径修改 2025-07-30 11:31:11 +08:00
hang eccb127492 修改列表默认排序
continuous-integration/drone/push Build is running Details
2025-07-30 11:30:41 +08:00
hang e979649ef4 1、用户参与项目统计数字
continuous-integration/drone/push Build is passing Details
2、复核不允许申请重传
3、CDISC导表排序
2025-07-30 11:15:03 +08:00
hang 62789f4cd8 增加影像重传导表
continuous-integration/drone/push Build is passing Details
2025-07-29 17:25:38 +08:00
hang 8e2477c19d QC自动领取问题修改
continuous-integration/drone/push Build is passing Details
2025-07-29 15:56:34 +08:00
hang 6c103b577c 更新里面有添加bug
continuous-integration/drone/push Build is passing Details
2025-07-29 15:23:56 +08:00
hang 9082caa57c Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8 2025-07-29 15:22:12 +08:00
he 3b4cb52fab 修改稽查
continuous-integration/drone/push Build is passing Details
2025-07-29 15:18:46 +08:00
he 088143fb70 修改稽查
continuous-integration/drone/push Build is passing Details
2025-07-29 14:54:54 +08:00
hang 9e63e742bf 初审通过bug 修改 2025-07-29 14:34:22 +08:00
he 8431ece7f9 稽查修改
continuous-integration/drone/push Build is passing Details
2025-07-29 14:21:26 +08:00
he ef03bac3f2 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 Details
2025-07-29 14:03:44 +08:00
he f8f0b5661a 稽查修改 2025-07-29 14:03:40 +08:00
hang 704fd261fc 项目邮件配置修改2
continuous-integration/drone/push Build is passing Details
2025-07-29 13:51:37 +08:00
hang 329cc3b6bf 项目邮件配置修改
continuous-integration/drone/push Build is passing Details
2025-07-29 13:12:28 +08:00
hang 766ce3123a 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 Details
2025-07-28 17:19:10 +08:00
hang 5bebaa247a Excel 导表增加受试者状态列 2025-07-28 17:19:08 +08:00
he 71a4b241fd 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 Details
2025-07-28 17:04:59 +08:00
he 228e50c3df 稽查图片修改 2025-07-28 17:04:56 +08:00
hang fee78546c0 编译错误
continuous-integration/drone/push Build is passing Details
2025-07-28 14:24:58 +08:00
hang 06118b08c5 pacs 影像预览
continuous-integration/drone/push Build is passing Details
2025-07-28 14:22:56 +08:00
hang 47b8d5186e 质疑记录排序增加
continuous-integration/drone/push Build is passing Details
2025-07-28 13:29:26 +08:00
hang 19f700acc6 复核重传完成bug 修改
continuous-integration/drone/push Build is passing Details
2025-07-25 16:49:33 +08:00
hang 4b4347c839 subject 中止 领取下一个任务
continuous-integration/drone/push Build is passing Details
2025-07-25 16:24:57 +08:00
hang 854df31461 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 Details
2025-07-25 15:57:07 +08:00
hang 58ce173543 修改退回已阅任务无SPM 状态修改 2025-07-25 15:57:03 +08:00
he 5c668ee733 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 Details
2025-07-25 15:28:30 +08:00
he 4b0dd31fd1 代码修改 2025-07-25 15:28:30 +08:00
hang 23ec2a6275 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 Details
2025-07-25 15:13:46 +08:00
hang 043037328e 稽查审批人增加字段 2025-07-25 15:13:44 +08:00
he 0b1a4bb53e 路径修改
continuous-integration/drone/push Build is passing Details
2025-07-25 14:31:14 +08:00
he 3eb3478353 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 Details
2025-07-25 11:10:25 +08:00
he cb25fa309f 修改原因 2025-07-25 11:10:19 +08:00
hang 1f8f3242b5 取tag 做判断
continuous-integration/drone/push Build is passing Details
2025-07-25 10:38:43 +08:00
hang a52a06cf89 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 Details
2025-07-24 17:29:18 +08:00
hang 0475b9891c 后处理阅片数量-1 2025-07-24 17:29:17 +08:00
he 0a927d6087 稽查修改
continuous-integration/drone/push Build is passing Details
2025-07-24 16:29:13 +08:00
he f06bc9654c 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 Details
2025-07-24 16:18:51 +08:00
he eacdcb1eb1 稽查代码修改 2025-07-24 16:18:50 +08:00
hang 11d57fb0b6 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 Details
2025-07-24 15:52:29 +08:00
hang 0d91ceafff 质控自动任务逻辑修改 2025-07-24 15:52:27 +08:00
he c81cdf30a0 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 Details
2025-07-24 15:42:30 +08:00
he facb4cdc47 修改 2025-07-24 15:42:30 +08:00
hang 3f31c8ad14 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 Details
2025-07-24 15:33:18 +08:00
hang 76a2ef3cbd IQC项目配置返回 2025-07-24 15:33:16 +08:00
he 3c1ecf8e43 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 Details
2025-07-24 15:30:42 +08:00
he 7a9e2f95ca 临床数据修改 2025-07-24 15:30:41 +08:00
hang 582ea4c5ab 复核的时候允许直接关闭质疑,项目增加质控自动任务配置
continuous-integration/drone/push Build is passing Details
2025-07-24 15:16:26 +08:00
hang 668f93d0ac instance 返回subjectCode VisitName
continuous-integration/drone/push Build is passing Details
2025-07-24 15:03:55 +08:00
hang f2d6d62083 复核任务修改
continuous-integration/drone/push Build is passing Details
2025-07-24 14:35:51 +08:00
hang 2e8ffaecff 复核删除做的所有答案
continuous-integration/drone/push Build is passing Details
2025-07-24 14:22:05 +08:00
hang 77a250fc71 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 Details
2025-07-24 13:52:43 +08:00
hang 1ce5938e78 序列层级返回subjectCode VisitName 2025-07-24 13:52:41 +08:00
he e221af244d 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 Details
2025-07-24 13:37:50 +08:00
he e4883f116f 标记修改 2025-07-24 13:37:48 +08:00
hang 57b7e3f65c 一致性分析自定义阅片导表修改
continuous-integration/drone/push Build is passing Details
2025-07-24 11:49:44 +08:00
hang 26b17c12bb 重传影像时不允许删除检查
continuous-integration/drone/push Build is passing Details
2025-07-24 10:06:21 +08:00
hang f10b62c548 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 Details
2025-07-24 09:38:35 +08:00
hang 8eae9dde16 返回邮件配置 2025-07-24 09:38:33 +08:00
he 469e7cb49b 修改
continuous-integration/drone/push Build is passing Details
2025-07-23 16:32:04 +08:00
he 3f6e81bc3e 外层问题的稽查修改
continuous-integration/drone/push Build is passing Details
2025-07-23 16:22:10 +08:00
he 1dafe81770 Forrest的默认值改一下 设置为非dicom
continuous-integration/drone/push Build is passing Details
2025-07-23 15:57:02 +08:00
he 549691c8ac 稽查外层问题修改
continuous-integration/drone/push Build is passing Details
2025-07-23 15:31:17 +08:00
he 364ce9aefb 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 Details
2025-07-23 15:14:16 +08:00
hang 27d15599c1 复核指派bug修改
continuous-integration/drone/push Build is running Details
2025-07-23 15:13:23 +08:00
hang 356384142a 下一个任务不会跳复核任务 2025-07-23 15:13:19 +08:00
he d0f0b5046c 表格问题标记稽查修改 2025-07-23 15:10:45 +08:00
hang beb6f2fca8 修改稽查2
continuous-integration/drone/push Build is passing Details
2025-07-23 14:29:21 +08:00
hang d933df437c 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 Details
2025-07-23 13:59:31 +08:00
hang fbf7fc6a70 申请回退访视数据 稽查处理 2025-07-23 13:59:29 +08:00
he c84753f99d 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 Details
2025-07-23 13:34:38 +08:00
he c1995f1547 邮件修改 区分CRC与CRA 2025-07-23 13:34:37 +08:00
hang ffe6a0a4a9 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 Details
2025-07-23 09:28:47 +08:00
hang 2541d08fba 质控导出 2025-07-23 09:28:45 +08:00
he 76fe4ae8a8 修改
continuous-integration/drone/push Build is passing Details
2025-07-23 09:16:38 +08:00
he 85ff14f160 稽查修改
continuous-integration/drone/push Build is passing Details
2025-07-23 09:08:57 +08:00
he a8224aa018 修改
continuous-integration/drone/push Build is passing Details
2025-07-22 16:22:52 +08:00
he 18d2ea7d31 修改
continuous-integration/drone/push Build is passing Details
2025-07-22 16:18:01 +08:00
he 5ea31ee1b0 修改
continuous-integration/drone/push Build is passing Details
2025-07-22 16:13:04 +08:00
he e3e83612fc Reapply "修改稽查"
continuous-integration/drone/push Build is passing Details
This reverts commit 36750cc81c.
2025-07-22 15:57:15 +08:00
he 36750cc81c Revert "修改稽查"
continuous-integration/drone/push Build is passing Details
This reverts commit d93cfb6a4d.
2025-07-22 15:33:56 +08:00
he d93cfb6a4d 修改稽查
continuous-integration/drone/push Build is passing Details
2025-07-22 14:02:49 +08:00
he fed62ce5e3 修改绑定关系
continuous-integration/drone/push Build is passing Details
2025-07-21 16:55:38 +08:00
he c66c7eaef7 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 Details
2025-07-21 15:33:59 +08:00
he 3d671c79ea 绑定的标记不让删除 2025-07-21 15:33:58 +08:00
hang dae5ee098a 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 Details
2025-07-21 14:23:10 +08:00
hang f2836a8928 修改邮箱配置校验 2025-07-21 14:23:09 +08:00
he a86448a5c1 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 Details
2025-07-21 14:19:51 +08:00
he 0b8e6fc2e8 修改一致性分析临床数据数据 2025-07-21 14:19:50 +08:00
hang bae6f099fe 复核稽查修改016
continuous-integration/drone/push Build is passing Details
2025-07-18 17:04:30 +08:00
hang 1d74e33b8b 复核稽查修改015 2025-07-18 17:04:26 +08:00
hang caca3e77a5 复核稽查修改014 2025-07-18 17:04:21 +08:00
hang e9b79cc1f1 复核稽查修改013 2025-07-18 17:03:56 +08:00
hang 435479cd9d 复核稽查修改012 2025-07-18 17:01:26 +08:00
hang f191da2df3 维护dicom 数据大小方法
continuous-integration/drone/push Build is passing Details
2025-07-18 16:57:03 +08:00
hang 72e8106516 复核稽查修改011
continuous-integration/drone/push Build is passing Details
2025-07-18 16:24:28 +08:00
hang 85d58d3ca2 复核稽查修改010 2025-07-18 16:24:17 +08:00
hang 1c05010552 复核稽查修改009 2025-07-18 16:24:13 +08:00
hang 1aad2c6a3f 复核稽查修改008
continuous-integration/drone/push Build is passing Details
2025-07-17 16:32:51 +08:00
hang 08ff24b14a 复核稽查修改007 2025-07-17 16:32:47 +08:00
hang 530d11c769 复核稽查修改006 2025-07-17 16:32:41 +08:00
hang 24135801ac 复核稽查修改005 2025-07-17 16:32:37 +08:00
hang d225e26d95 复核稽查修改004 2025-07-17 16:32:33 +08:00
hang a0b14d5957 复核稽查修改003 2025-07-17 16:32:28 +08:00
hang f776d2e663 复核稽查修改002 2025-07-17 16:32:24 +08:00
hang 5099ad654e 复核稽查修改 2025-07-17 16:32:20 +08:00
he b68e91b71e 退回的原因
continuous-integration/drone/push Build is passing Details
2025-07-17 11:25:42 +08:00
he fa209e54b6 修改稽查
continuous-integration/drone/push Build is passing Details
2025-07-17 10:27:14 +08:00
he 316caa8482 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 Details
2025-07-17 10:20:58 +08:00
he 05bd1bd9b8 稽查修改 2025-07-17 10:20:57 +08:00
hang 3e4026e899 修改复核-退回-003
continuous-integration/drone/push Build is passing Details
2025-07-17 09:01:12 +08:00
hang cf52923060 修改复核查询接口-002 2025-07-17 09:01:09 +08:00
hang 67a5f1c32c 修改复核查询接口-001
continuous-integration/drone/push Build is passing Details
2025-07-16 16:54:45 +08:00
hang 405ab20ef5 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 Details
2025-07-16 11:48:36 +08:00
hang 47e8183d4f 返回文件大小 2025-07-16 11:48:25 +08:00
he d76f600e03 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 Details
2025-07-16 10:26:40 +08:00
he c7b10af268 代码修改 2025-07-16 10:26:39 +08:00
hang ff08efd978 指派其他质控-uat-13
continuous-integration/drone/push Build is passing Details
2025-07-16 10:11:24 +08:00
hang af1b0cbbb9 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 Details
2025-07-16 09:38:26 +08:00
hang 21dd3f455c 指派其他质控-uat-12 2025-07-16 09:38:24 +08:00
he 3eaca22700 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 Details
2025-07-16 09:23:46 +08:00
he 3f6ea7cf05 修改 2025-07-16 09:23:44 +08:00
hang 81a4b55e13 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 Details
2025-07-16 09:13:39 +08:00
hang 235c87ced0 指派其他质控-uat-11 2025-07-16 09:13:38 +08:00
he fb30808e01 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 Details
2025-07-15 17:50:31 +08:00
he 24b11f1b38 修改 2025-07-15 17:50:30 +08:00
hang a17235d9dd 修改QC复核 -二次提交-uat-10
continuous-integration/drone/push Build is passing Details
2025-07-15 17:46:13 +08:00
hang e11ab15e6c 修改QC复核 -二次提交-uat-9
continuous-integration/drone/push Build is passing Details
2025-07-15 17:27:05 +08:00
hang 132a0a8eba 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 Details
2025-07-15 17:13:04 +08:00
hang ec2a717b9b 修改QC复核 -二次提交-uat-8 2025-07-15 17:13:01 +08:00
he 8bbd93409e Revert "代码修改"
continuous-integration/drone/push Build is passing Details
This reverts commit bf3ebebb0f.
2025-07-15 17:10:05 +08:00
he 94ba76b3f3 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 Details
2025-07-15 16:49:14 +08:00
he bf3ebebb0f 代码修改 2025-07-15 16:49:13 +08:00
hang 723531d0a4 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 Details
2025-07-15 16:46:22 +08:00
hang 903344160e 修改QC复核 -二次提交-uat-7 2025-07-15 16:46:19 +08:00
he 5b0dfa8d7a 修改
continuous-integration/drone/push Build is passing Details
2025-07-15 16:26:29 +08:00
he 8272dc71d5 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 Details
2025-07-15 16:21:14 +08:00
he e01945f273 修改 2025-07-15 16:21:12 +08:00
hang 1cf961c75d 修改QC复核 -二次提交-uat-6
continuous-integration/drone/push Build is passing Details
2025-07-15 16:15:42 +08:00
hang 4214fcc870 修改QC复核 -二次提交-uat-5
continuous-integration/drone/push Build is passing Details
2025-07-15 16:07:35 +08:00
hang 56429d0b37 修改QC复核 -二次提交-uat-4
continuous-integration/drone/push Build is passing Details
2025-07-15 15:43:08 +08:00
hang e39d2e8ff8 QC复核 -二次提交-uat-3
continuous-integration/drone/push Build is passing Details
2025-07-15 15:28:58 +08:00
he 16099cc6d8 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 Details
2025-07-15 15:19:10 +08:00
he 899ef3034f 代码修改 2025-07-15 15:19:08 +08:00
hang 1671141b12 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 Details
2025-07-15 15:03:27 +08:00
hang 887b45f3d2 QC复核 -二次提交-uat-3 2025-07-15 15:03:24 +08:00
he 31aca49f1a 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 Details
2025-07-15 15:02:25 +08:00
he 9239cc490b 稽查修改 2025-07-15 15:02:23 +08:00
hang 9a5258bf83 QC复核 -二次提交-uat-2
continuous-integration/drone/push Build is passing Details
2025-07-15 14:53:00 +08:00
hang 5e31d0d853 回退申请,原因
continuous-integration/drone/push Build is passing Details
2025-07-15 11:18:15 +08:00
hang 3b24e85d5f uat-qc更新数据库
continuous-integration/drone/push Build is passing Details
2025-07-15 10:16:01 +08:00
hang 574629970c QC 审核提交--迁移uat
continuous-integration/drone/push Build is passing Details
2025-07-15 10:12:09 +08:00
he c556061a79 修改
continuous-integration/drone/push Build is passing Details
2025-07-14 15:20:51 +08:00
he e6d2f13b7e 修改
continuous-integration/drone/push Build is passing Details
2025-07-14 15:09:48 +08:00
he 24ec6b21d5 Revert "标记修改"
continuous-integration/drone/push Build is running Details
This reverts commit fd52011be9.
2025-07-14 15:08:14 +08:00
he fd52011be9 标记修改
continuous-integration/drone/push Build is passing Details
2025-07-14 15:05:13 +08:00
he ef351674b7 修改
continuous-integration/drone/push Build is passing Details
2025-07-14 14:51:25 +08:00
he fa979b57cc 修改
continuous-integration/drone/push Build is passing Details
2025-07-14 14:31:09 +08:00
he 36594c349e 标记修改
continuous-integration/drone/push Build is passing Details
2025-07-14 14:19:48 +08:00
he 053edf9e4d 修改
continuous-integration/drone/push Build is passing Details
2025-07-14 14:10:21 +08:00
he addd8fb321 修改
continuous-integration/drone/push Build is passing Details
2025-07-14 14:06:30 +08:00
he 4417767e35 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 Details
2025-07-14 13:55:10 +08:00
he 02beaa24fc 自定义问题标记修改 2025-07-14 13:55:06 +08:00
hang 48f924e64f uat 序列获取Instance 增加文件大小
continuous-integration/drone/push Build is passing Details
2025-07-14 13:25:04 +08:00
hang 85fa51150d 修改访视统计新需求
continuous-integration/drone/push Build is passing Details
2025-07-14 13:20:49 +08:00
hang c8a70fd385 修改非dicom 设置删除,检查上的数量不变更
continuous-integration/drone/push Build is passing Details
2025-07-11 16:24:31 +08:00
hang 09db5e13b8 修改预览看到阅片影像 修改后受试者随机bug修改 4
continuous-integration/drone/push Build is passing Details
2025-07-11 15:20:59 +08:00
hang 710d4f54b0 修改后受试者随机bug修改 3
continuous-integration/drone/push Build is passing Details
2025-07-11 10:08:01 +08:00
hang d66e92b971 修改后受试者随机bug修改 2
continuous-integration/drone/push Build is passing Details
2025-07-11 09:47:33 +08:00
hang 7436b4ca5d 受试者随机bug修改
continuous-integration/drone/push Build is passing Details
2025-07-11 09:20:39 +08:00
hang d43d38719e 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 Details
2025-07-10 18:21:31 +08:00
hang 416b9ea4d5 修改subject 随机阅片下载影像重阅bug 2025-07-10 18:21:30 +08:00
he 395e7b4388 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 Details
2025-07-10 17:48:58 +08:00
he 3fbccad84c 稽查修改 2025-07-10 17:48:57 +08:00
hang b2e494843d 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 Details
2025-07-10 16:18:57 +08:00
hang 4624b0f12e 修改后处理下载过滤不阅片的 2025-07-10 16:18:51 +08:00
he cb68dc8fb5 修改
continuous-integration/drone/push Build is passing Details
2025-07-10 15:57:46 +08:00
he e8b2196bc4 修改
continuous-integration/drone/push Build is passing Details
2025-07-10 15:15:39 +08:00
he b6a795b8b0 修改
continuous-integration/drone/push Build is running Details
2025-07-10 15:15:23 +08:00
he 1e96e671a9 稽查修改
continuous-integration/drone/push Build is passing Details
2025-07-10 13:36:07 +08:00
he 164b074d1b 修改删除
continuous-integration/drone/push Build is passing Details
2025-07-10 13:26:23 +08:00
he bce2ed0dfa 稽查修改
continuous-integration/drone/push Build is passing Details
2025-07-10 13:16:43 +08:00
he 88cb7b8a1a 修改
continuous-integration/drone/push Build is passing Details
2025-07-10 11:15:53 +08:00
he 50b47e0752 字段添加
continuous-integration/drone/push Build is passing Details
2025-07-10 11:10:14 +08:00
he 7189ea563c 稽查答案修改
continuous-integration/drone/push Build is passing Details
2025-07-10 10:50:35 +08:00
he 4d185f6f99 移除CustomTag表
continuous-integration/drone/push Build is passing Details
2025-07-10 10:42:51 +08:00
he e0592989b0 修改
continuous-integration/drone/push Build is passing Details
2025-07-10 09:40:54 +08:00
he 8bbe424456 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 Details
2025-07-10 09:19:57 +08:00
he dd35e37e65 代码修改 2025-07-10 09:19:56 +08:00
hang c49bd189b6 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 Details
2025-07-10 09:19:00 +08:00
hang 6880b48f73 影像上传 访视状态变更 2025-07-10 09:18:59 +08:00
he 474b9ca80e 稽查修改
continuous-integration/drone/push Build is passing Details
2025-07-09 17:47:12 +08:00
he 6ef41cae1d 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 Details
2025-07-09 16:24:48 +08:00
he 8831834be6 修改操作时间 2025-07-09 16:24:47 +08:00
hang d567b9d252 增加dicom study
continuous-integration/drone/push Build is passing Details
2025-07-09 11:47:09 +08:00
hang be4826a6ba 修改dicom 检查
continuous-integration/drone/push Build is passing Details
2025-07-09 11:33:24 +08:00
hang 5ac9a37de2 修改质控编辑是否阅片 是否删除 稽查合并
continuous-integration/drone/push Build is passing Details
2025-07-09 11:29:03 +08:00
hang 546d8e2cc3 修改非dicom 编辑检查 是否阅片 是否删除稽查
continuous-integration/drone/push Build is passing Details
2025-07-09 11:04:10 +08:00
hang 8d81115525 oss 维护大小代码变更
continuous-integration/drone/push Build is passing Details
2025-07-08 10:20:08 +08:00
hang 4c60a32c7e 项目检查技术修改
continuous-integration/drone/push Build is passing Details
2025-07-07 16:09:10 +08:00
hang e1755eb11a 手动设置包版本
continuous-integration/drone/push Build is passing Details
2025-07-07 15:52:59 +08:00
hang 9e1b61fbf5 修改hangfirecore 版本
continuous-integration/drone/push Build is passing Details
2025-07-07 15:30:22 +08:00
hang f3915dc5b7 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 Details
2025-07-07 14:39:55 +08:00
hang 4a6cac2327 修改非diocm 文件稽查 2025-07-07 14:39:54 +08:00
he 5cc8a246da 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 Details
2025-07-07 14:31:47 +08:00
he f8f66b1110 定时任务修改 2025-07-07 14:31:45 +08:00
hang 40f8887ef9 修改关键图导出生效的
continuous-integration/drone/push Build is passing Details
2025-07-07 11:07:28 +08:00
he cf59838779 修改登录
continuous-integration/drone/push Build is passing Details
2025-07-04 17:25:18 +08:00
he e628ed91e7 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 Details
2025-07-04 17:13:41 +08:00
he c8fef30b15 修改 2025-07-04 17:13:40 +08:00
hang c860b5c365 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 Details
2025-07-04 16:57:47 +08:00
hang 49b2ba2484 subject 中止状态联动 2025-07-04 16:57:45 +08:00
he d35bdb6899 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 Details
2025-07-04 16:47:03 +08:00
he b7fe79208e 登录修改 2025-07-04 16:47:03 +08:00
hang e1e7abb65a 编译错误
continuous-integration/drone/push Build is passing Details
2025-07-04 16:16:28 +08:00
hang c71f7e38cc 修改非dicom 返回路径格式
continuous-integration/drone/push Build is running Details
2025-07-04 16:14:22 +08:00
hang 981585498d 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 Details
2025-07-04 16:08:57 +08:00
hang 7c3b71de93 非dicom 标记图片增加 2025-07-04 16:08:54 +08:00
he 34f6292fa7 稽查修改
continuous-integration/drone/push Build is passing Details
2025-07-04 15:11:32 +08:00
he 6c82cbe11d 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 Details
2025-07-04 14:47:33 +08:00
he 587c12f331 代码修改 2025-07-04 14:47:32 +08:00
hang d4dc00804b 修改入组报告
continuous-integration/drone/push Build is passing Details
2025-07-04 13:58:36 +08:00
hang df54375e6d 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 Details
2025-07-04 13:52:22 +08:00
hang e5597d25b9 增加有阅片期 无全局触发PD 2025-07-04 13:52:20 +08:00
he b6149c4d32 修改
continuous-integration/drone/push Build is passing Details
2025-07-04 13:35:54 +08:00
he 373a9a2bb1 修改稽查
continuous-integration/drone/push Build is passing Details
2025-07-04 13:25:11 +08:00
he 256a5a6ea6 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 Details
2025-07-04 13:21:00 +08:00
he 8baf6ddf53 修改稽查 2025-07-04 13:20:58 +08:00
hang 066f66b969 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 Details
2025-07-04 11:29:00 +08:00
hang 57ab098e12 邮箱正则配置到配置文件 2025-07-04 11:28:56 +08:00
he 5aae3b7fc4 修改
continuous-integration/drone/push Build is passing Details
2025-07-04 10:52:30 +08:00
he e0fef9f4ca 稽查修改
continuous-integration/drone/push Build is passing Details
2025-07-04 10:45:55 +08:00
he e898f17873 PCWG 全局
continuous-integration/drone/push Build is passing Details
2025-07-03 16:17:32 +08:00
he 8456108db8 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 Details
2025-07-03 16:02:16 +08:00
he 3603e7c3ab 稽查修改 2025-07-03 16:02:13 +08:00
hang 43339ba6e0 完全随机跟下载关联 2025-07-03 15:16:13 +08:00
hang 8715032780 修改一致性核查质疑
continuous-integration/drone/push Build is passing Details
2025-07-03 11:12:49 +08:00
hang efb9532fbc 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 Details
2025-07-03 10:13:50 +08:00
hang 7264c4a417 修改非dicom 删除稽查 2025-07-03 10:13:48 +08:00
he 50d3974cdf 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 Details
2025-07-02 17:55:31 +08:00
he 879a85a26f 修改中心查询不到的问题 2025-07-02 17:55:30 +08:00
hang 8f5d391c0d 修改pcwg 判断
continuous-integration/drone/push Build is passing Details
2025-07-02 16:43:23 +08:00
hang f8ba3019e6 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 Details
2025-07-02 16:32:00 +08:00
hang 61b67b935a 访视执行状态修改 2025-07-02 16:31:57 +08:00
he 7cf1798dd7 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 Details
2025-07-02 15:55:08 +08:00
he 33c5efc8d7 修改 查询关联数据 2025-07-02 15:55:08 +08:00
hang f8e501fb0d 修改入组Pd报告
continuous-integration/drone/push Build is passing Details
2025-07-02 15:16:10 +08:00
hang bdb48f93bc 修改pacs 稽查配置
continuous-integration/drone/push Build is passing Details
2025-07-02 14:24:30 +08:00
hang 32cd6e0c74 修改项目接入配置--无更新时不产生稽查
continuous-integration/drone/push Build is passing Details
2025-07-02 13:44:46 +08:00
he 397a36214c 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 Details
2025-07-02 10:30:44 +08:00
he 5d49a0c9b9 裁判的默认值 2025-07-02 10:30:43 +08:00
hang 485e1359a9 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 Details
2025-07-02 10:20:26 +08:00
hang 0333002ffa 修改关键图裁判选择标记 2025-07-02 10:20:22 +08:00
he 14b1a62a1f 修改裁判的默认值
continuous-integration/drone/push Build is passing Details
2025-07-02 10:01:49 +08:00
he f52e35379f 稽查修改
continuous-integration/drone/push Build is passing Details
2025-07-01 17:56:01 +08:00
he e32b7c2ca4 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 Details
2025-07-01 17:41:52 +08:00
he e902fe88d0 稽查修改 2025-07-01 17:41:51 +08:00
hang 6d9cfe5e45 修改稽查,忽略UserRole 角色表的稽查
continuous-integration/drone/push Build is passing Details
2025-07-01 16:21:38 +08:00
hang bc5b93b924 QC 问题确认稽查
continuous-integration/drone/push Build is passing Details
2025-07-01 16:04:21 +08:00
hang e94f971495 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 Details
2025-06-30 17:19:56 +08:00
hang 12a2683bc3 修改阅片人查询列表 2025-06-30 17:19:54 +08:00
he e3e1d6bbb7 修改
continuous-integration/drone/push Build is passing Details
2025-06-30 17:08:18 +08:00
he 46c824a84a 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 Details
2025-06-30 16:55:15 +08:00
he a8ad59eb91 修改返回 2025-06-30 16:55:14 +08:00
hang bdaa997416 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 Details
2025-06-30 16:15:47 +08:00
hang b770f8765d 修改查询 2025-06-30 16:15:41 +08:00
he 8d8865cef7 阅片人入项同意记录修改
continuous-integration/drone/push Build is passing Details
2025-06-30 14:28:20 +08:00
he 1e72d83284 非Dicom阅片标记排序
continuous-integration/drone/push Build is passing Details
2025-06-30 13:26:19 +08:00
he 2260a5621e 修改bug
continuous-integration/drone/push Build is passing Details
2025-06-30 10:38:37 +08:00
he b7efd0c97f 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 Details
2025-06-26 13:59:30 +08:00
he f13c2bf7cc 修改确认信息 2025-06-26 13:59:28 +08:00
hang 49a7d5fc29 修改统计数字-bug
continuous-integration/drone/push Build is passing Details
2025-06-26 09:47:16 +08:00
hang efb9201598 修改失访配置统计数字
continuous-integration/drone/push Build is passing Details
2025-06-26 09:26:30 +08:00
hang e17e3a4b53 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 Details
2025-06-25 16:34:46 +08:00
hang aa2bd91426 修改导表控制 2025-06-25 16:34:44 +08:00
he fb66e2c738 项目文档发布稽查 区分接口
continuous-integration/drone/push Build is passing Details
2025-06-25 14:18:23 +08:00
he c44c37b76b 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 Details
2025-06-25 14:00:18 +08:00
he 6b068e3919 发布项目文档的时候 记录稽查 2025-06-25 14:00:17 +08:00
hang 92c0612a90 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 Details
2025-06-25 10:45:46 +08:00
hang bb9d7da55f 增加失访可读配置-uat 2025-06-25 10:45:44 +08:00
he c0f7a921d6 添加返回小数点位数
continuous-integration/drone/push Build is passing Details
2025-06-25 10:41:01 +08:00
he 0a6f2e2011 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 Details
2025-06-24 16:38:33 +08:00
he b30d11b5dd 稽查的单位要加空格 2025-06-24 16:38:32 +08:00
hang df1e87897f 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 Details
2025-06-24 16:17:26 +08:00
hang e86a5e005c 修改重阅审批 同意限制 2025-06-24 16:17:24 +08:00
he 3859dc0d79 单位修改2
continuous-integration/drone/push Build is passing Details
2025-06-24 14:54:09 +08:00
he 61d1641716 修改单位1
continuous-integration/drone/push Build is passing Details
2025-06-24 14:41:19 +08:00
he 06af37f74c 修改单位
continuous-integration/drone/push Build is running Details
2025-06-24 14:40:42 +08:00
he d9b46437a4 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 Details
2025-06-24 14:03:29 +08:00
he 4ee760ed53 修改OCT计算触发逻辑 2025-06-24 14:03:28 +08:00
hang b030959b64 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 Details
2025-06-24 13:43:29 +08:00
hang 814f27244a 查询增加 subject退出状态 2025-06-24 13:43:26 +08:00
he e53531636d 阅片标准默认值修改
continuous-integration/drone/push Build is running Details
2025-06-24 13:41:53 +08:00
he 6d100555d8 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 Details
2025-06-24 11:27:12 +08:00
he fea55de838 添加默认值 2025-06-24 11:27:10 +08:00
hang d9326a1e8e 修改入组和PD逻辑
continuous-integration/drone/push Build is passing Details
2025-06-24 10:02:11 +08:00
he b44c92f291 保存测量值
continuous-integration/drone/push Build is passing Details
2025-06-23 15:35:42 +08:00
he a51130b4ea Bug修改
continuous-integration/drone/push Build is passing Details
2025-06-23 14:51:26 +08:00
he 424441a3fc 稽查保存Ivus和Oct
continuous-integration/drone/push Build is passing Details
2025-06-23 14:36:46 +08:00
he dce62d076b 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 Details
2025-06-23 14:13:53 +08:00
he 04422cd795 标记的排序修改 2025-06-23 14:13:51 +08:00
hang 1548498d3d 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 Details
2025-06-23 10:58:39 +08:00
hang 40fd8b0d5a 修改发布配置文件 2025-06-23 10:58:37 +08:00
he b143ffbcfc 角色禁用不发邮件
continuous-integration/drone/push Build is passing Details
2025-06-20 16:57:59 +08:00
he 1d8be8c04b 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 Details
2025-06-20 16:46:25 +08:00
he 139e1f8186 退出项目不发邮件 2025-06-20 16:46:24 +08:00
hang 81cb43d3a3 修改PD 逻辑
continuous-integration/drone/push Build is passing Details
2025-06-20 16:21:28 +08:00
hang c2db7a2c61 修改项目邮件配置
continuous-integration/drone/push Build is passing Details
2025-06-20 14:46:02 +08:00
hang 8cd19b929c 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 Details
2025-06-20 14:25:43 +08:00
hang c62e7b13a9 修改搜索查询 2025-06-20 14:25:38 +08:00
he fc81738176 修改文档发布发邮件
continuous-integration/drone/push Build is passing Details
2025-06-20 14:10:33 +08:00
he b1e1840c87 修改阅片期计划的排序
continuous-integration/drone/push Build is passing Details
2025-06-20 14:03:37 +08:00
he b31d7ee762 阅片期计划可以选择基线
continuous-integration/drone/push Build is passing Details
2025-06-20 13:55:34 +08:00
he fb0c3879cf 邮件发送
continuous-integration/drone/push Build is passing Details
2025-06-20 11:53:25 +08:00
he 5ffe788a3b 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 Details
2025-06-20 09:31:57 +08:00
he 056573874a 修改受试者内随机 2025-06-20 09:31:55 +08:00
hang c959a47fa6 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 Details
2025-06-19 17:35:27 +08:00
hang 41fe678708 CDISC导表库bug 2025-06-19 17:35:24 +08:00
he e7bbf09a50 修改稽查的单位翻译
continuous-integration/drone/push Build is passing Details
2025-06-19 16:33:21 +08:00
he 3bd16d7fce 邮件修改
continuous-integration/drone/push Build is passing Details
2025-06-19 16:18:01 +08:00
he db1d1b0f14 修改
continuous-integration/drone/push Build is passing Details
2025-06-19 15:08:24 +08:00
he ef980fdc68 邮件修改
continuous-integration/drone/push Build is passing Details
2025-06-19 14:31:41 +08:00
he 4de186a36b 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 Details
2025-06-19 14:16:54 +08:00
he 0dd73991f0 邮件修改 2025-06-19 14:16:52 +08:00
hang 27e8e0e79c 修改子项排序
continuous-integration/drone/push Build is passing Details
2025-06-19 13:32:34 +08:00
hang fa53d6e88e 修改标准查询条件
continuous-integration/drone/push Build is passing Details
2025-06-19 11:37:54 +08:00
hang f3fc3fa4bf 修改邮件配置
continuous-integration/drone/push Build is passing Details
2025-06-19 11:26:17 +08:00
hang 476f692355 禁用人员系统查看文档
continuous-integration/drone/push Build is passing Details
2025-06-19 10:32:11 +08:00
hang 41b2a638fe 完全随机触发系统盲态名称
continuous-integration/drone/push Build is passing Details
2025-06-19 10:21:33 +08:00
hang c3631eee51 修改有序阅片生成任务bug
continuous-integration/drone/push Build is passing Details
2025-06-18 18:06:16 +08:00
hang 3ed74a578e 修改邮件配置为适配多标准
continuous-integration/drone/push Build is passing Details
2025-06-18 17:14:13 +08:00
hang 918728a42e 修改日志保留天数
continuous-integration/drone/push Build is passing Details
2025-06-18 13:57:50 +08:00
hang a8c0bef99e 关键图像-加上条件,已签名的才导出
continuous-integration/drone/push Build is passing Details
2025-06-18 13:05:53 +08:00
hang b3468a6d1b 修改影像下载bug
continuous-integration/drone/push Build is passing Details
2025-06-18 10:40:14 +08:00
hang dba8d3c964 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 Details
2025-06-18 10:33:29 +08:00
hang 8f5b024d3b 修改导表bug 2025-06-18 10:33:28 +08:00
he ea836d9349 修改阅片期计划生成裁判的逻辑
continuous-integration/drone/push Build is passing Details
2025-06-17 16:45:09 +08:00
he c32878911d 生成阅片期计划的时候 产生裁判 2025-06-17 16:45:07 +08:00
hang 0c4bd680dd 增加影像统计导出
continuous-integration/drone/push Build is passing Details
2025-06-17 16:30:13 +08:00
hang 90cd6ad0eb 真实随机阅片导表-1
continuous-integration/drone/push Build is passing Details
2025-06-17 09:59:22 +08:00
hang 013561541c 随机阅片导表
continuous-integration/drone/push Build is running Details
2025-06-17 09:58:53 +08:00
he f1f584c337 修改阅片期选择访视下拉框的数据
continuous-integration/drone/push Build is passing Details
2025-06-16 16:46:05 +08:00
he c443969f18 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 Details
2025-06-16 16:05:33 +08:00
hang 01621511f1 随机阅片排序-5
continuous-integration/drone/push Build is running Details
2025-06-16 16:03:25 +08:00
he 0740b38b10 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8 2025-06-16 15:59:03 +08:00
he ebd70e2202 生成了裁判任务 阅片期不让删除和修改 2025-06-16 15:59:00 +08:00
hang 80c026d5b2 修改CDISC 导出bug
continuous-integration/drone/push Build is passing Details
2025-06-16 15:58:33 +08:00
hang 8e2fbf06c5 随机阅片-NextTask-5
continuous-integration/drone/push Build is passing Details
2025-06-16 15:18:49 +08:00
hang daee20e309 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 Details
2025-06-16 15:00:48 +08:00
hang 3ba7481df8 末次访视的展示+ 展示基线选择阅片期 2025-06-16 15:00:37 +08:00
he 1e299e3f9e 添加阅片期 产生裁判
continuous-integration/drone/push Build is running Details
2025-06-16 14:59:23 +08:00
he 05cc46a6d6 修改标记信息
continuous-integration/drone/push Build is passing Details
2025-06-13 16:01:23 +08:00
he f1b943b6b0 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 Details
2025-06-13 14:40:47 +08:00
he 9f00c1c49b 修改阅片标记信息 2025-06-13 14:40:47 +08:00
hang b1fd623065 随机阅片NextTask-4
continuous-integration/drone/push Build is passing Details
2025-06-13 14:33:15 +08:00
hang 7683866718 随机阅片序号3
continuous-integration/drone/push Build is passing Details
2025-06-13 11:49:14 +08:00
hang d58395c25e 随机阅片序号2
continuous-integration/drone/push Build is passing Details
2025-06-13 11:38:09 +08:00
hang 15dd21451e 随机阅片随机序号
continuous-integration/drone/push Build is passing Details
2025-06-13 10:46:29 +08:00
hang 483c7c68e8 修改重置阅片稽查3
continuous-integration/drone/push Build is passing Details
2025-06-13 09:53:59 +08:00
hang 738ad29c0b 修改阅片重置稽查
continuous-integration/drone/push Build is passing Details
2025-06-12 17:55:02 +08:00
hang f87b57ecc5 修改重置阅片稽查
continuous-integration/drone/push Build is passing Details
2025-06-12 17:40:50 +08:00
hang fccd704659 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 Details
2025-06-12 16:36:37 +08:00
hang e5b41735ec 确认浏览临床数据 2025-06-12 16:36:29 +08:00
he 07b496eb67 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 Details
2025-06-11 15:26:20 +08:00
he 762e46480c 删除标记 2025-06-11 15:26:18 +08:00
hang a7ad22ed28 修改关键图下载
continuous-integration/drone/push Build is passing Details
2025-06-11 14:35:56 +08:00
hang 8610a627ea 修改导出影响接口
continuous-integration/drone/push Build is passing Details
2025-06-11 14:03:50 +08:00
hang 302658d467 修改影响导出列表
continuous-integration/drone/push Build is passing Details
2025-06-11 13:46:13 +08:00
hang 97c882b0b2 肿瘤学稽查修改
continuous-integration/drone/push Build is passing Details
2025-06-11 09:33:24 +08:00
hang d711bb4b7f 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 Details
2025-06-11 09:27:24 +08:00
hang 1a4ca6e36b 增加进入阅片中稽查 2025-06-11 09:27:18 +08:00
he aaac85b7b2 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 Details
2025-06-10 17:16:59 +08:00
he cb3e4bc671 添加数据 2025-06-10 17:16:58 +08:00
hang 9f187e4b36 稽查 申请PM 重阅,有SPM 判断
continuous-integration/drone/push Build is passing Details
2025-06-10 15:11:41 +08:00
hang 663ec11c8d 稽查修改,区分标识
continuous-integration/drone/push Build is passing Details
2025-06-10 13:44:27 +08:00
he 122447a621 修改
continuous-integration/drone/push Build is passing Details
2025-06-10 10:31:09 +08:00
he 31bd3c646b 修改
continuous-integration/drone/push Build is passing Details
2025-06-10 10:11:16 +08:00
he f53fc409cb 修改
continuous-integration/drone/push Build is passing Details
2025-06-10 10:06:11 +08:00
he 7f4357de68 修改
continuous-integration/drone/push Build is passing Details
2025-06-10 09:37:26 +08:00
he 23fa689498 修改
continuous-integration/drone/push Build is passing Details
2025-06-10 09:31:55 +08:00
he e564debbab 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 Details
2025-06-10 09:13:49 +08:00
he 04aa2c79f6 修改 2025-06-10 09:13:48 +08:00
hang 68d66523e8 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 Details
2025-06-09 17:38:44 +08:00
hang 549f394d43 增加稽查标识 2025-06-09 17:38:41 +08:00
he 5a83bf9221 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 Details
2025-06-09 17:01:32 +08:00
he 65bffa26b7 修改定时发送 2025-06-09 17:01:30 +08:00
hang 39a6f6a9dc 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 Details
2025-06-09 15:26:22 +08:00
hang fc02428435 导表修改 2025-06-09 15:26:20 +08:00
he 4262189508 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 Details
2025-06-09 15:21:34 +08:00
he 6dd6a5f696 修改 2025-06-09 15:21:33 +08:00
hang e03f2e35b5 修改到处临床数据bug
continuous-integration/drone/push Build is running Details
2025-06-09 15:20:02 +08:00
hang ea4a3db145 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 Details
2025-06-09 14:57:02 +08:00
hang f4ac12d4f8 修改导表+界面展示 2025-06-09 14:57:01 +08:00
he a2afe4f6e4 修改
continuous-integration/drone/push Build is passing Details
2025-06-09 14:44:17 +08:00
he ef31afa1d8 修改
continuous-integration/drone/push Build is passing Details
2025-06-09 14:14:41 +08:00
he d9fda60b99 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 Details
2025-06-09 13:39:48 +08:00
he 6508698bda 添加字段 2025-06-09 13:39:47 +08:00
hang 734675a1a5 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 Details
2025-06-09 10:31:06 +08:00
hang d2697d5133 检查部位、检查技术、检查名称在确认提交时,增加校验 2025-06-09 10:31:02 +08:00
he 1c7f4eac90 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 Details
2025-06-09 10:19:03 +08:00
he 6dcaa953d4 添加历史记录 2025-06-09 10:19:00 +08:00
hang 1f67d24abc 修改部位使用
continuous-integration/drone/push Build is passing Details
2025-06-06 14:24:25 +08:00
hang c7a310c1ad 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 Details
2025-06-06 11:12:51 +08:00
hang 578aaa467c 邮件修改+影像导出 2025-06-06 11:12:46 +08:00
he 82a7c4de29 报错修改
continuous-integration/drone/push Build is passing Details
2025-06-05 16:19:59 +08:00
he fe4df21a68 稽查添加
continuous-integration/drone/push Build is passing Details
2025-06-05 15:19:39 +08:00
he 9cb6fb2a92 添加验证
continuous-integration/drone/push Build is passing Details
2025-06-05 14:52:07 +08:00
he 37cfe07ea6 添加字段
continuous-integration/drone/push Build is passing Details
2025-06-05 09:20:47 +08:00
he 52ffdac948 修改
continuous-integration/drone/push Build is passing Details
2025-06-04 17:09:23 +08:00
he 83a15a0b47 修改
continuous-integration/drone/push Build is passing Details
2025-06-04 16:14:24 +08:00
he 1952a108a9 修改
continuous-integration/drone/push Build is passing Details
2025-06-04 16:00:32 +08:00
he ccff36507f 修改
continuous-integration/drone/push Build is passing Details
2025-06-04 15:51:27 +08:00
he 285fd0e1bb 修改映射
continuous-integration/drone/push Build is passing Details
2025-06-04 15:17:58 +08:00
he 918aafa7e5 测量值可以为空
continuous-integration/drone/push Build is passing Details
2025-06-04 14:24:26 +08:00
he 60accb2f87 修改
continuous-integration/drone/push Build is passing Details
2025-06-04 14:21:56 +08:00
he 018c9afee0 添加表
continuous-integration/drone/push Build is passing Details
2025-06-04 14:13:38 +08:00
he 1b9351b23f 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 Details
2025-06-04 13:36:31 +08:00
he 86ea3373fc 修改 2025-06-04 13:36:30 +08:00
hang dd3b43da7b 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 Details
2025-06-04 13:15:22 +08:00
hang 3151e42e78 访视裁判,裁判选择标记bug 2025-06-04 13:15:21 +08:00
he 5d8f94ef65 修改
continuous-integration/drone/push Build is passing Details
2025-06-04 10:51:32 +08:00
he 26acc94172 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 Details
2025-06-04 10:50:28 +08:00
he 5c663ec3e9 添加获取模块类型列表 2025-06-04 10:50:28 +08:00
hang 5c0917f14e 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 Details
2025-06-04 10:20:52 +08:00
hang 74230da400 修改CDISC 多表导出 2025-06-04 10:20:47 +08:00
he df104ec527 验证修改
continuous-integration/drone/push Build is passing Details
2025-06-04 09:42:00 +08:00
he 5cdef2051a 修改
continuous-integration/drone/push Build is passing Details
2025-06-03 17:21:07 +08:00
he 470d05131e 修改
continuous-integration/drone/push Build is passing Details
2025-06-03 16:57:04 +08:00
he 5e046b847d 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 Details
2025-06-03 16:12:11 +08:00
he 8b6fcf9ae1 添加字段 2025-06-03 16:12:09 +08:00
hang 4dfa1e9812 表格问题竖列留底
continuous-integration/drone/push Build is passing Details
2025-06-03 16:02:45 +08:00
he a05cb71e0d 修改
continuous-integration/drone/push Build is passing Details
2025-06-03 13:21:56 +08:00
he 137b18446c 修改
continuous-integration/drone/push Build is passing Details
2025-06-03 12:46:51 +08:00
he e44478dafe 修改
continuous-integration/drone/push Build is passing Details
2025-06-03 11:45:57 +08:00
he 0a5a36adb3 添加表
continuous-integration/drone/push Build is passing Details
2025-06-03 10:43:31 +08:00
he 91e4553795 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 Details
2025-05-30 09:03:29 +08:00
he f504cfee9e 修改 2025-05-30 09:03:26 +08:00
hang 2e7e3acf68 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 Details
2025-05-29 17:56:20 +08:00
hang c00b98daf8 心动超声后端处理下载,上传,预备 2025-05-29 17:56:19 +08:00
he 235f420e97 添加字段
continuous-integration/drone/push Build is passing Details
2025-05-29 11:37:35 +08:00
he da15b352a1 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 Details
2025-05-29 11:30:28 +08:00
he 9857b1ae92 添加发送邮件功能 2025-05-29 11:30:24 +08:00
hang 9e83f8df36 返回EnrollId
continuous-integration/drone/push Build is passing Details
2025-05-28 11:35:05 +08:00
he ae431df9b5 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 Details
2025-05-27 13:30:14 +08:00
he e5592c5bfa 修改 2025-05-27 13:30:11 +08:00
hang 1b2bca9f1e 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 Details
2025-05-27 13:15:41 +08:00
hang 4235e6025a 下载项目影像修改 2025-05-27 13:15:38 +08:00
he 209ce439c2 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 Details
2025-05-27 10:27:36 +08:00
he eabf8f4532 添加字段 2025-05-27 10:27:33 +08:00
hang 07ddb7b234 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 Details
2025-05-26 16:37:44 +08:00
hang 1f157bd1a2 项目下载影像 2025-05-26 16:37:41 +08:00
he 0c28f85f49 修改按照标记时间排序
continuous-integration/drone/push Build is passing Details
2025-05-26 14:11:54 +08:00
hang 44536b803f 裁判阅片明细表bug
continuous-integration/drone/push Build is passing Details
2025-05-23 19:13:23 +08:00
hang 750c31a159 修改导出bug
continuous-integration/drone/push Build is passing Details
2025-05-23 19:00:33 +08:00
hang 8325ccad72 返回系统简称配置
continuous-integration/drone/push Build is passing Details
2025-05-22 17:40:30 +08:00
hang c27c4ce617 生产删除影像
continuous-integration/drone/push Build is passing Details
2025-05-22 17:16:35 +08:00
hang b9ecabf915 稽查退回修改
continuous-integration/drone/push Build is passing Details
2025-05-22 16:36:12 +08:00
hang 4f13a98eff 修改退回
continuous-integration/drone/push Build is passing Details
2025-05-22 15:45:26 +08:00
hang 2a4e4e66fa 阅片跟踪页面,返回该任务退回原因字
continuous-integration/drone/push Build is passing Details
2025-05-22 15:23:59 +08:00
hang b72cc5cbc0 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 Details
2025-05-22 15:19:30 +08:00
hang 04f91560b8 pm设置回退原因 2025-05-22 15:19:27 +08:00
he 87af2edf17 修改领取
continuous-integration/drone/push Build is passing Details
2025-05-22 13:41:38 +08:00
he 856977612d 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 Details
2025-05-22 11:07:00 +08:00
he d1ac17cee1 修改退回的时候不让领取 2025-05-22 11:06:59 +08:00
hang 9748e70cdf 申请退回领取限制
continuous-integration/drone/push Build is passing Details
2025-05-22 11:02:05 +08:00
hang 5ba0a9bbd0 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 Details
2025-05-21 15:15:23 +08:00
hang d8ea1e8f94 修改IR 申请,PM 同意发送邮件 2025-05-21 15:15:21 +08:00
he 806d663cfb 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 Details
2025-05-21 14:05:17 +08:00
he 7ab1728bc7 修改关键序列排序 2025-05-21 14:05:16 +08:00
hang 32e64eaeff MR MRI 统一,认为是一致的
continuous-integration/drone/push Build is passing Details
2025-05-20 15:24:20 +08:00
he 7b6efd52bb 修改国际化
continuous-integration/drone/push Build is passing Details
2025-05-20 14:30:19 +08:00
he 7467f2ae11 修改
continuous-integration/drone/push Build is passing Details
2025-05-20 10:28:42 +08:00
he c498ffb21b 修改
continuous-integration/drone/push Build is passing Details
2025-05-19 17:15:15 +08:00
he 1dadf7b8b6 修改
continuous-integration/drone/push Build is passing Details
2025-05-19 16:42:33 +08:00
he 793cf1b570 修改
continuous-integration/drone/push Build is passing Details
2025-05-19 16:22:43 +08:00
he 5a8f564b74 修改
continuous-integration/drone/push Build is passing Details
2025-05-19 15:58:27 +08:00
he e24c9e6ac2 代码修改
continuous-integration/drone/push Build is passing Details
2025-05-19 13:54:29 +08:00
he 814f6fd83c 修改发送邮件逻辑
continuous-integration/drone/push Build is passing Details
2025-05-19 13:47:17 +08:00
hang d34be9b07d 修改获取授权
continuous-integration/drone/push Build is passing Details
2025-05-09 09:28:53 +08:00
hang e205ea0018 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 Details
2025-05-09 09:09:11 +08:00
hang ba9d3a30b9 增加老的获取token的接口 2025-05-09 09:09:10 +08:00
he 10cf908775 修改
continuous-integration/drone/push Build is passing Details
2025-05-08 14:49:57 +08:00
he ee9ad472f0 修改
continuous-integration/drone/push Build is passing Details
2025-05-08 13:57:16 +08:00
he 1cdfc5f2b5 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 Details
2025-05-08 13:41:47 +08:00
he 9e9f07e4fd 修改 2025-05-08 13:41:46 +08:00
hang a0294e6bd6 修改触发逻辑
continuous-integration/drone/push Build is passing Details
2025-05-08 13:16:43 +08:00
hang 55fdf431e0 修改触发邮件逻辑
continuous-integration/drone/push Build is passing Details
2025-05-08 13:12:39 +08:00
hang 9f1110f91a 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 Details
2025-05-08 11:44:42 +08:00
hang d76b24bc25 驳回修改 2025-05-08 11:44:35 +08:00
he 0787875b3b 修改
continuous-integration/drone/push Build is passing Details
2025-05-08 09:50:03 +08:00
he b33aca3230 合并
continuous-integration/drone/push Build is passing Details
2025-05-07 15:47:09 +08:00
he 0b291e8b21 修改邮件 2025-05-07 15:46:32 +08:00
hang 0cf7e5fddd 增加备注
continuous-integration/drone/push Build is passing Details
2025-05-07 15:25:56 +08:00
hang 95f708da58 修改邮件配置
continuous-integration/drone/push Build is passing Details
2025-05-07 14:53:49 +08:00
hang ce47776f19 统一修改邮件配置
continuous-integration/drone/push Build is passing Details
2025-05-07 14:47:22 +08:00
hang 7fff48b07a 修改邮件配置
continuous-integration/drone/push Build is passing Details
2025-05-07 14:17:16 +08:00
hang 4688cb388e 修改触发
continuous-integration/drone/push Build is passing Details
2025-05-07 13:51:32 +08:00
he 21e1a7ab01 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 failing Details
2025-05-07 13:39:52 +08:00
he 5952af85f1 修改 2025-05-07 13:39:51 +08:00
hang 5e193db33b 修改中心调研邮件
continuous-integration/drone/push Build is running Details
2025-05-07 13:38:52 +08:00
he 30bcfcc675 修改
continuous-integration/drone/push Build is passing Details
2025-05-07 13:34:49 +08:00
he 514764ee6e 邮件修改
continuous-integration/drone/push Build is passing Details
2025-05-07 13:16:35 +08:00
he 685269eebf 修改
continuous-integration/drone/push Build is passing Details
2025-05-07 10:25:56 +08:00
he 276ad83080 修改
continuous-integration/drone/push Build is passing Details
2025-05-07 10:21:30 +08:00
he 7a318eae45 代码修改
continuous-integration/drone/push Build is passing Details
2025-05-06 17:08:04 +08:00
hang 0769f8fe05 增加额外参数
continuous-integration/drone/push Build is passing Details
2025-05-06 16:35:05 +08:00
hang 03ac25835e 修改增加TrialId
continuous-integration/drone/push Build is running Details
2025-05-06 16:33:41 +08:00
he 29c3888108 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 Details
2025-05-06 15:34:22 +08:00
he 91951be107 邮件发送修改 2025-05-06 15:34:20 +08:00
hang 935e46a8f1 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 Details
2025-05-06 14:19:08 +08:00
hang 1345808019 修改过滤项目参与人员 2025-05-06 14:19:07 +08:00
he 400d0d3336 修改
continuous-integration/drone/push Build is passing Details
2025-05-06 14:12:57 +08:00
he ca0fd77176 邮件修改
continuous-integration/drone/push Build is passing Details
2025-05-06 13:57:31 +08:00
he f7cf6d9669 邮件修改
continuous-integration/drone/push Build is passing Details
2025-05-06 13:39:49 +08:00
he 7f19944005 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 Details
2025-05-06 10:49:43 +08:00
he e8aec5f04c 添加邮件枚举 2025-05-06 10:49:42 +08:00
hang 0afbd24923 增加备注
continuous-integration/drone/push Build is passing Details
2025-05-06 10:30:48 +08:00
hang 932772f8c8 修改阅片人筛选事件触发
continuous-integration/drone/push Build is passing Details
2025-05-06 10:26:39 +08:00
he b7a803678c Revert "修改稽查"
continuous-integration/drone/push Build is passing Details
This reverts commit 5064630d1f.
2025-04-30 09:57:13 +08:00
he e99360bf5b 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 Details
2025-04-29 17:56:16 +08:00
he 5064630d1f 修改稽查 2025-04-29 17:56:14 +08:00
hang 4034da47f2 测量数据里面带任务Id 需要替换
continuous-integration/drone/push Build is passing Details
2025-04-28 18:03:18 +08:00
hang 381b1965cf 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 Details
2025-04-27 16:24:26 +08:00
hang d5e747becd 修改导出 2025-04-27 16:24:24 +08:00
he 758273d362 修改
continuous-integration/drone/push Build is passing Details
2025-04-27 13:08:22 +08:00
he 1560a0278e 修改
continuous-integration/drone/push Build is passing Details
2025-04-27 13:05:31 +08:00
he 64c275a91c 修改
continuous-integration/drone/push Build is passing Details
2025-04-27 10:18:31 +08:00
he 05189b4e5a 修改稽查
continuous-integration/drone/push Build is passing Details
2025-04-25 17:19:12 +08:00
hang 80aaac997d 没有收件人,默认不发送
continuous-integration/drone/push Build is passing Details
2025-04-25 10:01:32 +08:00
hang c560921092 修改配置
continuous-integration/drone/push Build is passing Details
2025-04-25 09:46:41 +08:00
hang 81cd9aa6b7 修改邮件自动发送配置
continuous-integration/drone/push Build is passing Details
2025-04-25 09:20:06 +08:00
hang 4bfc6dd295 调研表发送邮件修改
continuous-integration/drone/push Build is passing Details
2025-04-24 17:29:22 +08:00
hang a8464364c1 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 Details
2025-04-24 17:22:54 +08:00
hang e333368528 修改邮件发送配置 2025-04-24 17:22:52 +08:00
he 58c1c25fc2 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 Details
2025-04-24 15:53:26 +08:00
he 3045b0ec48 修改 2025-04-24 15:53:22 +08:00
hang 2d50037c03 外部人员 不能看未签名的文档
continuous-integration/drone/push Build is passing Details
2025-04-24 15:18:55 +08:00
he 6a1cd07951 修改
continuous-integration/drone/push Build is passing Details
2025-04-24 14:55:50 +08:00
he c7103654e3 修改
continuous-integration/drone/push Build is passing Details
2025-04-24 10:02:39 +08:00
he 4e03071c4c 修改
continuous-integration/drone/push Build is passing Details
2025-04-24 09:55:49 +08:00
he bf9e8a6758 修改
continuous-integration/drone/push Build is passing Details
2025-04-24 09:36:57 +08:00
he 00c6705161 修改
continuous-integration/drone/push Build is passing Details
2025-04-24 09:31:56 +08:00
he 209d932757 修改
continuous-integration/drone/push Build is passing Details
2025-04-23 16:25:00 +08:00
he e954ea8538 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 Details
2025-04-23 13:56:38 +08:00
he f79a8b4cfb 复制修改 2025-04-23 13:56:36 +08:00
hang 8fc01e2509 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 Details
2025-04-23 13:30:14 +08:00
hang 232e607b8c 增加系统文档导出 2025-04-23 13:30:09 +08:00
he bdeb7c464e 修改
continuous-integration/drone/push Build is passing Details
2025-04-23 10:55:08 +08:00
he 3668079479 修改
continuous-integration/drone/push Build is passing Details
2025-04-23 10:48:16 +08:00
he c115e9453b 修改
continuous-integration/drone/push Build is passing Details
2025-04-23 10:03:24 +08:00
he f157a0f473 登录修改
continuous-integration/drone/push Build is passing Details
2025-04-23 09:54:00 +08:00
he c2252b4e9f 修改
continuous-integration/drone/push Build is passing Details
2025-04-22 17:53:55 +08:00
he b0554119f1 修改
continuous-integration/drone/push Build is passing Details
2025-04-22 13:56:05 +08:00
he 37387692dd 修改
continuous-integration/drone/push Build is passing Details
2025-04-22 13:20:02 +08:00
he 970c41a064 修改
continuous-integration/drone/push Build is passing Details
2025-04-22 11:41:24 +08:00
he 67a3fe0f1b 修改
continuous-integration/drone/push Build is running Details
2025-04-22 11:40:28 +08:00
he 15108156c2 拷贝问题修改
continuous-integration/drone/push Build is passing Details
2025-04-22 11:33:38 +08:00
he 1a2c51da12 修改
continuous-integration/drone/push Build is passing Details
2025-04-22 09:40:16 +08:00
he 3d10482da8 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 Details
2025-04-22 09:29:36 +08:00
he 3abc8787c6 修改 2025-04-22 09:29:32 +08:00
hang df346d31e6 编译错误
continuous-integration/drone/push Build is passing Details
2025-04-22 09:24:30 +08:00
hang a8babb53f2 修改时区测试
continuous-integration/drone/push Build is passing Details
2025-04-22 09:20:49 +08:00
hang 3c1cc92e1b 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 Details
2025-04-21 17:00:28 +08:00
hang 99ee8c4757 增加邮件事件 2025-04-21 17:00:26 +08:00
he fc81d6da22 修改
continuous-integration/drone/push Build is passing Details
2025-04-21 14:50:58 +08:00
he 47edcbd761 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 Details
2025-04-21 14:26:24 +08:00
he a499971e91 修改 2025-04-21 14:26:23 +08:00
he afd34c7c9b 修改
continuous-integration/drone/push Build is running Details
2025-04-21 14:15:21 +08:00
hang 529c646277 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 Details
2025-04-21 14:15:20 +08:00
hang b8f03153ca 修改反了 2025-04-21 14:15:19 +08:00
he a14df73879 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 Details
2025-04-21 14:05:51 +08:00
he cb9141c1ce 修改 2025-04-21 14:05:50 +08:00
hang ff2461dafc 查询启用的角色
continuous-integration/drone/push Build is passing Details
2025-04-21 14:02:39 +08:00
he 779af013e6 修改
continuous-integration/drone/push Build is passing Details
2025-04-21 13:37:50 +08:00
he 75fb357cc5 修改
continuous-integration/drone/push Build is passing Details
2025-04-21 13:24:24 +08:00
he 89eb1032cf 修改
continuous-integration/drone/push Build is passing Details
2025-04-21 11:28:45 +08:00
he eca9c36110 修改
continuous-integration/drone/push Build is passing Details
2025-04-21 11:09:38 +08:00
he 2430651ed4 修改
continuous-integration/drone/push Build is passing Details
2025-04-18 14:13:12 +08:00
he 87d658031b 修改
continuous-integration/drone/push Build is passing Details
2025-04-18 14:10:46 +08:00
he 34b90538ab 修改
continuous-integration/drone/push Build is passing Details
2025-04-18 13:36:53 +08:00
he d2571d5f79 修改
continuous-integration/drone/push Build is passing Details
2025-04-18 11:41:47 +08:00
he 1688d7c934 修改
continuous-integration/drone/push Build is passing Details
2025-04-18 10:24:38 +08:00
he 9ab5dc7d02 修改
continuous-integration/drone/push Build is passing Details
2025-04-17 17:24:15 +08:00
he 97cdec61be 修改
continuous-integration/drone/push Build is passing Details
2025-04-17 17:21:23 +08:00
he c0d6eb3203 修改
continuous-integration/drone/push Build is passing Details
2025-04-17 15:33:44 +08:00
he d125ff6324 x修改
continuous-integration/drone/push Build is passing Details
2025-04-16 13:28:00 +08:00
he 1b830b386e 修改
continuous-integration/drone/push Build is passing Details
2025-04-16 11:30:27 +08:00
he ee83909123 修改
continuous-integration/drone/push Build is passing Details
2025-04-16 10:26:10 +08:00
he 844e27e94e 修改
continuous-integration/drone/push Build is passing Details
2025-04-15 17:55:16 +08:00
he 6fded9f028 修改
continuous-integration/drone/push Build is passing Details
2025-04-15 17:23:45 +08:00
he b5103f1940 修改
continuous-integration/drone/push Build is passing Details
2025-04-15 16:54:38 +08:00
he 8bf54dfc1b 修改
continuous-integration/drone/push Build is running Details
2025-04-15 16:54:24 +08:00
he 1069292c54 修改
continuous-integration/drone/push Build is passing Details
2025-04-15 15:39:59 +08:00
he 88c6f574ec 修改
continuous-integration/drone/push Build is passing Details
2025-04-15 15:36:23 +08:00
he f5f6d3b6ac 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 Details
2025-04-15 15:16:11 +08:00
he 38f937ea9e 查询修改 2025-04-15 15:16:08 +08:00
hang 2913eb67f4 修改删除的文件统计数字
continuous-integration/drone/push Build is running Details
2025-04-15 15:14:37 +08:00
hang a0ceec28e7 修改删除统计文件数字
continuous-integration/drone/push Build is passing Details
2025-04-15 14:54:32 +08:00
hang b77a50caf6 非dicom 删除上传
continuous-integration/drone/push Build is passing Details
2025-04-15 14:33:03 +08:00
hang e17fc6bce9 修改删除
continuous-integration/drone/push Build is passing Details
2025-04-15 13:20:55 +08:00
hang 0970e2807b 修改非dicom 删除
continuous-integration/drone/push Build is passing Details
2025-04-15 11:37:00 +08:00
hang a64d26513a 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 Details
2025-04-15 11:33:24 +08:00
hang 73e80f2571 修改非dicom 删除 2025-04-15 11:33:23 +08:00
hang 770f361d04 修改非dicom 删除
continuous-integration/drone/push Build is passing Details
2025-04-15 11:05:22 +08:00
hang 7476472071 软删除修改
continuous-integration/drone/push Build is passing Details
2025-04-15 10:54:28 +08:00
hang 1fff2f7256 修改删除
continuous-integration/drone/push Build is passing Details
2025-04-15 09:13:56 +08:00
he 1e4044488d 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 Details
2025-04-14 14:39:42 +08:00
he 1e1822151b 修改 2025-04-14 14:39:40 +08:00
hang c37b6c4c84 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 Details
2025-04-14 14:23:49 +08:00
hang 8f65b9e60e 修改检查列表查询 2025-04-14 14:23:47 +08:00
he a8a9a09f88 修改
continuous-integration/drone/push Build is passing Details
2025-04-14 14:11:06 +08:00
he 7526ca2905 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 Details
2025-04-14 14:10:23 +08:00
he fd83c3e7a7 修改 2025-04-14 14:10:23 +08:00
hang a3c575857a 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 Details
2025-04-14 14:04:53 +08:00
hang c292f6ce44 修改质控删除bug 测试 2025-04-14 14:04:51 +08:00
he 84a7d75174 修改
continuous-integration/drone/push Build is running Details
2025-04-14 14:03:54 +08:00
he 048afdcc7b 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 Details
2025-04-14 13:56:54 +08:00
he 06e319cf09 代码修改 2025-04-14 13:56:52 +08:00
hang cee0730e03 升级nuget包
continuous-integration/drone/push Build is passing Details
2025-04-14 13:54:27 +08:00
he adaa672185 修改
continuous-integration/drone/push Build is passing Details
2025-04-14 11:20:59 +08:00
he b6b5d3e4c9 代码修改
continuous-integration/drone/push Build is passing Details
2025-04-14 11:03:01 +08:00
he 6ac057a0c7 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 Details
2025-04-14 10:28:33 +08:00
he 6607a0ff8f 修改复制 2025-04-14 10:28:30 +08:00
hang 0374551655 修改限制
continuous-integration/drone/push Build is passing Details
2025-04-11 17:43:07 +08:00
hang be9f0075e3 增加申请限制
continuous-integration/drone/push Build is passing Details
2025-04-11 16:57:39 +08:00
hang 2cc004746e 增加限制
continuous-integration/drone/push Build is passing Details
2025-04-11 16:32:00 +08:00
hang b1a7ac1d28 修改映射字段
continuous-integration/drone/push Build is passing Details
2025-04-11 15:05:18 +08:00
hang 5a31e16c65 修改限制
continuous-integration/drone/push Build is passing Details
2025-04-11 14:06:53 +08:00
hang 0b56836097 升级普通组件包
continuous-integration/drone/push Build is passing Details
2025-04-11 13:40:07 +08:00
hang a4a11aaaec 修改查询条件
continuous-integration/drone/push Build is passing Details
2025-04-11 11:36:29 +08:00
hang ae1b2523b1 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 Details
2025-04-11 10:21:45 +08:00
hang 87f9d08c74 添加冗余字段 2025-04-11 10:21:42 +08:00
he 81abd9622f 修改病灶验证
continuous-integration/drone/push Build is passing Details
2025-04-11 10:10:46 +08:00
he faf87f5b86 修改记录
continuous-integration/drone/push Build is passing Details
2025-04-10 17:30:09 +08:00
he 66dc231850 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 Details
2025-04-10 14:01:07 +08:00
he 34ff47bc1c 修改 2025-04-10 14:01:06 +08:00
hang 842b7117a2 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 Details
2025-04-10 11:50:23 +08:00
hang 6543aba53f 文档签署 2025-04-10 11:50:20 +08:00
he 06cee8926e 修改
continuous-integration/drone/push Build is passing Details
2025-04-10 11:18:36 +08:00
he a35fe11f5b 修改
continuous-integration/drone/push Build is passing Details
2025-04-10 11:14:00 +08:00
he cc13544968 修改
continuous-integration/drone/push Build is passing Details
2025-04-10 10:40:05 +08:00
he 19ee511d8d 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 Details
2025-04-10 10:32:18 +08:00
he 0b47d6ca09 新增文件夹 2025-04-10 10:32:15 +08:00
hang 00193bb4bc 修改统计数字
continuous-integration/drone/push Build is passing Details
2025-04-10 10:05:15 +08:00
hang 4379fcbdb3 增加字段
continuous-integration/drone/push Build is passing Details
2025-04-10 09:49:38 +08:00
hang 8464625bbf 修改统计数字
continuous-integration/drone/push Build is passing Details
2025-04-10 09:31:36 +08:00
hang e88f949cb7 增加新的提示
continuous-integration/drone/push Build is passing Details
2025-04-09 17:46:23 +08:00
hang 4fdb0737fc 修改查询条件
continuous-integration/drone/push Build is passing Details
2025-04-09 17:07:18 +08:00
hang 04be8cf642 修改访视查询下拉框
continuous-integration/drone/push Build is passing Details
2025-04-09 17:03:17 +08:00
hang 089ecbf144 增加访视提交时间
continuous-integration/drone/push Build is passing Details
2025-04-09 16:48:22 +08:00
hang b95e97a5df 增加用户列表接口
continuous-integration/drone/push Build is passing Details
2025-04-09 16:45:52 +08:00
hang e84710c4aa 修改查询
continuous-integration/drone/push Build is passing Details
2025-04-09 15:20:40 +08:00
hang f549d1fca9 删除部分迁移文件
continuous-integration/drone/push Build is passing Details
2025-04-09 15:15:26 +08:00
hang 2c72dc000f 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 Details
2025-04-09 15:09:54 +08:00
hang 2ceddc1340 修改统计 2025-04-09 15:09:53 +08:00
he f118c48d0e 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 Details
2025-04-09 15:03:58 +08:00
he a3a1236d5b 修改 2025-04-09 15:03:57 +08:00
hang a7848727ee 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 Details
2025-04-09 11:27:21 +08:00
hang 5787c36687 修改验证 2025-04-09 11:27:17 +08:00
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 Details
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 Details
2025-04-08 15:20:09 +08:00
hang 4fd77ce70d 影像回退逻辑增加
continuous-integration/drone/push Build is passing Details
2025-04-08 14:50:45 +08:00
he 8213c6d10f 测试肿瘤学评估
continuous-integration/drone/push Build is passing Details
2025-04-08 09:31:36 +08:00
he b79b4567b4 修改稽查文档
continuous-integration/drone/push Build is passing Details
2025-04-07 17:42:58 +08:00
he 8c5b759a92 同步修改
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
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 Details
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 Details
2025-04-07 14:31:06 +08:00
hang 9bcaa07c1a 测试新的解析IP的库
continuous-integration/drone/push Build is passing Details
2025-04-07 14:08:30 +08:00
he bf5f56f5f2 修改查询
continuous-integration/drone/push Build is passing Details
2025-04-07 11:06:11 +08:00
he c1c2b59641 修改
continuous-integration/drone/push Build is passing Details
2025-04-03 17:31:51 +08:00
he 33820c2acb 修改
continuous-integration/drone/push Build is passing Details
2025-04-03 17:26:19 +08:00
he 9814f63246 修改
continuous-integration/drone/push Build is passing Details
2025-04-03 16:27:06 +08:00
he 5e6c018199 修改
continuous-integration/drone/push Build is passing Details
2025-04-03 16:10:11 +08:00
he b24751287c 修改
continuous-integration/drone/push Build is running Details
2025-04-03 16:07:48 +08:00
he 759cc6c1be 修改
continuous-integration/drone/push Build is passing Details
2025-04-03 15:29:22 +08:00
he 1a929ce2ca 修改
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-04-03 14:26:11 +08:00
hang ab00d64725 移除之前的废弃包换用微软新包
continuous-integration/drone/push Build is running Details
2025-04-03 14:23:42 +08:00
hang 5e36054ee9 删除logdashboard 升级下fo-dicom 常见包
continuous-integration/drone/push Build is passing Details
2025-04-03 14:17:24 +08:00
hang 2b11042f35 升级fo-dicom
continuous-integration/drone/push Build is passing Details
2025-04-03 14:04:28 +08:00
hang e9e5075c1c 验证环境生成缩略图测试ok提交
continuous-integration/drone/push Build is passing Details
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 Details
2025-04-03 11:29:13 +08:00
he 553ad4760c 修改
continuous-integration/drone/push Build is passing Details
2025-04-02 15:55:12 +08:00
he 5acd56689b 修改
continuous-integration/drone/push Build is running Details
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 Details
2025-04-02 13:46:08 +08:00
he c49f16b055 修改
continuous-integration/drone/push Build is passing Details
2025-04-02 13:44:36 +08:00
he aa42d64cac 修改
continuous-integration/drone/push Build is passing Details
2025-04-01 18:05:58 +08:00
he 8f0ef86ab9 修改
continuous-integration/drone/push Build is passing Details
2025-04-01 17:55:48 +08:00
he c17b2f6bac 修改
continuous-integration/drone/push Build is running Details
2025-04-01 17:53:13 +08:00
he be498f2329 修改
continuous-integration/drone/push Build is passing Details
2025-04-01 16:54:23 +08:00
he fea3d8d415 修改
continuous-integration/drone/push Build is passing Details
2025-04-01 16:39:28 +08:00
he bffc8626c7 修改
continuous-integration/drone/push Build is passing Details
2025-04-01 16:31:47 +08:00
he 1efe1228ac 修改
continuous-integration/drone/push Build is passing Details
2025-04-01 16:21:50 +08:00
he f900b811c7 修改
continuous-integration/drone/push Build is passing Details
2025-04-01 16:18:10 +08:00
he a5f7e03f6c 修改
continuous-integration/drone/push Build is passing Details
2025-04-01 16:05:13 +08:00
he 7aba4adc14 修改
continuous-integration/drone/push Build is passing Details
2025-04-01 15:52:37 +08:00
he 12c8c641ea 查询修改
continuous-integration/drone/push Build is passing Details
2025-04-01 15:09:47 +08:00
he 977adf3153 修改项目下拉查询
continuous-integration/drone/push Build is passing Details
2025-04-01 13:10:30 +08:00
he 409b76df26 修改
continuous-integration/drone/push Build is passing Details
2025-03-31 17:48:30 +08:00
he 2d9ebe7094 修改
continuous-integration/drone/push Build is passing Details
2025-03-31 15:26:13 +08:00
he 71e797cf7d 修改
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
2025-03-28 14:55:59 +08:00
he 58e8c2392f 添加MRecisthhc
continuous-integration/drone/push Build is passing Details
2025-03-28 11:12:09 +08:00
he 0e1310324d 修改
continuous-integration/drone/push Build is passing Details
2025-03-28 09:48:46 +08:00
he efcda61104 修改
continuous-integration/drone/push Build is passing Details
2025-03-27 17:11:00 +08:00
he 97133a5554 文档修改
continuous-integration/drone/push Build is passing Details
2025-03-27 16:29:55 +08:00
he 577ed42f97 修改文件路径
continuous-integration/drone/push Build is passing Details
2025-03-27 16:19:08 +08:00
he 8f704c4617 修改
continuous-integration/drone/push Build is passing Details
2025-03-27 16:03:12 +08:00
he a03d7f55c7 稽查文档
continuous-integration/drone/push Build is passing Details
2025-03-27 15:48:33 +08:00
he 2bbc101f95 修改
continuous-integration/drone/push Build is passing Details
2025-03-27 11:17:59 +08:00
he 2b11e9165f 修改
continuous-integration/drone/push Build is passing Details
2025-03-27 11:08:06 +08:00
he b25dec68cb 修改项目下拉列表
continuous-integration/drone/push Build is passing Details
2025-03-27 10:55:45 +08:00
hang 2f57238f66 修改swagger 展示
continuous-integration/drone/push Build is passing Details
2025-03-26 14:22:26 +08:00
hang 8239061a84 修改异地登录bug 设置最后一次登录的iP
continuous-integration/drone/push Build is passing Details
2025-03-26 11:11:34 +08:00
hang a43ebc016a 修改异地登录ip逻辑
continuous-integration/drone/push Build is passing Details
2025-03-25 17:49:13 +08:00
hang c036aab9c4 修改refer
continuous-integration/drone/push Build is passing Details
2025-03-24 17:13:43 +08:00
hang dd6419dc44 撤回修改
continuous-integration/drone/push Build is passing Details
2025-03-24 17:13:21 +08:00
hang 54a9cfbb8e 修改refer
continuous-integration/drone/push Build is running Details
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 Details
2025-03-24 16:59:47 +08:00
hang 712f1ceb61 修改非dicom 检查
continuous-integration/drone/push Build is passing Details
2025-03-24 16:59:11 +08:00
he adf873639c 修改稽查报错问题
continuous-integration/drone/push Build is passing Details
2025-03-24 16:46:33 +08:00
hang 4e9460e7da 为cdn 部署取项目Id 修改
continuous-integration/drone/push Build is passing Details
2025-03-24 15:17:44 +08:00
hang 5481eac988 增加环境变量
continuous-integration/drone/push Build is passing Details
2025-03-24 11:20:03 +08:00
he b7c9abca02 拷贝表单
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
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 Details
2025-03-20 09:35:34 +08:00
hang f99cab6983 获取文件大小 oss
continuous-integration/drone/push Build is passing Details
2025-03-19 17:16:39 +08:00
he c94d800646 移动文件
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-03-18 13:55:30 +08:00
he 5cf8c7a898 查询撤销
continuous-integration/drone/push Build is passing Details
2025-03-18 10:33:43 +08:00
he 11c9cebf47 接口修改
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-03-18 09:33:38 +08:00
he 9e4cf1d1db 修改
continuous-integration/drone/push Build is passing Details
2025-03-17 16:44:43 +08:00
he ae38c84ef7 修改
continuous-integration/drone/push Build is passing Details
2025-03-17 16:30:27 +08:00
he 6306c6752a 修改
continuous-integration/drone/push Build is passing Details
2025-03-17 16:23:38 +08:00
he 5490630922 修改
continuous-integration/drone/push Build is passing Details
2025-03-17 15:31:53 +08:00
he d1ea886e76 修改排序
continuous-integration/drone/push Build is passing Details
2025-03-17 14:48:16 +08:00
he 7dc1205bb6 修改
continuous-integration/drone/push Build is passing Details
2025-03-17 14:14:01 +08:00
he 15b094a422 修改
continuous-integration/drone/push Build is passing Details
2025-03-17 13:52:23 +08:00
he 78c46572a2 修改路径
continuous-integration/drone/push Build is passing Details
2025-03-17 11:21:56 +08:00
he abeda7820d 修改文件路径
continuous-integration/drone/push Build is passing Details
2025-03-17 10:50:21 +08:00
he 2dac67618c 修改
continuous-integration/drone/push Build is passing Details
2025-03-14 17:10:22 +08:00
he bb9b1283bf 修改
continuous-integration/drone/push Build is passing Details
2025-03-14 16:47:39 +08:00
he b9458ecb38 修改
continuous-integration/drone/push Build is passing Details
2025-03-14 16:12:42 +08:00
he b205757f8f 修改
continuous-integration/drone/push Build is passing Details
2025-03-14 16:01:41 +08:00
he 0b937663ff 修改
continuous-integration/drone/push Build is passing Details
2025-03-14 15:11:21 +08:00
he 7a75d107dc 修改
continuous-integration/drone/push Build is passing Details
2025-03-14 14:50:12 +08:00
he 0f682dd184 修改
continuous-integration/drone/push Build is passing Details
2025-03-14 14:40:14 +08:00
he c2360dd519 修改
continuous-integration/drone/push Build is passing Details
2025-03-14 14:25:02 +08:00
he f9c2ac030a 修改
continuous-integration/drone/push Build is passing Details
2025-03-14 13:29:01 +08:00
he 7ce2386aea 修改
continuous-integration/drone/push Build is passing Details
2025-03-14 12:52:14 +08:00
he 67b226ee44 修改
continuous-integration/drone/push Build is passing Details
2025-03-14 11:45:20 +08:00
he 70c7f8a740 查询修改
continuous-integration/drone/push Build is passing Details
2025-03-14 10:20:55 +08:00
he e409aa3c05 修改
continuous-integration/drone/push Build is passing Details
2025-03-13 16:59:47 +08:00
he a3b5129ee2 修改
continuous-integration/drone/push Build is passing Details
2025-03-13 16:43:19 +08:00
he 57cd0281fa 查询条件修改
continuous-integration/drone/push Build is passing Details
2025-03-13 16:33:53 +08:00
he ba9d3abc52 修改
continuous-integration/drone/push Build is passing Details
2025-03-13 16:16:30 +08:00
he b9bc1f6da0 入项记录上传与修改
continuous-integration/drone/push Build is passing Details
2025-03-13 15:43:53 +08:00
he 08f1998e61 修改
continuous-integration/drone/push Build is passing Details
2025-03-13 15:22:40 +08:00
he bc19ead2f5 添加optuserType
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-03-12 18:05:34 +08:00
he 94bba7837c 国际化修改
continuous-integration/drone/push Build is passing Details
2025-03-12 11:12:35 +08:00
he 626fcb9cf3 修改
continuous-integration/drone/push Build is passing Details
2025-03-12 09:37:36 +08:00
he bf92165432 修改
continuous-integration/drone/push Build is running Details
2025-03-12 09:36:55 +08:00
he 92e99edbbd 修改项目稽查
continuous-integration/drone/push Build is passing Details
2025-03-11 16:59:34 +08:00
he 94507c7887 修改稽查
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
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 Details
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 Details
2025-03-10 17:35:30 +08:00
he 0f03dbc75b 修改
continuous-integration/drone/push Build is passing Details
2025-03-10 14:45:03 +08:00
he e5fa3a09b3 修改查询
continuous-integration/drone/push Build is passing Details
2025-03-10 14:17:22 +08:00
he 4cdfb60fdf 添加阅片人接口
continuous-integration/drone/push Build is passing Details
2025-03-10 13:46:12 +08:00
he 200bdaccc4 修改
continuous-integration/drone/push Build is passing Details
2025-03-10 11:38:10 +08:00
he 17a35e0fdb 修改
continuous-integration/drone/push Build is passing Details
2025-03-10 11:13:43 +08:00
he 28f2bf1629 修改
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-03-07 15:54:05 +08:00
hang 92c495ed07 非dicom 预览阅片
continuous-integration/drone/push Build is passing Details
2025-03-07 15:41:46 +08:00
hang d9d807e3d1 修改dicom 只有一个序列设置删除 检查被过滤
continuous-integration/drone/push Build is passing Details
2025-03-07 10:35:18 +08:00
hang 959b49a2cc 非dicom 预览阅片影像 过滤是否阅片
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-03-06 14:38:12 +08:00
he 104b1208ed 修改
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
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 Details
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 Details
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 Details
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 Details
2025-03-05 13:12:48 +08:00
he caf1fb6b32 修改
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-03-05 10:43:11 +08:00
hang f89b3daf50 qc 序列层级返回更新时间
continuous-integration/drone/push Build is passing Details
2025-03-05 10:42:58 +08:00
hang 29f6196698 合并
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
2025-03-05 09:31:37 +08:00
he a9efd85aec 修改
continuous-integration/drone/push Build is passing Details
2025-03-04 17:58:33 +08:00
he 09e70b9f21 修改
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-03-04 15:20:27 +08:00
hang 336e7768b8 时间拼写错误
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
2025-03-04 10:45:29 +08:00
he b6da27ac07 修改
continuous-integration/drone/push Build is passing Details
2025-03-03 17:20:38 +08:00
he a6b81b038f 修改
continuous-integration/drone/push Build is passing Details
2025-03-03 16:49:43 +08:00
he e2c80babfa 修改
continuous-integration/drone/push Build is passing Details
2025-03-03 16:34:58 +08:00
he 01b9f28e7b 批量添加
continuous-integration/drone/push Build is passing Details
2025-03-03 16:08:50 +08:00
he 2c9fad60fb 修改
continuous-integration/drone/push Build is passing Details
2025-03-03 16:03:04 +08:00
he 398baea876 字段修改
continuous-integration/drone/push Build is passing Details
2025-03-03 13:56:01 +08:00
he aec94d0a46 数据库修改
continuous-integration/drone/push Build is passing Details
2025-03-03 13:43:34 +08:00
he 4b69e45d44 实体修改
continuous-integration/drone/push Build is passing Details
2025-03-03 13:18:11 +08:00
he 12f2c2becb 修改
continuous-integration/drone/push Build is passing Details
2025-03-03 11:06:44 +08:00
he 699f79278b 修改
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
2025-02-27 17:19:53 +08:00
he bf62ee92dd 添加 ImageFormatList
continuous-integration/drone/push Build is passing Details
2025-02-27 17:19:35 +08:00
he 78532803bc 影像质疑超限天数修改
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-02-27 16:15:11 +08:00
hang 02e5d770db 增加查询配置
continuous-integration/drone/push Build is passing Details
2025-02-27 16:14:46 +08:00
hang f8c3704c87 合并修改
continuous-integration/drone/push Build is passing Details
2025-02-27 15:39:48 +08:00
hang 4c21459e00 修改StudyName 存放位置
continuous-integration/drone/push Build is passing Details
2025-02-27 15:38:51 +08:00
he cdbbe460ab 修改实体
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
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 Details
2025-02-27 13:05:00 +08:00
he 553a8d392f 查询返回检查名称
continuous-integration/drone/push Build is passing Details
2025-02-27 11:33:31 +08:00
he f050416265 数据库文件
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
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 Details
2025-02-26 13:37:30 +08:00
hang 56170b73ed 修改非dicom 阅片
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
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 Details
2025-02-25 15:51:16 +08:00
he 4c04718db4 修改
continuous-integration/drone/push Build is passing Details
2025-02-25 15:23:42 +08:00
he 64d803cbc0 修改
continuous-integration/drone/push Build is passing Details
2025-02-25 15:01:57 +08:00
he 54ccae5762 修改
continuous-integration/drone/push Build is passing Details
2025-02-25 14:48:05 +08:00
he 8d6bf0c7b1 修改
continuous-integration/drone/push Build is passing Details
2025-02-25 14:26:21 +08:00
he 8496e6bcd7 修改
continuous-integration/drone/push Build is running Details
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 Details
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 Details
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 Details
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 Details
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 Details
2025-02-25 11:08:37 +08:00
hang e9f57b5001 临时注释提交,手动维护
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-02-25 10:26:55 +08:00
hang 812035686e 修改用户参与项目接口
continuous-integration/drone/push Build is passing Details
2025-02-25 09:57:45 +08:00
hang 1f8caa4616 合并
continuous-integration/drone/push Build is passing Details
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 Details
2025-02-24 17:17:25 +08:00
he c2412bfb4b 复制系统到项目
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
2025-02-24 13:45:55 +08:00
he 8bbc8c449f 合并
continuous-integration/drone/push Build is running Details
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 Details
2025-02-24 13:43:21 +08:00
hang 1c3ddcf1cd 修改邮箱登录bug
continuous-integration/drone/push Build is passing Details
2025-02-24 13:32:54 +08:00
hang fc4ef6b939 账号初始化链接过期+初始化不允许忘记密码修改密码
continuous-integration/drone/push Build is passing Details
2025-02-24 13:24:41 +08:00
hang 6d009c4f86 增加备注
continuous-integration/drone/push Build is passing Details
2025-02-24 11:32:26 +08:00
hang f995187925 修改文件类型基础代码
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-02-21 14:46:10 +08:00
hang 5dd2dfd17b 增加项目文档新表
continuous-integration/drone/push Build is passing Details
2025-02-21 14:20:39 +08:00
hang 5791aca9fd 最后一次登录时间 和ip 记录
continuous-integration/drone/push Build is passing Details
2025-02-20 15:26:36 +08:00
hang f61ce70b82 修改项目培训统计数字
continuous-integration/drone/push Build is passing Details
2025-02-20 15:05:13 +08:00
hang c8091d3215 清理签名文档的表
continuous-integration/drone/push Build is passing Details
2025-02-20 13:47:09 +08:00
hang 7153d810aa 删除用户角色表部分字段,修改统计
continuous-integration/drone/push Build is passing Details
2025-02-20 13:08:06 +08:00
hang 68053d24b6 项目创建账户的时候,没有用户名,但是目标用户Id 有值,导致查询出来有名字
continuous-integration/drone/push Build is passing Details
2025-02-19 14:20:06 +08:00
hang a49b4c8ef7 修改冲突
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-02-18 13:35:22 +08:00
hang 21626cda9d 维护历史退出人员数据
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-02-17 17:15:44 +08:00
hang fed2cbe043 修改 创建账号仅仅记录一条
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
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 Details
2025-02-17 09:28:02 +08:00
hang 4555997957 修改文档查询条件问题
continuous-integration/drone/push Build is passing Details
2025-02-17 09:22:58 +08:00
hang 3b43bee0f1 x
continuous-integration/drone/push Build is passing Details
2025-02-14 17:30:21 +08:00
hang 3677a30bab 修改日志角色查询
continuous-integration/drone/push Build is passing Details
2025-02-14 17:19:50 +08:00
hang 2e8b2a24ae 合并冲突
continuous-integration/drone/push Build is passing Details
2025-02-14 16:51:09 +08:00
hang 26500aa1cf 修改日志
continuous-integration/drone/push Build is passing Details
2025-02-14 16:48:52 +08:00
hang adfd6b50c1 修改登录日志
continuous-integration/drone/push Build is failing Details
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 Details
2025-02-14 16:15:37 +08:00
hang 580eea7a61 修改稽查查询条件bug
continuous-integration/drone/push Build is passing Details
2025-02-14 16:15:21 +08:00
hang da27b65e56 用户登录日志 项目参与用户修改
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
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 Details
2025-02-14 14:18:51 +08:00
hang c2c8f65aaa 修改质控问题答案排序
continuous-integration/drone/push Build is passing Details
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 Details
2025-02-14 13:09:26 +08:00
hang 1e9f4d890f 质控预览再次修改0214
continuous-integration/drone/push Build is passing Details
2025-02-14 10:54:00 +08:00
hang 44f74fd9e6 修改 预览根据质控状态过滤
continuous-integration/drone/push Build is passing Details
2025-02-13 18:01:17 +08:00
hang f1c8415899 修改阅片预览影像(同时标记了删除 和阅片)
continuous-integration/drone/push Build is passing Details
2025-02-13 17:11:21 +08:00
hang 823ada5673 合并
continuous-integration/drone/push Build is passing Details
2025-02-13 16:53:27 +08:00
hang 55f146a44a 修改序列上的Instance 数量
continuous-integration/drone/push Build is passing Details
2025-02-13 16:52:13 +08:00
hang 5fe972bd99 修改质控预览影像 uat 修改
continuous-integration/drone/push Build is passing Details
2025-02-13 16:43:59 +08:00
hang 0578263e10 修改质控预览影像 uat 修改
continuous-integration/drone/push Build is passing Details
2025-02-13 16:40:34 +08:00
hang 9316c0814f 合并
continuous-integration/drone/push Build is passing Details
2025-02-13 16:16:18 +08:00
hang 8bdd9e29ab 修改阅片看到得instance 序列
continuous-integration/drone/push Build is failing Details
2025-02-13 16:13:52 +08:00
hang ae14a8a530 修改预览不阅片影像数字
continuous-integration/drone/push Build is passing Details
2025-02-13 15:53:02 +08:00
hang 2a170cc97e 修改预览不阅片影像数字
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
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 Details
2025-02-13 11:06:32 +08:00
hang 14690dc3cc 合并修改
continuous-integration/drone/push Build is passing Details
2025-02-13 10:59:23 +08:00
hang 6dd0831a66 质控预览 增加是否阅片 是否删除 第二次提交
continuous-integration/drone/push Build is passing Details
2025-02-13 10:40:18 +08:00
hang a150156810 修改配置文件
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
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 Details
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 Details
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 Details
2025-02-10 15:08:14 +08:00
hang 585e4cdc1b 修改一致性核查对话判断
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
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 Details
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 Details
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 Details
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 Details
2025-02-08 10:54:06 +08:00
he f1185758d6 修改领取规则
continuous-integration/drone/push Build is passing Details
2025-02-08 10:48:00 +08:00
he 0d4a0adf00 添加IsPACSConnect
continuous-integration/drone/push Build is passing Details
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 Details
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 Details
2025-02-08 09:33:29 +08:00
he 91471dee13 修改配置
continuous-integration/drone/push Build is passing Details
2025-02-07 15:03:14 +08:00
hang a80dc14dcc 修改一致性核查测试
continuous-integration/drone/push Build is passing Details
2025-01-24 16:26:57 +08:00
hang e1cd187f4b 修改部位排序
continuous-integration/drone/push Build is passing Details
2025-01-24 15:55:33 +08:00
hang 35fb7533db x
continuous-integration/drone/push Build is passing Details
2025-01-24 14:30:47 +08:00
hang bdd9b69dfd 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 Details
2025-01-24 13:43:49 +08:00
hang 82a043a233 修改配置文件 2025-01-24 13:43:48 +08:00
he 66819a1e89 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 Details
2025-01-24 12:28:56 +08:00
he 9089376e5e 添加美国正式环境 2025-01-24 12:28:54 +08:00
hang 8d3f654fe5 修改生产配置文件
continuous-integration/drone/push Build is passing Details
2025-01-24 10:30:08 +08:00
hang c607af9736 搜素条件修改
continuous-integration/drone/push Build is passing Details
2025-01-24 09:52:08 +08:00
hang 0b45c30d0b 修改配置
continuous-integration/drone/push Build is passing Details
2025-01-23 18:22:51 +08:00
hang 1b7de79209 修改统计数字过滤删除的
continuous-integration/drone/push Build is running Details
2025-01-23 18:19:50 +08:00
hang 4ffedb4052 修改参与人员退出限制
continuous-integration/drone/push Build is passing Details
2025-01-23 17:40:05 +08:00
hang d8eb7acf2e 修改登录设置自动退出时间
continuous-integration/drone/push Build is passing Details
2025-01-23 16:53:18 +08:00
hang 6f3a4d723c 修改配置文件
continuous-integration/drone/push Build is passing Details
2025-01-23 16:47:42 +08:00
hang 0b2305ae65 修改登录挤账号登录
continuous-integration/drone/push Build is passing Details
2025-01-23 16:35:02 +08:00
hang e86c255186 修改配置文件
continuous-integration/drone/push Build is passing Details
2025-01-23 15:40:38 +08:00
hang d8658dca2a 修改美国生产配置文件
continuous-integration/drone/push Build is passing Details
2025-01-23 14:51:33 +08:00
hang 4372202a5b 修改中心导入数据
continuous-integration/drone/push Build is passing Details
2025-01-23 14:42:26 +08:00
hang affdc3e229 修改导入数据空格问题
continuous-integration/drone/push Build is passing Details
2025-01-23 14:37:30 +08:00
hang cfa384d02a 修改文档签署统计数字
continuous-integration/drone/push Build is passing Details
2025-01-23 12:54:09 +08:00
hang a33b7d606b 修改过滤
continuous-integration/drone/push Build is passing Details
2025-01-23 11:19:27 +08:00
hang da9ea70e5e Merge branch 'Test_IRC_Net8' into Uat_IRC_Net8
continuous-integration/drone/push Build is passing Details
2025-01-23 11:15:22 +08:00
hang 6f254ca958 增加MIM
continuous-integration/drone/push Build is passing Details
2025-01-23 10:42:29 +08:00
hang da3bd07607 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 Details
2025-01-23 10:38:41 +08:00
hang 1569010d69 修改内外部筛选 2025-01-23 10:38:39 +08:00
he ea7b3f4f7a 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 Details
2025-01-23 09:33:35 +08:00
he fc041e810c 修改KeyFramesList 2025-01-23 09:33:33 +08:00
hang ebc00e3e6d 修改文档过滤
continuous-integration/drone/push Build is passing Details
2025-01-22 16:29:46 +08:00
hang 612c0b127c 修改取账号排序
continuous-integration/drone/push Build is passing Details
2025-01-22 14:56:00 +08:00
hang a67df04da6 Merge branch 'Test_IRC_Net8' into Uat_IRC_Net8
continuous-integration/drone/push Build is passing Details
2025-01-22 10:42:14 +08:00
hang 43ae270eb7 修改邮件配置
continuous-integration/drone/push Build is passing Details
2025-01-22 10:40:43 +08:00
he d41c88beeb 修改配置
continuous-integration/drone/push Build is passing Details
2025-01-22 10:25:12 +08:00
he 92486d8320 修改导出配置 2025-01-22 10:25:09 +08:00
hang 0d2d3408b5 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 Details
2025-01-22 10:14:41 +08:00
hang f76b66c35d 修改内外部 2025-01-22 10:14:38 +08:00
he 48a98de7cc 修改配置
continuous-integration/drone/push Build is passing Details
2025-01-22 09:27:24 +08:00
he 23ba634a42 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 Details
2025-01-22 09:25:51 +08:00
he 23d7598722 修改导出配置 2025-01-22 09:25:49 +08:00
hang 7885cd151a 优化逻辑
continuous-integration/drone/push Build is passing Details
2025-01-21 22:54:23 +08:00
hang fb478aa5f2 修改导表填充测试
continuous-integration/drone/push Build is passing Details
2025-01-21 22:23:45 +08:00
hang 31f56a39a5 导表临时修改
continuous-integration/drone/push Build is passing Details
2025-01-21 19:00:01 +08:00
hang 6860f9437b 修改裁判重阅问题
continuous-integration/drone/push Build is passing Details
2025-01-21 18:29:36 +08:00
hang a06e7a9a2c 维护密码历史日志
continuous-integration/drone/push Build is passing Details
2025-01-21 15:16:40 +08:00
hang ac8875acdf 修改验证码
continuous-integration/drone/push Build is passing Details
2025-01-21 11:40:18 +08:00
hang f79c12165e 修改用户密码增加记录
continuous-integration/drone/push Build is passing Details
2025-01-21 09:16:44 +08:00
hang 91b358e674 修改 前三次密码验证
continuous-integration/drone/push Build is passing Details
2025-01-20 20:14:44 +08:00
hang 7ec274fb72 修改密码逻辑
continuous-integration/drone/push Build is passing Details
2025-01-20 19:53:54 +08:00
hang 7d419595ca 修改添加pacs 影像bug
continuous-integration/drone/push Build is passing Details
2025-01-20 19:39:08 +08:00
hang a6e260dce1 签名文档bug
continuous-integration/drone/push Build is passing Details
2025-01-20 17:36:37 +08:00
hang 2e9a75279d 修改邮箱修改邮箱验证码错误
continuous-integration/drone/push Build is running Details
2025-01-20 17:35:25 +08:00
hang 68a57594ff 修改时间
continuous-integration/drone/push Build is passing Details
2025-01-20 17:23:21 +08:00
hang bd4d6c8c5f 修改退回bug
continuous-integration/drone/push Build is passing Details
2025-01-20 16:01:05 +08:00
hang a36a0513fe 修改scp 服务地址
continuous-integration/drone/push Build is passing Details
2025-01-20 15:51:52 +08:00
hang 02e418f660 修改账号日志
continuous-integration/drone/push Build is passing Details
2025-01-20 15:17:53 +08:00
hang 199f7060fa 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 Details
2025-01-20 14:53:23 +08:00
hang 9bdb782b8d 修改查看日志 和项目列表过滤
continuous-integration/drone/push Build is passing Details
2025-01-20 14:52:43 +08:00
he 9b9bbfbd5d 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 Details
2025-01-20 14:24:50 +08:00
he a9a034923f 删除OSS脏文件夹 2025-01-20 14:24:49 +08:00
hang 07b63077d1 Merge branch 'Uat_IRC_Net8' into Test_IRC_Net8
continuous-integration/drone/push Build is passing Details
2025-01-20 11:34:35 +08:00
hang 013b9720b3 添加中心增加验证
continuous-integration/drone/push Build is passing Details
2025-01-20 11:33:48 +08:00
hang f924b4985a 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 Details
2025-01-20 11:27:40 +08:00
hang 40b986e310 修改默认值 和账号已过期 2025-01-20 11:27:39 +08:00
he 146b0635c8 修改默认值
continuous-integration/drone/push Build is passing Details
2025-01-20 11:22:53 +08:00
he e76a5d189e 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 Details
2025-01-20 11:17:26 +08:00
he 6f81c39c62 全局阅片 默认值改为false 2025-01-20 11:17:24 +08:00
hang 036565ec81 Merge branch 'Test_IRC_Net8' into Uat_IRC_Net8
continuous-integration/drone/push Build is passing Details
2025-01-20 11:12:09 +08:00
hang a2225d7cba 修改发放token
continuous-integration/drone/push Build is passing Details
2025-01-20 11:09:55 +08:00
hang 3463b69b78 修改邮件 多了IR
continuous-integration/drone/push Build is passing Details
2025-01-20 10:44:27 +08:00
he bf61a05e45 修改查询问题
continuous-integration/drone/push Build is passing Details
2025-01-18 23:03:58 +08:00
he d930d51d0d 修改查询问题
continuous-integration/drone/push Build is passing Details
2025-01-18 22:55:22 +08:00
hang 629fbfb037 修改邮件
continuous-integration/drone/push Build is passing Details
2025-01-17 15:23:46 +08:00
hang 2255ee1b03 维护数据不要权限
continuous-integration/drone/push Build is passing Details
2025-01-17 14:10:19 +08:00
hang 5d269b699c Merge branch 'Test_IRC_Net8' into Uat_IRC_Net8
continuous-integration/drone/push Build is passing Details
2025-01-17 13:58:42 +08:00
hang 7b7723426b 修改统计数字
continuous-integration/drone/push Build is passing Details
2025-01-17 10:17:15 +08:00
hang 07f1511bb9 修改导入表
continuous-integration/drone/push Build is passing Details
2025-01-16 17:48:39 +08:00
hang 36f0e20340 修改备注
continuous-integration/drone/push Build is passing Details
2025-01-16 16:51:58 +08:00
hang 63919c8f6b 修改维护方法
continuous-integration/drone/push Build is passing Details
2025-01-16 15:13:58 +08:00
he 77798e929e 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 Details
2025-01-16 15:06:52 +08:00
he f407c5f514 稽查修改 2025-01-16 15:06:50 +08:00
hang e66df9bbc9 修改登录记录异地登录
continuous-integration/drone/push Build is passing Details
2025-01-16 13:31:14 +08:00
hang 38fe5aea25 修改枚举值
continuous-integration/drone/push Build is passing Details
2025-01-16 13:19:36 +08:00
hang 2d792b4557 修改用户登录
continuous-integration/drone/push Build is passing Details
2025-01-16 12:26:26 +08:00
hang 5222cdb8f1 屏幕解锁+ 密码错误 也异地登录
continuous-integration/drone/push Build is passing Details
2025-01-16 11:47:24 +08:00
hang 453d3f7653 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 Details
2025-01-16 11:22:40 +08:00
hang dca0dfb003 修改裁判阅片明细表过滤 2025-01-16 11:22:39 +08:00
he 2d1e2f53ee 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 Details
2025-01-16 11:12:57 +08:00
he 82167463e4 修改登录状态 2025-01-16 11:12:55 +08:00
hang e46f204204 非肿瘤评估标准,多表格 和单表格处理
continuous-integration/drone/push Build is passing Details
2025-01-16 08:59:21 +08:00
hang 9d6cdd5711 修改导表配置完成
continuous-integration/drone/push Build is passing Details
2025-01-15 22:48:54 +08:00
hang fc70ec7ad0 修改导表bug
continuous-integration/drone/push Build is passing Details
2025-01-15 22:39:20 +08:00
hang 68845ae44b 临时提交
continuous-integration/drone/push Build is passing Details
2025-01-15 21:09:06 +08:00
hang 5570c56b1e 修改导表 Excel 列名处理
continuous-integration/drone/push Build is passing Details
2025-01-15 12:54:58 +08:00
hang 2fdd7bf464 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 Details
2025-01-15 11:13:26 +08:00
hang 24c259a38b 修改导表 2025-01-15 11:13:24 +08:00
he f4a97b940a 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 Details
2025-01-15 10:57:03 +08:00
he 0f74444b22 修改 2025-01-15 10:57:02 +08:00
hang cf9d42dc49 修改翻译字典名
continuous-integration/drone/push Build is passing Details
2025-01-15 10:15:36 +08:00
hang f518b44007 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 Details
2025-01-14 15:50:13 +08:00
hang 95a203881e 修改1.1 导表配置 2025-01-14 15:50:12 +08:00
he b86361bf0e 修改
continuous-integration/drone/push Build is passing Details
2025-01-14 14:55:24 +08:00
he 5c97f37a75 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 Details
2025-01-14 13:20:54 +08:00
he 307d982fcb 删除项目 2025-01-14 13:20:52 +08:00
hang 3d791d2e41 修改阅片结果导出
continuous-integration/drone/push Build is passing Details
2025-01-14 10:45:12 +08:00
hang 538cfa279a 修改维护数据
continuous-integration/drone/push Build is passing Details
2025-01-13 16:55:04 +08:00
hang 3f2315c96d 异地登录修改
continuous-integration/drone/push Build is passing Details
2025-01-13 16:07:12 +08:00
he 293933ec7d 修改
continuous-integration/drone/push Build is passing Details
2025-01-13 15:35:53 +08:00
he 97d3b986de 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 Details
2025-01-13 15:22:55 +08:00
he f8fea6561d 修改 2025-01-13 15:22:54 +08:00
hang dfa8474a6e 修改导表
continuous-integration/drone/push Build is passing Details
2025-01-13 15:20:53 +08:00
he e022eb058b 修改
continuous-integration/drone/push Build is passing Details
2025-01-13 15:15:36 +08:00
he d04b425d62 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 Details
2025-01-13 14:56:16 +08:00
he c1fdf67d39 修改 2025-01-13 14:56:14 +08:00
hang dd902c1355 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 Details
2025-01-13 14:28:03 +08:00
hang b21b122d24 修改导表 2025-01-13 14:28:02 +08:00
he 7544bc81a3 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 Details
2025-01-13 13:51:38 +08:00
he aab998d5c6 修改 2025-01-13 13:51:37 +08:00
hang 3dc5507b6b 参与人员导表
continuous-integration/drone/push Build is passing Details
2025-01-13 13:08:28 +08:00
hang 12fbc2643c 修改角色停用,签名文档问题
continuous-integration/drone/push Build is passing Details
2025-01-13 11:46:26 +08:00
hang b14e712126 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 Details
2025-01-13 11:39:40 +08:00
hang c303f6677b 修改国际化和导表 2025-01-13 11:39:31 +08:00
he 1976cd8cdd 去掉ExportIdentification
continuous-integration/drone/push Build is passing Details
2025-01-13 11:25:14 +08:00
he cc6d5d2b4f 修改
continuous-integration/drone/push Build is passing Details
2025-01-10 15:41:32 +08:00
he b72edbf326 修改稽查
continuous-integration/drone/push Build is passing Details
2025-01-10 15:03:53 +08:00
he b0b23593f6 代码修改
continuous-integration/drone/push Build is passing Details
2025-01-10 14:54:31 +08:00
he 941eee9857 修改
continuous-integration/drone/push Build is passing Details
2025-01-10 14:38:48 +08:00
he 8f8751103e 修改
continuous-integration/drone/push Build is passing Details
2025-01-10 14:31:57 +08:00
he c575e15c55 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 Details
2025-01-10 14:17:50 +08:00
he 56afa2bf8d 修改 2025-01-10 14:17:48 +08:00
hang 2e993149a9 修改默认配置文件
continuous-integration/drone/push Build is passing Details
2025-01-10 14:06:51 +08:00
hang 89421ee731 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 Details
2025-01-10 14:05:10 +08:00
hang 2509e26aae 修改角色禁用 2025-01-10 14:05:05 +08:00
he db7e9b90ec 添加 SplitAndConcatenate 方法处理 IP 地址字符串 2025-01-10 10:29:56 +08:00
he 9827b22b6f 修改验证
continuous-integration/drone/push Build is passing Details
2025-01-10 10:09:53 +08:00
he 9636efcb56 修改标记
continuous-integration/drone/push Build is passing Details
2025-01-10 09:14:18 +08:00
he 06d8e4bea8 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 Details
2025-01-09 17:12:05 +08:00
he 5111372972 修改 2025-01-09 17:12:03 +08:00
hang 4cdf94d29c 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 Details
2025-01-09 16:20:40 +08:00
hang 5bacf2667f 修改最晚拍片日期 2025-01-09 16:20:39 +08:00
he 81cb833d57 修改
continuous-integration/drone/push Build is passing Details
2025-01-09 15:47:49 +08:00
he 53e96811ce 修改
continuous-integration/drone/push Build is running Details
2025-01-09 15:46:27 +08:00
he 7b52c0b785 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 Details
2025-01-09 15:34:54 +08:00
he 9362d29fae 添加重复验证 2025-01-09 15:34:53 +08:00
hang 212268cfa5 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 Details
2025-01-09 15:23:31 +08:00
hang 862da87a0c 修改用户日志 2025-01-09 15:23:28 +08:00
he 0dae3c000c 首次添加病灶
continuous-integration/drone/push Build is passing Details
2025-01-09 15:06:54 +08:00
he 55ea791387 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 Details
2025-01-09 15:05:11 +08:00
he 3a62189503 稽查修改 2025-01-09 15:05:10 +08:00
hang d3396d9683 修改导表错位
continuous-integration/drone/push Build is passing Details
2025-01-09 13:59:23 +08:00
hang 7672c9ab85 修改导表
continuous-integration/drone/push Build is passing Details
2025-01-09 13:19:18 +08:00
he afbc43b83f 修改
continuous-integration/drone/push Build is passing Details
2025-01-09 11:22:53 +08:00
he 4613f98154 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 Details
2025-01-09 11:11:33 +08:00
he 52f34d70b7 提交 2025-01-09 11:11:33 +08:00
hang 02d378e0e6 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 Details
2025-01-09 11:06:47 +08:00
hang c29bb8e1a3 发布版本 2025-01-09 11:06:46 +08:00
he 1eaa56bb2a 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 Details
2025-01-09 11:01:28 +08:00
he 54cdd14889 稽查修改 2025-01-09 11:01:26 +08:00
hang 01c253952b 修改医生bug
continuous-integration/drone/push Build is passing Details
2025-01-09 09:47:28 +08:00
hang 060be72143 打出日志
continuous-integration/drone/push Build is passing Details
2025-01-09 09:41:34 +08:00
hang f5032b95ce 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 Details
2025-01-09 09:27:35 +08:00
hang 8fce9f4bf2 修改阅片人 产生用户名 2025-01-09 09:27:34 +08:00
he 857e7c5523 修改
continuous-integration/drone/push Build is passing Details
2025-01-08 17:49:40 +08:00
he 67dbf7c701 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 Details
2025-01-08 17:09:18 +08:00
he 17fd46c2dc 计算修改 2025-01-08 17:09:17 +08:00
hang 75b3a60ca6 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 Details
2025-01-08 16:09:54 +08:00
hang f499a9b803 修改培训导表 2025-01-08 16:09:52 +08:00
he c87c724685 修改计算
continuous-integration/drone/push Build is passing Details
2025-01-08 16:02:45 +08:00
he 36ea9f526e 修改
continuous-integration/drone/push Build is passing Details
2025-01-08 14:43:10 +08:00
he e5bf8c4c8c 修改
continuous-integration/drone/push Build is passing Details
2025-01-08 13:49:28 +08:00
he 60a5cc4602 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 Details
2025-01-08 13:39:41 +08:00
he c376fe1d22 计算修改 2025-01-08 13:39:39 +08:00
hang 8111b60d4f 修改参与人员导表
continuous-integration/drone/push Build is passing Details
2025-01-08 13:22:24 +08:00
hang 86c871bc9f 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 Details
2025-01-08 11:32:25 +08:00
hang a21cca53f8 修改文档返回状态 2025-01-08 11:32:24 +08:00
he 4a03467968 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 Details
2025-01-08 10:48:37 +08:00
he f6151b7ce1 计算修改 2025-01-08 10:48:37 +08:00
hang cbfc2f9538 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 Details
2025-01-08 10:37:06 +08:00
hang 35ca08ee04 CMM SMM 阅片人筛选 2025-01-08 10:37:04 +08:00
he 0781496c69 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 Details
2025-01-08 10:36:47 +08:00
he 0cca369eaa 修改 2025-01-08 10:36:46 +08:00
hang 62fafeb7d2 添加用户 重新发送邮件
continuous-integration/drone/push Build is passing Details
2025-01-08 09:50:25 +08:00
hang f513829c94 修改统计数字
continuous-integration/drone/push Build is passing Details
2025-01-07 18:04:14 +08:00
hang bbb3a41293 中心人员添加
continuous-integration/drone/push Build is passing Details
2025-01-07 15:26:30 +08:00
hang e966779cc8 修改中心调研发现的bug
continuous-integration/drone/push Build is passing Details
2025-01-07 14:25:50 +08:00
hang bcc576dfd1 修改映射
continuous-integration/drone/push Build is passing Details
2025-01-07 11:40:26 +08:00
hang dac9453048 修改查询
continuous-integration/drone/push Build is passing Details
2025-01-07 11:31:31 +08:00
hang faf5430248 修改返回真实名字
continuous-integration/drone/push Build is passing Details
2025-01-07 10:51:52 +08:00
hang 561e1748d6 修改部位
continuous-integration/drone/push Build is running Details
2025-01-07 10:49:40 +08:00
hang 83749e15cb CDISC_Reading_Export
continuous-integration/drone/push Build is passing Details
2025-01-07 10:34:19 +08:00
hang 1a64c07c8e 导表准备
continuous-integration/drone/push Build is passing Details
2025-01-06 17:58:17 +08:00
hang 6ead8ffd53 修改配置临时提交
continuous-integration/drone/push Build is passing Details
2025-01-06 17:29:53 +08:00
hang 1676516441 修改返回的配置
continuous-integration/drone/push Build is passing Details
2025-01-06 16:41:33 +08:00
hang c97186a557 修改废除文档签署数字
continuous-integration/drone/push Build is passing Details
2025-01-06 16:05:02 +08:00
he 59f88175b4 修改枚举
continuous-integration/drone/push Build is passing Details
2025-01-06 15:40:07 +08:00
he 77b45e80fe 合并
continuous-integration/drone/push Build is passing Details
2025-01-06 15:17:55 +08:00
he 2b9272c495 修改 2025-01-06 14:28:23 +08:00
hang 5dae08d9c0 修改列表过滤
continuous-integration/drone/push Build is passing Details
2025-01-06 13:59:04 +08:00
hang 653533020f 修改文档签署
continuous-integration/drone/push Build is passing Details
2025-01-06 13:23:49 +08:00
hang 5a12879182 修改签名
continuous-integration/drone/push Build is passing Details
2025-01-06 13:14:38 +08:00
hang 8132f9a2ea x
continuous-integration/drone/push Build is passing Details
2025-01-06 13:07:33 +08:00
hang 293865fc3f 修改稽查
continuous-integration/drone/push Build is passing Details
2025-01-06 11:41:54 +08:00
hang cfbe3d2589 检查部位智能处理
continuous-integration/drone/push Build is passing Details
2025-01-06 10:05:10 +08:00
hang 69151bbddb 修改查询
continuous-integration/drone/push Build is passing Details
2025-01-03 17:58:33 +08:00
hang 5faf1a5442 修改筛选忽略过滤器
continuous-integration/drone/push Build is passing Details
2025-01-03 17:42:19 +08:00
hang 25648a8a69 修改启用禁用查询
continuous-integration/drone/push Build is passing Details
2025-01-03 17:16:13 +08:00
hang 522d619ee8 xx
continuous-integration/drone/push Build is passing Details
2025-01-03 16:56:58 +08:00
hang 4a901085d8 x
continuous-integration/drone/push Build is passing Details
2025-01-03 16:49:40 +08:00
hang 49d60f6f68 修改测试
continuous-integration/drone/push Build is running Details
2025-01-03 16:47:27 +08:00
hang 73b8cfe723 修改系统角色状态
continuous-integration/drone/push Build is passing Details
2025-01-03 16:34:43 +08:00
hang 05a4de1464 项目参与用户修改
continuous-integration/drone/push Build is passing Details
2025-01-03 16:29:11 +08:00
hang 9002d850a5 遗漏了else
continuous-integration/drone/push Build is passing Details
2025-01-03 15:22:18 +08:00
hang 23cfe72d40 裁判未分配导致没有被影响到bug 修复测试
continuous-integration/drone/push Build is passing Details
2025-01-03 15:16:39 +08:00
hang 8303f9faae spm 逻辑修改
continuous-integration/drone/push Build is passing Details
2025-01-03 15:09:56 +08:00
hang 517c799e00 设置重阅
continuous-integration/drone/push Build is passing Details
2025-01-03 14:30:01 +08:00
hang 69f5b54919 修改SPM 逻辑
continuous-integration/drone/push Build is passing Details
2025-01-03 13:38:28 +08:00
hang 5c0d30d2bc 修改文档签署
continuous-integration/drone/push Build is passing Details
2025-01-03 13:32:49 +08:00
hang c62086f8e8 撤回修改
continuous-integration/drone/push Build is passing Details
2025-01-03 13:20:22 +08:00
hang 2dfcedfe3c 修改签署文档
continuous-integration/drone/push Build is passing Details
2025-01-03 13:17:49 +08:00
hang 77180ea7ba xx
continuous-integration/drone/push Build is passing Details
2025-01-03 11:50:25 +08:00
hang 8656ed09bb 修改PM 申审批
continuous-integration/drone/push Build is passing Details
2025-01-03 10:52:34 +08:00
hang 7cdfce354c xx
continuous-integration/drone/push Build is passing Details
2025-01-03 10:29:05 +08:00
hang 2ac7af44b9 修改mfa 登录
continuous-integration/drone/push Build is running Details
2025-01-03 10:27:12 +08:00
hang a0b18bbf72 修改登录mfa
continuous-integration/drone/push Build is passing Details
2025-01-03 09:50:18 +08:00
hang 6713a9c8e2 修改mfa 验证
continuous-integration/drone/push Build is passing Details
2025-01-03 09:38:24 +08:00
hang ecfc603dda 修改mfa 登录
continuous-integration/drone/push Build is passing Details
2025-01-03 09:34:59 +08:00
hang 55db1a2eab 修改发送邮件人员判断
continuous-integration/drone/push Build is passing Details
2025-01-02 17:33:42 +08:00
hang f117fbb571 邮件发送
continuous-integration/drone/push Build is passing Details
2025-01-02 17:20:13 +08:00
he 5a1687b45f 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 Details
2025-01-02 16:58:51 +08:00
he d31e560a6b 接口名称修改 2025-01-02 16:58:50 +08:00
hang de4bf6951f 管理员重置密码修改
continuous-integration/drone/push Build is running Details
2025-01-02 16:55:01 +08:00
hang f034d9ca87 MFA 登录修改
continuous-integration/drone/push Build is running Details
2025-01-02 16:53:54 +08:00
hang f62e849f80 忘记密码记录日志
continuous-integration/drone/push Build is passing Details
2025-01-02 16:47:13 +08:00
hang 055537ddbb 修改账号禁用日志
continuous-integration/drone/push Build is passing Details
2025-01-02 16:28:24 +08:00
hang 13efa0f1d3 修改创建账号日志
continuous-integration/drone/push Build is passing Details
2025-01-02 16:17:09 +08:00
he 901438a4a7 修改
continuous-integration/drone/push Build is passing Details
2025-01-02 15:37:34 +08:00
he 7b26af01b1 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 Details
2025-01-02 15:32:08 +08:00
he de0534c3a1 代码修改 2025-01-02 15:32:07 +08:00
hang 1f490138a0 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 Details
2025-01-02 15:23:52 +08:00
hang ed3d0421db 增加信息验证 2025-01-02 15:23:49 +08:00
he b83e42d788 代码导出配置修改
continuous-integration/drone/push Build is passing Details
2025-01-02 15:06:09 +08:00
he 141fbc2e75 代码修改
continuous-integration/drone/push Build is running Details
2025-01-02 15:03:26 +08:00
he 2e7cbbb8b0 修改
continuous-integration/drone/push Build is passing Details
2025-01-02 14:41:09 +08:00
he 461a59b678 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 Details
2025-01-02 14:18:15 +08:00
he 774680ced0 代码修改 2025-01-02 14:18:13 +08:00
hang 8a26c42857 修改批量增加到中心
continuous-integration/drone/push Build is passing Details
2025-01-02 13:20:55 +08:00
hang 25a91904b8 加人软删除逻辑有问题
continuous-integration/drone/push Build is passing Details
2025-01-02 13:09:21 +08:00
hang 1fa94b95f0 修改用户类型展示
continuous-integration/drone/push Build is passing Details
2025-01-02 11:26:18 +08:00
hang 52efdc28e4 修改映射
continuous-integration/drone/push Build is passing Details
2025-01-02 11:19:17 +08:00
hang 678599f218 修改创建角色设置id
continuous-integration/drone/push Build is passing Details
2025-01-02 10:48:07 +08:00
hang ba49164db6 修改登录中心调研表
continuous-integration/drone/push Build is passing Details
2024-12-31 17:49:45 +08:00
hang 6089fef0a8 修改邮件内容 首次登录区分用户名
continuous-integration/drone/push Build is passing Details
2024-12-31 17:27:44 +08:00
hang 8b3dd419b7 修改筛选用户角色启用
continuous-integration/drone/push Build is passing Details
2024-12-31 16:49:17 +08:00
hang 86236e865e 外部人员bug
continuous-integration/drone/push Build is passing Details
2024-12-31 16:44:31 +08:00
hang e696873025 修改状态
continuous-integration/drone/push Build is passing Details
2024-12-31 15:50:41 +08:00
hang e4c602095f 修改bug
continuous-integration/drone/push Build is passing Details
2024-12-31 15:44:09 +08:00
hang be1f8dfad9 记录日志
continuous-integration/drone/push Build is passing Details
2024-12-31 14:00:07 +08:00
hang 9571775343 修改启用项目参与人员的状态
continuous-integration/drone/push Build is passing Details
2024-12-31 13:37:22 +08:00
hang 518ed694fb 修改添加人员
continuous-integration/drone/push Build is passing Details
2024-12-31 13:28:14 +08:00
hang bf2b439ce1 修改账号角色禁用
continuous-integration/drone/push Build is passing Details
2024-12-31 13:12:39 +08:00
hang bfed24028a 修改邮件发送
continuous-integration/drone/push Build is passing Details
2024-12-31 11:18:44 +08:00
hang da570f8c5a 修改加入人员逻辑
continuous-integration/drone/push Build is passing Details
2024-12-31 10:41:12 +08:00
hang 99fa476b80 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 Details
2024-12-31 10:35:05 +08:00
hang e0ee9abd61 修改内部人员退出 2024-12-31 10:35:03 +08:00
he 4696951923 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 Details
2024-12-31 10:23:36 +08:00
he ea0209f20d 代码修改 2024-12-31 10:23:36 +08:00
hang 28a56ee298 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 Details
2024-12-31 10:19:26 +08:00
hang 2691da82ae 修改内部人员 查询列表接口 2024-12-31 10:19:25 +08:00
he c5519976ee 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 Details
2024-12-31 10:09:24 +08:00
he bc079d3586 导出修改 2024-12-31 10:09:23 +08:00
hang a8ec762a7d 修改项目参与人员列表
continuous-integration/drone/push Build is passing Details
2024-12-31 10:03:11 +08:00
hang 2b6ae95160 医生生成账号修改
continuous-integration/drone/push Build is passing Details
2024-12-31 09:42:24 +08:00
hang c9c38b5053 用户角色签名修改
continuous-integration/drone/push Build is passing Details
2024-12-31 09:26:05 +08:00
hang f97df34b65 文档列表查询修改
continuous-integration/drone/push Build is passing Details
2024-12-30 21:39:58 +08:00
hang aec6757748 修改查询
continuous-integration/drone/push Build is passing Details
2024-12-30 19:53:02 +08:00
hang 33c27cccc2 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 Details
2024-12-30 18:24:24 +08:00
hang a449013c5d 项目文档修改临时提交 2024-12-30 18:24:21 +08:00
he b0b3744cb1 添加defaultValue
continuous-integration/drone/push Build is passing Details
2024-12-30 16:01:59 +08:00
he b2ba48ea90 修改
continuous-integration/drone/push Build is passing Details
2024-12-30 15:41:47 +08:00
he 8a20051436 修改计算
continuous-integration/drone/push Build is passing Details
2024-12-30 14:53:57 +08:00
he eedfa4b84d 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 Details
2024-12-30 14:24:34 +08:00
he 4403a09e79 修改 2024-12-30 14:24:33 +08:00
hang 12fb19c47c 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 Details
2024-12-30 14:08:11 +08:00
hang 14c62a8852 修改项目参与人员判断 2024-12-30 14:08:08 +08:00
he 2c818b9caa 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 Details
2024-12-30 13:59:56 +08:00
he db8f587e93 修改 2024-12-30 13:59:55 +08:00
hang 260be98cef 修改登录日志查询接口
continuous-integration/drone/push Build is passing Details
2024-12-30 13:26:08 +08:00
hang b42bf4e201 修改日志,以及添加项目参与人员
continuous-integration/drone/push Build is passing Details
2024-12-30 11:36:25 +08:00
hang 2a42a921c4 修改退出
continuous-integration/drone/push Build is passing Details
2024-12-27 15:01:02 +08:00
hang e84b8c25f1 修改项目增加接口
continuous-integration/drone/push Build is passing Details
2024-12-27 14:41:46 +08:00
hang 8b44900931 中心调研初步维护
continuous-integration/drone/push Build is passing Details
2024-12-27 14:29:13 +08:00
hang 918362e854 导入人员发送邮件
continuous-integration/drone/push Build is passing Details
2024-12-27 13:50:26 +08:00
hang ba2965e295 修改外部人员邀请邮件以及添加账号
continuous-integration/drone/push Build is passing Details
2024-12-27 12:33:48 +08:00
hang ecdd0fda85 增加查询条件
continuous-integration/drone/push Build is passing Details
2024-12-27 11:43:35 +08:00
hang dba356446e 登录选择角色
continuous-integration/drone/push Build is passing Details
2024-12-27 11:35:53 +08:00
hang 4e1ea21ba8 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 Details
2024-12-27 11:32:18 +08:00
hang 7853614d2d 修改查询 2024-12-27 11:32:17 +08:00
he 8cabb7440a 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 Details
2024-12-27 09:37:16 +08:00
he 4fc68e1f82 修改排序 2024-12-27 09:37:15 +08:00
hang c06681f379 修改账号编号问题
continuous-integration/drone/push Build is passing Details
2024-12-26 17:59:04 +08:00
hang 57539b0471 用户反馈修改查询条件
continuous-integration/drone/push Build is passing Details
2024-12-26 17:49:39 +08:00
hang 8b7c429e9f 修改日志查询条数有问题
continuous-integration/drone/push Build is passing Details
2024-12-26 17:38:42 +08:00
hang 9b94ad70ee 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 Details
2024-12-26 17:25:03 +08:00
hang 9aa8bb99dc 修改中心人员 2024-12-26 17:25:00 +08:00
he b203c891a4 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 Details
2024-12-26 17:16:25 +08:00
he 3833a1e696 登录修改 2024-12-26 17:16:24 +08:00
hang 6e83891139 修改稽查查询
continuous-integration/drone/push Build is passing Details
2024-12-26 17:10:18 +08:00
hang 39616448b8 添加内部人员修改
continuous-integration/drone/push Build is running Details
2024-12-26 17:07:31 +08:00
hang 6b9feca865 修改日志
continuous-integration/drone/push Build is passing Details
2024-12-26 16:48:20 +08:00
hang e0779ab295 修改用户发邮件
continuous-integration/drone/push Build is passing Details
2024-12-26 16:23:30 +08:00
hang 32e3153434 修改角色禁用bug
continuous-integration/drone/push Build is passing Details
2024-12-26 16:03:51 +08:00
hang b40bfe26c5 修改枚举值
continuous-integration/drone/push Build is passing Details
2024-12-26 15:53:14 +08:00
hang b8d5ed2bb7 修改密码bug
continuous-integration/drone/push Build is passing Details
2024-12-26 15:44:51 +08:00
hang 96e1f84c8c 修改映射
continuous-integration/drone/push Build is running Details
2024-12-26 15:37:48 +08:00
hang 353e03c4fe 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 Details
2024-12-26 15:23:13 +08:00
hang aa60cb4822 修改日志展示 2024-12-26 15:23:12 +08:00
he 7eaa61678b 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 Details
2024-12-26 14:57:25 +08:00
he d74cf15138 修改 2024-12-26 14:57:24 +08:00
hang 6238361bd2 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 Details
2024-12-26 14:54:14 +08:00
hang cf9248b0cc 修改用户日志 2024-12-26 14:54:13 +08:00
he 8c884b3269 删除表格标记
continuous-integration/drone/push Build is passing Details
2024-12-26 14:49:42 +08:00
he 8710edf1bd 修改计算
continuous-integration/drone/push Build is passing Details
2024-12-26 12:23:28 +08:00
he 5f9572a0ab Merge branch 'IRC_NewDev' into Test_IRC_Net8
continuous-integration/drone/push Build is passing Details
2024-12-26 11:12:00 +08:00
hang 21c10307b9 增加修改用户角色接口
continuous-integration/drone/push Build is running Details
2024-12-26 11:10:36 +08:00
hang 6e0dc64981 修改查询映射
continuous-integration/drone/push Build is passing Details
2024-12-26 11:00:34 +08:00
hang 66922f8e7b 修改token 名字
continuous-integration/drone/push Build is passing Details
2024-12-26 09:27:05 +08:00
hang 2aa0382376 医生加入项目修改
continuous-integration/drone/push Build is passing Details
2024-12-25 19:30:42 +08:00
hang 5cdc5400dc 修改医生生成账号
continuous-integration/drone/push Build is passing Details
2024-12-25 19:19:41 +08:00
hang 53bcdaa6ce 增加用户映射
continuous-integration/drone/push Build is passing Details
2024-12-25 17:55:49 +08:00
hang 473e218b2b 增加用户基本信息修改接口
continuous-integration/drone/push Build is passing Details
2024-12-25 17:36:04 +08:00
hang 2eaf2d5c69 修改项目添加参与人员
continuous-integration/drone/push Build is passing Details
2024-12-25 16:19:57 +08:00
hang 25116a9f0e 中心调研邮件初步修改
continuous-integration/drone/push Build is passing Details
2024-12-25 16:02:49 +08:00
hang 7535d49844 导入人员
continuous-integration/drone/push Build is passing Details
2024-12-25 15:43:42 +08:00
hang 340f5c580e 添加用户修改
continuous-integration/drone/push Build is passing Details
2024-12-25 14:53:19 +08:00
hang 1d4eedf5bb 修改映射
continuous-integration/drone/push Build is passing Details
2024-12-25 14:21:16 +08:00
hang 3ff0230fc1 增加更新角色接口
continuous-integration/drone/push Build is passing Details
2024-12-25 14:02:17 +08:00
hang c2166556ea 修改项目用户
continuous-integration/drone/push Build is passing Details
2024-12-25 13:53:38 +08:00
hang 4b938e6643 外部用户修改
continuous-integration/drone/push Build is passing Details
2024-12-25 13:42:05 +08:00
hang 4740e04ff1 修改映射
continuous-integration/drone/push Build is passing Details
2024-12-25 13:29:43 +08:00
hang ccdad2f4fd 修改中心命名提交
continuous-integration/drone/push Build is passing Details
2024-12-25 13:18:40 +08:00
hang 54d17f2e24 项目中心修改
continuous-integration/drone/push Build is passing Details
2024-12-25 13:07:57 +08:00
hang 0b3fe111b7 项目中心人员修改
continuous-integration/drone/push Build is passing Details
2024-12-25 12:27:48 +08:00
hang a6080b76b1 修改用户临时提交
continuous-integration/drone/push Build is passing Details
2024-12-25 11:25:45 +08:00
hang 26cba15742 项目用户表增加初步修改
continuous-integration/drone/push Build is passing Details
2024-12-25 10:20:17 +08:00
hang 32c6d745b6 用户角色重命名初步修改
continuous-integration/drone/push Build is passing Details
2024-12-25 09:31:36 +08:00
hang 76649f264b 重置密码修改
continuous-integration/drone/push Build is passing Details
2024-12-24 17:39:44 +08:00
hang db360938fd 修改用户重置密码
continuous-integration/drone/push Build is passing Details
2024-12-24 17:32:45 +08:00
hang bd82470995 列表增加时间
continuous-integration/drone/push Build is passing Details
2024-12-24 17:26:08 +08:00
hang 87560e0602 修改用户编辑
continuous-integration/drone/push Build is passing Details
2024-12-24 17:16:14 +08:00
hang 89cd31cd03 修改提交
continuous-integration/drone/push Build is passing Details
2024-12-24 17:06:42 +08:00
hang 1badf2610e 账号管理提交
continuous-integration/drone/push Build is passing Details
2024-12-24 17:00:56 +08:00
hang 1129a2210a 修改映射
continuous-integration/drone/push Build is passing Details
2024-12-24 16:49:19 +08:00
hang a1199b44a3 修改提交
continuous-integration/drone/push Build is passing Details
2024-12-24 16:36:54 +08:00
hang dc32df27ec 添加新的用户表提交
continuous-integration/drone/push Build is pending Details
2024-12-24 16:25:04 +08:00
hang f7519b2095 修改账户信息
continuous-integration/drone/push Build is passing Details
2024-12-23 18:06:26 +08:00
hang 686c7bac9b 修改账户信息
continuous-integration/drone/push Build is passing Details
2024-12-23 17:49:25 +08:00
hang 230852b2a9 修改获取账户信息
continuous-integration/drone/push Build is passing Details
2024-12-23 17:41:03 +08:00
hang 613957d0ac 修改传递参数
continuous-integration/drone/push Build is passing Details
2024-12-23 17:25:18 +08:00
hang 4fe61ac51a 修改传参方式
continuous-integration/drone/push Build is passing Details
2024-12-23 17:01:54 +08:00
hang e9bafe9e38 返回用户简称
continuous-integration/drone/push Build is passing Details
2024-12-23 16:45:53 +08:00
hang d1bf517aa7 修改传递的参数
continuous-integration/drone/push Build is passing Details
2024-12-23 16:34:32 +08:00
hang a2809dc15a 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 Details
2024-12-23 15:47:41 +08:00
hang c1a58401eb 用户初步修改 2024-12-23 15:47:39 +08:00
he e0cf5f804e 修改
continuous-integration/drone/push Build is passing Details
2024-12-20 17:48:28 +08:00
he a0725e1318 修改
continuous-integration/drone/push Build is passing Details
2024-12-20 17:25:55 +08:00
he 70b7fe73ad 修改
continuous-integration/drone/push Build is passing Details
2024-12-20 17:16:30 +08:00
he 5b616026ab 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 Details
2024-12-20 17:10:51 +08:00
hang 2e7a0fe68d 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 Details
2024-12-20 14:54:15 +08:00
hang 519eeb6df1 修改账号token 2024-12-20 14:54:11 +08:00
hang 496396fa6b 删除返回的机构名称
continuous-integration/drone/push Build is passing Details
2024-12-18 13:36:52 +08:00
hang 3b28e13fd8 修改时间展示
continuous-integration/drone/push Build is passing Details
2024-12-18 11:33:21 +08:00
hang b12877e39b 修改时间
continuous-integration/drone/push Build is passing Details
2024-12-18 11:16:05 +08:00
657 changed files with 1539506 additions and 727076 deletions

View File

@ -0,0 +1,37 @@
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Localization;
using Newtonsoft.Json;
namespace IRaCIS.Core.SCP.Filter
{
public class ModelActionFilter : ActionFilterAttribute, IActionFilter
{
public IStringLocalizer _localizer;
public ModelActionFilter(IStringLocalizer localizer)
{
_localizer = localizer;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
var validationErrors = context.ModelState
.Keys
.SelectMany(k => context.ModelState[k]!.Errors)
.Select(e => e.ErrorMessage)
.ToArray();
//---提供给接口的参数无效。
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["ModelAction_InvalidAPIParameter"] + JsonConvert.SerializeObject( validationErrors)));
}
}
}
}

View File

@ -0,0 +1,61 @@
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
namespace IRaCIS.Core.SCP.Filter
{
public class ProjectExceptionFilter : Attribute, IExceptionFilter
{
private readonly ILogger<ProjectExceptionFilter> _logger;
public IStringLocalizer _localizer;
public ProjectExceptionFilter(IStringLocalizer localizer, ILogger<ProjectExceptionFilter> logger)
{
_logger = logger;
_localizer = localizer;
}
public void OnException(ExceptionContext context)
{
//context.ExceptionHandled;//记录当前这个异常是否已经被处理过了
if (!context.ExceptionHandled)
{
if (context.Exception.GetType().Name == "DbUpdateConcurrencyException")
{
//---并发更新,当前不允许该操作
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["ProjectException_ConcurrentUpdateNotAllowed"] + context.Exception.Message));
}
if (context.Exception.GetType() == typeof(BusinessValidationFailedException))
{
var error = context.Exception as BusinessValidationFailedException;
context.Result = new JsonResult(ResponseOutput.NotOk(context.Exception.Message, error!.Code));
}
else if(context.Exception.GetType() == typeof(QueryBusinessObjectNotExistException))
{
context.Result = new JsonResult(ResponseOutput.NotOk( context.Exception.Message, ApiResponseCodeEnum.DataNotExist));
}
else
{
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["Project_ExceptionContactDeveloper"] + (context.Exception.InnerException is null ? (context.Exception.Message /*+ context.Exception.StackTrace*/)
: (context.Exception.InnerException?.Message /*+ context.Exception.InnerException?.StackTrace*/)), ApiResponseCodeEnum.ProgramException));
}
_logger.LogError(context.Exception.InnerException is null ? (context.Exception.Message + context.Exception.StackTrace) : (context.Exception.InnerException?.Message + context.Exception.InnerException?.StackTrace));
}
else
{
//继续
}
context.ExceptionHandled = true;//标记当前异常已经被处理过了
}
}
}

View File

@ -0,0 +1,120 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Core.Application.Service.BusinessFilter
{
/// <summary>
/// 统一返回前端数据包装之前在控制器包装现在修改为动态Api 在ResultFilter这里包装减少重复冗余代码
/// by zhouhang 2021.09.12 周末
/// </summary>
public class UnifiedApiResultFilter : Attribute, IAsyncResultFilter
{
/// <summary>
/// 异步版本
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
if (context.Result is ObjectResult objectResult)
{
var statusCode = objectResult.StatusCode ?? context.HttpContext.Response.StatusCode;
//是200 并且没有包装 那么包装结果
if (statusCode == 200 && !(objectResult.Value is IResponseOutput))
{
//if (objectResult.Value == null)
//{
// var apiResponse = ResponseOutput.DBNotExist();
// objectResult.Value = apiResponse;
// objectResult.DeclaredType = apiResponse.GetType();
//}
//else
//{
var type = objectResult.Value?.GetType();
if ( type!=null&& type.IsGenericType&&(type.GetGenericTypeDefinition()==typeof(ValueTuple<,>)|| type.GetGenericTypeDefinition()==typeof(Tuple<,>)))
{
//报错
//var tuple = (object, object))objectResult.Value;
//var (val1, val2) = ((dynamic, dynamic))objectResult.Value;
//var apiResponse = ResponseOutput.Ok(val1, val2);
//OK
var tuple = (dynamic)objectResult.Value;
var apiResponse = ResponseOutput.Ok(tuple.Item1, tuple.Item2);
objectResult.Value = apiResponse;
objectResult.DeclaredType = apiResponse.GetType();
}
else
{
var apiResponse = ResponseOutput.Ok(objectResult.Value);
objectResult.Value = apiResponse;
objectResult.DeclaredType = apiResponse.GetType();
}
//}
}
//如果不是200 是IResponseOutput 不处理
else if (statusCode != 200 && (objectResult.Value is IResponseOutput))
{
}
else if(statusCode != 200&&!(objectResult.Value is IResponseOutput))
{
//---程序错误,请联系开发人员。
var apiResponse = ResponseOutput.NotOk(I18n.T("UnifiedAPI_ProgramError"));
objectResult.Value = apiResponse;
objectResult.DeclaredType = apiResponse.GetType();
}
}
await next.Invoke();
}
public static bool IsTupleType(Type type, bool checkBaseTypes = false)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
if (type == typeof(Tuple))
return true;
while (type != null)
{
if (type.IsGenericType)
{
var genType = type.GetGenericTypeDefinition();
if (genType == typeof(Tuple<>)
|| genType == typeof(Tuple<,>)
|| genType == typeof(Tuple<,>))
return true;
}
if (!checkBaseTypes)
break;
type = type.BaseType;
}
return false;
}
}
}

View File

@ -0,0 +1,57 @@
using Autofac;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Http;
using Panda.DynamicWebApi;
using System;
using System.Linq;
using System.Reflection;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Application.Service;
using AutoMapper;
using IRaCIS.Core.SCP.Service;
namespace IRaCIS.Core.SCP
{
// ReSharper disable once IdentifierTypo
public class AutofacModuleSetup : Autofac.Module
{
protected override void Load(ContainerBuilder containerBuilder)
{
#region byzhouhang 20210917 此处注册泛型仓储 可以减少Domain层 和Infra.EFcore 两层 空的仓储接口定义和 仓储文件定义
containerBuilder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepository<>)).InstancePerLifetimeScope();//注册泛型仓储
containerBuilder.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
#endregion
#region 指定控制器也由autofac 来进行实例获取 https://www.cnblogs.com/xwhqwer/p/15320838.html
//获取所有控制器类型并使用属性注入
containerBuilder.RegisterAssemblyTypes(typeof(BaseService).Assembly)
.Where(type => typeof(IDynamicWebApi).IsAssignableFrom(type))
.PropertiesAutowired();
#endregion
Assembly application = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + typeof(BaseService).Assembly.GetName().Name+".dll");
containerBuilder.RegisterAssemblyTypes(application).Where(t => t.FullName.Contains("Service"))
.PropertiesAutowired().AsImplementedInterfaces();
//containerBuilder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
//containerBuilder.RegisterType<UserInfo>().As<IUserInfo>().InstancePerLifetimeScope();
}
}
}

View File

@ -0,0 +1,64 @@
using EntityFramework.Exceptions.SqlServer;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore;
using Medallion.Threading;
using Medallion.Threading.SqlServer;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace IRaCIS.Core.SCP
{
public static class EFSetup
{
public static void AddEFSetup( this IServiceCollection services, IConfiguration configuration)
{
services.AddHttpContextAccessor();
services.AddScoped<IUserInfo, UserInfo>();
services.AddScoped<ISaveChangesInterceptor, AuditEntityInterceptor>();
//这个注入没有成功--注入是没问题的构造函数也只是支持参数就好错在注入的地方不能写DbContext
//Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量 这在概念上类似于ADO.NET Provider原生的连接池操作方式具有节省DbContext实例化成本的优点
services.AddDbContext<IRaCISDBContext>((sp, options) =>
{
// 在控制台
//public static readonly ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });
var logFactory = LoggerFactory.Create(builder => { builder.AddDebug(); });
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value,
contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
options.UseLoggerFactory(logFactory);
options.UseExceptionProcessor();
options.EnableSensitiveDataLogging();
options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor());
options.AddInterceptors(sp.GetServices<ISaveChangesInterceptor>());
options.UseProjectables();
});
//// Register an additional context factory as a Scoped service, which gets a pooled context from the Singleton factory we registered above,
//services.AddScoped<IRaCISDBScopedFactory>();
//// Finally, arrange for a context to get injected from our Scoped factory:
//services.AddScoped(sp => sp.GetRequiredService<IRaCISDBScopedFactory>().CreateDbContext());
//注意区分 easy caching 也有 IDistributedLockProvider
services.AddSingleton<IDistributedLockProvider>(sp =>
{
//var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!);
return new SqlDistributedSynchronizationProvider(configuration.GetSection("ConnectionStrings:RemoteNew").Value);
});
}
}
}

View File

@ -0,0 +1,59 @@

using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
namespace IRaCIS.Core.SCP
{
public static class NewtonsoftJsonSetup
{
public static void AddNewtonsoftJsonSetup(this IMvcBuilder builder, IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddScoped<IOSSService,OSSService>();
builder.AddNewtonsoftJson(options =>
{
//options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
// 忽略循环引用
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
//options.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
//处理返回给前端 可空类型 给出默认值 比如in? 为null 设置 默认值0
options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver(); //new DefaultContractResolver();// new NullToEmptyStringResolver();
// 设置时间格式
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
//options.SerializerSettings.Converters.Add(new JSONCustomDateConverter()) ;
//options.SerializerSettings.Converters.Add(services.BuildServiceProvider().GetService<JSONTimeZoneConverter>());
})
.AddControllersAsServices()//动态webApi属性注入需要
.ConfigureApiBehaviorOptions(o =>
{
o.SuppressModelStateInvalidFilter = true; //自己写验证
});
Newtonsoft.Json.JsonSerializerSettings setting = new Newtonsoft.Json.JsonSerializerSettings();
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
setting.DateFormatString = "yyyy-MM-dd HH:mm:ss";
setting.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
return setting;
});
}
}
}

View File

@ -0,0 +1,36 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
namespace IRaCIS.Core.SCP
{
public class NullToEmptyStringResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
var list= type.GetProperties()
.Select(p =>
{
var jp = base.CreateProperty(p, memberSerialization);
jp.ValueProvider = new NullToEmptyStringValueProvider(p);
return jp;
}).ToList();
var uu = list.Select(t => t.PropertyName).ToList();
//获取复杂对象属性
properties = properties.TakeWhile(t => !uu.Contains(t.PropertyName)).ToList();
list.AddRange(properties);
return list;
}
}
}

View File

@ -0,0 +1,42 @@
using System;
using System.Reflection;
using Newtonsoft.Json.Serialization;
namespace IRaCIS.Core.SCP
{
public class NullToEmptyStringValueProvider : IValueProvider
{
PropertyInfo _MemberInfo;
public NullToEmptyStringValueProvider(PropertyInfo memberInfo)
{
_MemberInfo = memberInfo;
}
public object GetValue(object target)
{
object result = _MemberInfo.GetValue(target);
if (_MemberInfo.PropertyType == typeof(string) && result == null) result = "";
else if (_MemberInfo.PropertyType == typeof(String[]) && result == null) result = new string[] { };
//else if (_MemberInfo.PropertyType == typeof(Nullable<Int32>) && result == null) result = 0;
else if (_MemberInfo.PropertyType == typeof(Nullable<Decimal>) && result == null) result = 0.00M;
return result;
}
public void SetValue(object target, object value)
{
if(_MemberInfo.PropertyType == typeof(string))
{
//去掉前后空格
_MemberInfo.SetValue(target, value==null?string.Empty: value.ToString()==string.Empty? value:value.ToString().Trim());
}
else
{
_MemberInfo.SetValue(target, value);
}
}
}
}

View File

@ -0,0 +1,45 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.11" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.5" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageReference Include="AWSSDK.S3" Version="3.7.416.8" />
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.401.81" />
<PackageReference Include="DistributedLock.Core" Version="1.0.8" />
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
<PackageReference Include="fo-dicom" Version="5.2.1" />
<PackageReference Include="fo-dicom.Codecs" Version="5.16.1" />
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Minio" Version="6.0.4" />
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.1.2" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj" />
<ProjectReference Include="..\IRaCIS.Core.Infrastructure\IRaCIS.Core.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Helper\" />
</ItemGroup>
</Project>

186
IRC.Core.Dicom/Program.cs Normal file
View File

@ -0,0 +1,186 @@
using Autofac;
using Autofac.Extensions.DependencyInjection;
using AutoMapper.EquivalencyExpression;
using FellowOakDicom;
using FellowOakDicom.Imaging;
using FellowOakDicom.Imaging.NativeCodec;
using FellowOakDicom.Network;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.SCP;
using IRaCIS.Core.SCP.Filter;
using IRaCIS.Core.SCP.Service;
using MassTransit;
using MassTransit.NewIdProviders;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection;
using Panda.DynamicWebApi;
using Serilog;
using Serilog.Events;
using System.Runtime.InteropServices;
//以配置文件为准,否则 从url中取环境值(服务以命令行传递参数启动,配置文件配置了就不需要传递环境参数)
var config = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build();
var enviromentName = config["ASPNETCORE_ENVIRONMENT"];
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
EnvironmentName = enviromentName
});
#region 主机配置
NewId.SetProcessIdProvider(new CurrentProcessIdProvider());
builder.Configuration.AddJsonFile("appsettings.json", false, true)
.AddJsonFile($"appsettings.{enviromentName}.json", false, true);
builder.Host
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
containerBuilder.RegisterModule<AutofacModuleSetup>();
})
.UseSerilog();
#endregion
#region 配置服务
var _configuration = builder.Configuration;
//健康检查
builder.Services.AddHealthChecks();
//本地化
builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resources");
// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
builder.Services.AddControllers(options =>
{
options.Filters.Add<ModelActionFilter>();
options.Filters.Add<ProjectExceptionFilter>();
options.Filters.Add<UnitOfWorkFilter>();
})
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
builder.Services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
builder.Services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
builder.Services.AddOptions().Configure<DicomSCPServiceOption>(_configuration.GetSection("DicomSCPServiceConfig"));
//动态WebApi + UnifiedApiResultFilter 省掉控制器代码
//动态webApi 目前存在的唯一小坑是生成api上服务上的动态代理AOP失效 间接掉用不影响
builder.Services
.AddDynamicWebApi(dynamicWebApiOption =>
{
//默认是 api
dynamicWebApiOption.DefaultApiPrefix = "";
//首字母小写
dynamicWebApiOption.GetRestFulActionName = (actionName) => char.ToLower(actionName[0]) + actionName.Substring(1);
//删除 Service后缀
dynamicWebApiOption.RemoveControllerPostfixes.Add("Service");
});
//AutoMapper
builder.Services.AddAutoMapper(automapper =>
{
automapper.AddCollectionMappers();
}, typeof(BaseService).Assembly);
//EF ORM QueryWithNoLock
builder.Services.AddEFSetup(_configuration);
builder.Services.AddMediator(cfg =>
{
});
//转发头设置 获取真实IP
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
builder.Services.AddFellowOakDicom().AddTranscoderManager<NativeTranscoderManager>()
//.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
.AddImageManager<ImageSharpImageManager>();
#endregion
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
//if (app.Environment.IsDevelopment())
//{
app.UseSwagger();
app.UseSwaggerUI();
//}
app.UseAuthorization();
app.MapControllers();
#region 日志
Log.Logger = new LoggerConfiguration()
//.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.WriteTo.Console()
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day)
.CreateLogger();
#endregion
#region 运行环境 部署平台
Log.Logger.Warning($"当前环境:{enviromentName}");
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Log.Logger.Warning($"当前部署平台环境windows");
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Log.Logger.Warning($"当前部署平台环境linux");
}
else
{
Log.Logger.Warning($"当前部署平台环境OSX or FreeBSD");
}
#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);
app.Run();

View File

@ -0,0 +1,31 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:11224",
"sslPort": 0
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5127",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,111 @@
using AutoMapper;
using IRaCIS.Core.Application.Service.BusinessFilter;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Localization;
using Panda.DynamicWebApi;
using Panda.DynamicWebApi.Attributes;
using System.Diagnostics.CodeAnalysis;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure.Extention;
using IRaCIS.Core.Domain.Models;
namespace IRaCIS.Core.SCP.Service
{
#pragma warning disable CS8618
#region 非泛型版本
[Authorize, DynamicWebApi, UnifiedApiResultFilter]
public class BaseService : IBaseService, IDynamicWebApi
{
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
public IStringLocalizer _localizer { get; set; }
public IWebHostEnvironment _hostEnvironment { get; set; }
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
{
return new ResponseOutput<string>()
.NotOk($"The query object {typeof(TEntity).Name} does not exist , or was deleted by someone else, or an incorrect parameter query caused", code: ApiResponseCodeEnum.DataNotExist);
}
}
public interface IBaseService
{
[MemberNotNull(nameof(_mapper))]
public IMapper _mapper { get; set; }
[MemberNotNull(nameof(_userInfo))]
public IUserInfo _userInfo { get; set; }
[MemberNotNull(nameof(_localizer))]
public IStringLocalizer _localizer { get; set; }
[MemberNotNull(nameof(_hostEnvironment))]
public IWebHostEnvironment _hostEnvironment { get; set; }
}
#endregion
#region 泛型版本测试
public interface IBaseServiceTest<T> where T : Entity
{
[MemberNotNull(nameof(_mapper))]
public IMapper _mapper { get; set; }
[MemberNotNull(nameof(_userInfo))]
public IUserInfo _userInfo { get; set; }
[MemberNotNull(nameof(_localizer))]
public IStringLocalizer _localizer { get; set; }
}
[Authorize, DynamicWebApi, UnifiedApiResultFilter]
public class BaseServiceTest<T> : IBaseServiceTest<T>, IDynamicWebApi where T : Entity
{
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
public IStringLocalizer _localizer { get; set; }
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
{
return new ResponseOutput<string>()
.NotOk($"The query object {typeof(TEntity).Name} does not exist , or was deleted by someone else, or an incorrect parameter query caused", code: ApiResponseCodeEnum.DataNotExist);
}
}
#endregion
}

View File

@ -0,0 +1,376 @@
using FellowOakDicom.Network;
using FellowOakDicom;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using IRaCIS.Core.SCP.Service;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infra.EFCore;
using Medallion.Threading;
using IRaCIS.Core.Domain.Share;
using Serilog;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
using Microsoft.Extensions.Options;
using System.Data;
using FellowOakDicom.Imaging;
using SharpCompress.Common;
using SixLabors.ImageSharp.Formats.Jpeg;
using IRaCIS.Core.Infrastructure;
namespace IRaCIS.Core.SCP.Service
{
public class DicomSCPServiceOption
{
public List<string> CalledAEList { get; set; }
public string ServerPort { get; set; }
}
public class CStoreSCPService : DicomService, IDicomServiceProvider, IDicomCStoreProvider, IDicomCEchoProvider
{
private IServiceProvider _serviceProvider { get; set; }
private List<Guid> _SCPStudyIdList { get; set; } = new List<Guid>();
private SCPImageUpload _upload { get; set; }
private Guid _trialId { get; set; }
private Guid _trialSiteId { get; set; }
private static readonly DicomTransferSyntax[] _acceptedTransferSyntaxes = new DicomTransferSyntax[]
{
DicomTransferSyntax.ExplicitVRLittleEndian,
DicomTransferSyntax.ExplicitVRBigEndian,
DicomTransferSyntax.ImplicitVRLittleEndian
};
private static readonly DicomTransferSyntax[] _acceptedImageTransferSyntaxes = new DicomTransferSyntax[]
{
// Lossless
DicomTransferSyntax.JPEGLSLossless, //1.2.840.10008.1.2.4.80
DicomTransferSyntax.JPEG2000Lossless, //1.2.840.10008.1.2.4.90
DicomTransferSyntax.JPEGProcess14SV1, //1.2.840.10008.1.2.4.70
DicomTransferSyntax.JPEGProcess14, //1.2.840.10008.1.2.4.57 JPEG Lossless, Non-Hierarchical (Process 14)
DicomTransferSyntax.RLELossless, //1.2.840.10008.1.2.5
// Lossy
DicomTransferSyntax.JPEGLSNearLossless,//1.2.840.10008.1.2.4.81"
DicomTransferSyntax.JPEG2000Lossy, //1.2.840.10008.1.2.4.91
DicomTransferSyntax.JPEGProcess1, //1.2.840.10008.1.2.4.50
DicomTransferSyntax.JPEGProcess2_4, //1.2.840.10008.1.2.4.51
// Uncompressed
DicomTransferSyntax.ExplicitVRLittleEndian, //1.2.840.10008.1.2.1
DicomTransferSyntax.ExplicitVRBigEndian, //1.2.840.10008.1.2.2
DicomTransferSyntax.ImplicitVRLittleEndian //1.2.840.10008.1.2
};
public CStoreSCPService(INetworkStream stream, Encoding fallbackEncoding, Microsoft.Extensions.Logging.ILogger log, DicomServiceDependencies dependencies, IServiceProvider injectServiceProvider)
: base(stream, fallbackEncoding, log, dependencies)
{
_serviceProvider = injectServiceProvider.CreateScope().ServiceProvider;
}
public Task OnReceiveAssociationRequestAsync(DicomAssociation association)
{
_upload = new SCPImageUpload() { StartTime = DateTime.Now, CallingAE = association.CallingAE, CalledAE = association.CalledAE, CallingAEIP = association.RemoteHost };
Log.Logger.Warning($"接收到来自{association.CallingAE}的连接");
//_serviceProvider = (IServiceProvider)this.UserState;
var _trialDicomAERepository = _serviceProvider.GetService<IRepository<TrialDicomAE>>();
var trialDicomAEList = _trialDicomAERepository.Select(t => new { t.CalledAE, t.TrialId }).ToList();
var trialCalledAEList = trialDicomAEList.Select(t => t.CalledAE).ToList();
Log.Logger.Information("当前系统配置:", string.Join('|', trialDicomAEList));
var findCalledAE = trialDicomAEList.Where(t => t.CalledAE == association.CalledAE).FirstOrDefault();
var isCanReceiveIamge = false;
if (findCalledAE != null)
{
_trialId = findCalledAE.TrialId;
var _trialSiteDicomAERepository = _serviceProvider.GetService<IRepository<TrialSiteDicomAE>>();
var findTrialSiteAE = _trialSiteDicomAERepository.Where(t => t.CallingAE == association.CallingAE && t.TrialId==_trialId).FirstOrDefault();
if (findTrialSiteAE != null)
{
_trialSiteId = findTrialSiteAE.TrialSiteId;
isCanReceiveIamge = true;
}
}
if (association.CallingAE == "test-callingAE")
{
isCanReceiveIamge = true;
}
if (!trialCalledAEList.Contains(association.CalledAE) || isCanReceiveIamge == false)
{
Log.Logger.Warning($"拒绝CallingAE:{association.CallingAE} CalledAE:{association.CalledAE}的连接");
return SendAssociationRejectAsync(
DicomRejectResult.Permanent,
DicomRejectSource.ServiceUser,
DicomRejectReason.CalledAENotRecognized);
}
foreach (var pc in association.PresentationContexts)
{
if (pc.AbstractSyntax == DicomUID.Verification)
{
pc.AcceptTransferSyntaxes(_acceptedTransferSyntaxes);
}
else if (pc.AbstractSyntax.StorageCategory != DicomStorageCategory.None)
{
pc.AcceptTransferSyntaxes(_acceptedImageTransferSyntaxes);
}
}
return SendAssociationAcceptAsync(association);
}
public async Task OnReceiveAssociationReleaseRequestAsync()
{
await DataMaintenanceAsaync();
//记录监控
var _SCPImageUploadRepository = _serviceProvider.GetService<IRepository<SCPImageUpload>>();
_upload.EndTime = DateTime.Now;
_upload.StudyCount = _SCPStudyIdList.Count;
_upload.TrialId = _trialId;
_upload.TrialSiteId = _trialSiteId;
await _SCPImageUploadRepository.AddAsync(_upload, true);
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
//将检查设置为传输结束
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
await SendAssociationReleaseResponseAsync();
}
private async Task DataMaintenanceAsaync()
{
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}传输结束开始维护数据处理检查Modality");
//处理检查Modality
var _dictionaryRepository = _serviceProvider.GetService<IRepository<Dictionary>>();
var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
var dicModalityList = _dictionaryRepository.Where(t => t.Code == "Modality").SelectMany(t => t.ChildList.Select(c => c.Value)).ToList();
var seriesModalityList = _seriesRepository.Where(t => _SCPStudyIdList.Contains(t.StudyId)).Select(t => new { SCPStudyId = t.StudyId, t.Modality }).ToList();
foreach (var g in seriesModalityList.GroupBy(t => t.SCPStudyId))
{
var modality = string.Join('、', g.Select(t => t.Modality).Distinct().ToList());
//特殊逻辑
var modalityForEdit = dicModalityList.Contains(modality) ? modality : String.Empty;
if (modality == "MR")
{
modalityForEdit = "MRI";
}
if (modality == "PT")
{
modalityForEdit = "PET";
}
if (modality == "PT、CT" || modality == "CT、PT")
{
modalityForEdit = "PET-CT";
}
await _studyRepository.BatchUpdateNoTrackingAsync(t => t.Id == g.Key, u => new SCPStudy() { Modalities = modality, ModalityForEdit = modalityForEdit });
}
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}维护数据结束");
}
public void OnReceiveAbort(DicomAbortSource source, DicomAbortReason reason)
{
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}接收中断,中断原因:{source.ToString() + reason.ToString()}");
/* nothing to do here */
}
public async void OnConnectionClosed(Exception exception)
{
/* nothing to do here */
//奇怪的bug 上传的时候用王捷修改的影像会关闭重新连接导致检查id 丢失,然后状态不一致
if (exception == null)
{
//var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
////将检查设置为传输结束
//await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
//await _studyRepository.SaveChangesAndClearAllTrackingAsync();
}
Log.Logger.Warning($"连接关闭 {exception?.Message} {exception?.InnerException?.Message}");
}
public async Task<DicomCStoreResponse> OnCStoreRequestAsync(DicomCStoreRequest request)
{
string studyInstanceUid = request.Dataset.GetString(DicomTag.StudyInstanceUID);
string seriesInstanceUid = request.Dataset.GetString(DicomTag.SeriesInstanceUID);
string sopInstanceUid = request.Dataset.GetString(DicomTag.SOPInstanceUID);
//Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid, trialId.ToString());
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, _trialId.ToString());
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, _trialId.ToString());
var ossService = _serviceProvider.GetService<IOSSService>();
var dicomArchiveService = _serviceProvider.GetService<IDicomArchiveService>();
var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();
var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();
var storeRelativePath = string.Empty;
var ossFolderPath = $"{_trialId}/Image/PACS/{_trialSiteId}/{studyInstanceUid}";
long fileSize = 0;
try
{
using (MemoryStream ms = new MemoryStream())
{
await request.File.SaveAsync(ms);
//irc 从路径最后一截取Guid
storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false);
fileSize = ms.Length;
}
Log.Logger.Information($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} {request.SOPInstanceUID} 上传完成 ");
}
catch (Exception ec)
{
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 上传异常 {ec.Message}");
}
var @lock = _distributedLockProvider.CreateLock($"{studyInstanceUid}");
using (await @lock.AcquireAsync())
{
try
{
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.Dataset, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE,fileSize);
if (!_SCPStudyIdList.Contains(scpStudyId))
{
_SCPStudyIdList.Add(scpStudyId);
}
var series = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
//没有缩略图
if (series != null && string.IsNullOrEmpty(series.ImageResizePath))
{
// 生成缩略图
using (var memoryStream = new MemoryStream())
{
DicomImage image = new DicomImage(request.Dataset);
var sharpimage = image.RenderImage().AsSharpImage();
sharpimage.Save(memoryStream, new JpegEncoder());
// 上传缩略图到 OSS
var seriesPath = await ossService.UploadToOSSAsync(memoryStream, ossFolderPath, seriesId.ToString() + ".preview.jpg", false);
Console.WriteLine(seriesPath + " Id: " + seriesId);
series.ImageResizePath = seriesPath;
}
}
await _seriesRepository.SaveChangesAsync();
}
catch (Exception ex)
{
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 传输处理异常:{ex.ToString()}");
}
}
//监控信息设置
_upload.FileCount++;
_upload.FileSize = _upload.FileSize + fileSize;
return new DicomCStoreResponse(request, DicomStatus.Success);
}
public Task OnCStoreRequestExceptionAsync(string tempFileName, Exception e)
{
// let library handle logging and error response
return Task.CompletedTask;
}
public Task<DicomCEchoResponse> OnCEchoRequestAsync(DicomCEchoRequest request)
{
return Task.FromResult(new DicomCEchoResponse(request, DicomStatus.Success));
}
}
}

View File

@ -0,0 +1,356 @@
using IRaCIS.Core.Domain.Share;
using System.Text;
using Microsoft.AspNetCore.Hosting;
using IRaCIS.Core.Infrastructure;
using Medallion.Threading;
using FellowOakDicom;
using FellowOakDicom.Imaging.Codec;
using System.Data;
using IRaCIS.Core.Domain.Models;
using FellowOakDicom.Network;
using IRaCIS.Core.SCP.Service;
using IRaCIS.Core.Infra.EFCore;
using MassTransit;
using System.Runtime.Intrinsics.X86;
using Serilog.Sinks.File;
namespace IRaCIS.Core.SCP.Service
{
public class DicomArchiveService : BaseService, IDicomArchiveService
{
private readonly IRepository<SCPPatient> _patientRepository;
private readonly IRepository<SCPStudy> _studyRepository;
private readonly IRepository<SCPSeries> _seriesRepository;
private readonly IRepository<SCPInstance> _instanceRepository;
private readonly IRepository<Dictionary> _dictionaryRepository;
private readonly IDistributedLockProvider _distributedLockProvider;
private List<Guid> _instanceIdList = new List<Guid>();
public DicomArchiveService(IRepository<SCPPatient> patientRepository, IRepository<SCPStudy> studyRepository,
IRepository<SCPSeries> seriesRepository,
IRepository<SCPInstance> instanceRepository,
IRepository<Dictionary> dictionaryRepository,
IDistributedLockProvider distributedLockProvider)
{
_distributedLockProvider = distributedLockProvider;
_studyRepository = studyRepository;
_patientRepository = patientRepository;
_seriesRepository = seriesRepository;
_instanceRepository = instanceRepository;
_dictionaryRepository = dictionaryRepository;
}
/// <summary>
/// 单个文件接收 归档
/// </summary>
/// <param name="dataset"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<Guid> ArchiveDicomFileAsync(DicomDataset dataset, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize)
{
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID,string.Empty);
//Guid patientId= IdentifierHelper.CreateGuid(patientIdStr);
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid,trialId.ToString());
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, trialId.ToString());
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, trialId.ToString());
var isStudyNeedAdd = false;
var isSeriesNeedAdd = false;
var isInstanceNeedAdd = false;
var isPatientNeedAdd = false;
//var @lock = _distributedLockProvider.CreateLock($"{studyInstanceUid}");
//using (@lock.Acquire())
{
var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr && t.TrialSiteId==trialSiteId );
var findStudy = await _studyRepository.FirstOrDefaultAsync(t=>t.Id== studyId);
var findSerice = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
var findInstance = await _instanceRepository.FirstOrDefaultAsync(t => t.Id == instanceId);
DateTime? studyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.StudyTime).TimeOfDay);
//先传输了修改了患者编号的又传输了没有修改患者编号的导致后传输的没有修改患者编号的下面的检查为0
if (findPatient == null && findStudy==null)
{
isPatientNeedAdd = true;
findPatient = new SCPPatient()
{
Id = NewId.NextSequentialGuid(),
TrialId=trialId,
TrialSiteId=trialSiteId,
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
EarliestStudyTime = studyTime,
LatestStudyTime = studyTime,
LatestPushTime = DateTime.Now,
};
if (findPatient.PatientBirthDate.Length == 8)
{
var birthDateStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}-{findPatient.PatientBirthDate[4]}{findPatient.PatientBirthDate[5]}-{findPatient.PatientBirthDate[6]}{findPatient.PatientBirthDate[7]}";
var yearStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}";
int year = 0;
var canParse = int.TryParse(yearStr, out year);
if (canParse && year > 1900)
{
findPatient.PatientBirthDate = birthDateStr;
DateTime birthDate;
if (findPatient.PatientAge == string.Empty && studyTime.HasValue && DateTime.TryParse(findPatient.PatientBirthDate,out birthDate))
{
var patientAge = studyTime.Value.Year - birthDate.Year;
// 如果生日还未到,年龄减去一岁
if (studyTime.Value < birthDate.AddYears(patientAge))
{
patientAge--;
}
findPatient.PatientAge = patientAge.ToString();
}
}
else
{
findPatient.PatientBirthDate = string.Empty;
}
}
}
else
{
if (studyTime < findPatient.EarliestStudyTime)
{
findPatient.EarliestStudyTime = studyTime;
}
if (studyTime > findPatient.LatestStudyTime)
{
findPatient.LatestStudyTime = studyTime;
}
findPatient.LatestPushTime = DateTime.Now;
}
if (findStudy == null)
{
isStudyNeedAdd = true;
findStudy = new SCPStudy
{
CalledAE = calledAE,
CallingAE = callingAE,
PatientId = findPatient.Id,
Id = studyId,
TrialId = trialId,
TrialSiteId = trialSiteId,
StudyInstanceUid = studyInstanceUid,
StudyTime = studyTime,
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
//ModalityForEdit = modalityForEdit,
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
InstitutionName = dataset.GetSingleValueOrDefault(DicomTag.InstitutionName, string.Empty),
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),
//需要特殊处理
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
//IsDoubleReview = addtionalInfo.IsDoubleReview,
SeriesCount = 0,
InstanceCount = 0
};
if (findStudy.PatientBirthDate.Length == 8)
{
findStudy.PatientBirthDate = $"{findStudy.PatientBirthDate[0]}{findStudy.PatientBirthDate[1]}{findStudy.PatientBirthDate[2]}{findStudy.PatientBirthDate[3]}-{findStudy.PatientBirthDate[4]}{findStudy.PatientBirthDate[5]}-{findStudy.PatientBirthDate[6]}{findStudy.PatientBirthDate[7]}";
}
}
if (findSerice == null)
{
isSeriesNeedAdd = true;
findSerice = new SCPSeries
{
Id = seriesId,
StudyId = findStudy.Id,
StudyInstanceUid = findStudy.StudyInstanceUid,
SeriesInstanceUid = seriesInstanceUid,
SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
//SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay),
//SeriesTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.SeriesDate) + dataset.GetSingleValue<string>(DicomTag.SeriesTime), out DateTime dt) ? dt : null,
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay),
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
ImagePositionPatient = dataset.GetSingleValueOrDefault(DicomTag.ImagePositionPatient, string.Empty),
ImageOrientationPatient = dataset.GetSingleValueOrDefault(DicomTag.ImageOrientationPatient, string.Empty),
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
SequenceName = dataset.GetSingleValueOrDefault(DicomTag.SequenceName, string.Empty),
ProtocolName = dataset.GetSingleValueOrDefault(DicomTag.ProtocolName, string.Empty),
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
InstanceCount = 0
};
++findStudy.SeriesCount;
}
if (findInstance == null)
{
isInstanceNeedAdd = true;
findInstance = new SCPInstance
{
Id = instanceId,
StudyId = findStudy.Id,
SeriesId = findSerice.Id,
StudyInstanceUid = findStudy.StudyInstanceUid,
SeriesInstanceUid = findSerice.SeriesInstanceUid,
SopInstanceUid = sopInstanceUid,
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.ContentDate).Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.ContentTime).TimeOfDay),
//InstanceTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.ContentDate) + dataset.GetSingleValue<string>(DicomTag.ContentTime), out DateTime dt) ? dt : null,
//InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate,(DateTime?)null)?.Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, TimeSpan.Zero)),
//dataset.GetSingleValueOrDefault(DicomTag.ContentDate,DateTime.Now);//, DicomTag.ContentTime)
CPIStatus = false,
ImageRows = dataset.GetSingleValueOrDefault(DicomTag.Rows, 0),
ImageColumns = dataset.GetSingleValueOrDefault(DicomTag.Columns, 0),
SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0),
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 0),
PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty),
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty),
WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty),
WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty),
Path = fileRelativePath,
FileSize= fileSize,
};
++findStudy.InstanceCount;
++findSerice.InstanceCount;
}
if (isPatientNeedAdd)
{
var ss = await _patientRepository.AddAsync(findPatient);
}
if (isStudyNeedAdd)
{
var dd = await _studyRepository.AddAsync(findStudy);
}
else
{
await _studyRepository.BatchUpdateNoTrackingAsync(t => t.Id == findStudy.Id, t => new SCPStudy() { IsUploadFinished = false });
}
if (isSeriesNeedAdd)
{
await _seriesRepository.AddAsync(findSerice);
}
if (isInstanceNeedAdd)
{
await _instanceRepository.AddAsync(findInstance);
}
else
{
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath,FileSize=fileSize });
}
await _studyRepository.SaveChangesAsync();
return findStudy.Id;
}
}
// 从DICOM文件中获取使用的字符集
private string GetEncodingVaulueFromDicomFile(DicomDataset dataset, DicomTag dicomTag)
{
// 获取DICOM文件的特定元素通常用于指示使用的字符集
var charset = dataset.GetSingleValueOrDefault(DicomTag.SpecificCharacterSet, string.Empty);
var dicomEncoding = DicomEncoding.GetEncoding(charset);
var dicomStringElement = dataset.GetDicomItem<DicomStringElement>(dicomTag);
var bytes = dicomStringElement.Buffer.Data;
return dicomEncoding.GetString(bytes);
//// 从DICOM文件中获取使用的字符集
//string filePath = "C:\\Users\\hang\\Documents\\WeChat Files\\wxid_r2imdzb7j3q922\\FileStorage\\File\\2024-05\\1.2.840.113619.2.80.169103990.5390.1271401378.4.dcm";
//DicomFile dicomFile = DicomFile.Open(filePath);
//// 获取DICOM文件的特定元素通常用于指示使用的字符集
//var charset = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.SpecificCharacterSet, string.Empty);
//var dicomEncoding = DicomEncoding.GetEncoding(charset);
//var value = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
//var dicomStringElement = dicomFile.Dataset.GetDicomItem<DicomStringElement>(DicomTag.PatientName);
//var bytes = dicomStringElement.Buffer.Data;
//var aa= dicomEncoding.GetString(bytes);
}
}
}

View File

@ -0,0 +1,11 @@
using FellowOakDicom;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
namespace IRaCIS.Core.SCP.Service
{
public interface IDicomArchiveService
{
Task<Guid> ArchiveDicomFileAsync(DicomDataset dicomDataset,Guid trialId,Guid trialSiteId, string fileRelativePath,string callingAE,string calledAE,long fileSize);
}
}

View File

@ -0,0 +1,770 @@
using AlibabaCloud.SDK.Sts20150401;
using Aliyun.OSS;
using Amazon;
using Amazon.Runtime;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.NewtonsoftJson;
using MassTransit;
using Microsoft.Extensions.Options;
using Minio;
using Minio.DataModel.Args;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
namespace IRaCIS.Core.SCP;
#region 绑定和返回模型
[LowerCamelCaseJson]
public class MinIOOptions : AWSOptions
{
public int Port { get; set; }
}
public class AWSOptions
{
public string EndPoint { get; set; }
public bool UseSSL { get; set; }
public string AccessKeyId { get; set; }
public string RoleArn { get; set; }
public string SecretAccessKey { get; set; }
public string BucketName { get; set; }
public string ViewEndpoint { get; set; }
public int DurationSeconds { get; set; }
public string Region { get; set; }
}
public class AliyunOSSOptions
{
public string RegionId { get; set; }
public string AccessKeyId { get; set; }
public string AccessKeySecret { get; set; }
public string InternalEndpoint { get; set; }
public string EndPoint { get; set; }
public string BucketName { get; set; }
public string RoleArn { get; set; }
public string Region { get; set; }
public string ViewEndpoint { get; set; }
public int DurationSeconds { get; set; }
}
public class ObjectStoreServiceOptions
{
public string ObjectStoreUse { get; set; }
public AliyunOSSOptions AliyunOSS { get; set; }
public MinIOOptions MinIO { get; set; }
public AWSOptions AWS { get; set; }
}
public class ObjectStoreDTO
{
public string ObjectStoreUse { get; set; }
public AliyunOSSTempToken AliyunOSS { get; set; }
public MinIOOptions MinIO { get; set; }
public AWSTempToken AWS { get; set; }
}
[LowerCamelCaseJson]
public class AliyunOSSTempToken
{
public string AccessKeyId { get; set; }
public string AccessKeySecret { get; set; }
public string EndPoint { get; set; }
public string BucketName { get; set; }
public string Region { get; set; }
public string ViewEndpoint { get; set; }
public string SecurityToken { get; set; }
public DateTime Expiration { get; set; }
}
[LowerCamelCaseJson]
public class AWSTempToken
{
public string Region { get; set; }
public string SessionToken { get; set; }
public string EndPoint { get; set; }
public string AccessKeyId { get; set; }
public string SecretAccessKey { get; set; }
public string BucketName { get; set; }
public string ViewEndpoint { get; set; }
public DateTime Expiration { get; set; }
}
public enum ObjectStoreUse
{
AliyunOSS = 0,
MinIO = 1,
AWS = 2,
}
#endregion
// aws 参考链接 https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/S3/S3_Basics
public interface IOSSService
{
public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true);
public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true);
public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
public Task<string> GetSignedUrl(string ossRelativePath);
public Task DeleteFromPrefix(string prefix);
public ObjectStoreDTO GetObjectStoreTempToken();
}
public class OSSService : IOSSService
{
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
private AliyunOSSTempToken AliyunOSSTempToken { get; set; }
private AWSTempToken AWSTempToken { get; set; }
public OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options)
{
ObjectStoreServiceOptions = options.CurrentValue;
}
/// <summary>
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
/// </summary>
/// <param name="fileStream"></param>
/// <param name="oosFolderPath"></param>
/// <param name="fileRealName"></param>
/// <param name="isFileNameAddGuid"></param>
/// <returns></returns>
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
{
GetObjectStoreTempToken();
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
try
{
using (var memoryStream = new MemoryStream())
{
fileStream.Seek(0, SeekOrigin.Begin);
fileStream.CopyTo(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
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 result = _ossClient.PutObject(aliConfig.BucketName, ossRelativePath, memoryStream);
}
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 putObjectArgs = new PutObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(ossRelativePath)
.WithStreamData(memoryStream)
.WithObjectSize(memoryStream.Length);
await minioClient.PutObjectAsync(putObjectArgs);
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
{
var awsConfig = ObjectStoreServiceOptions.AWS;
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);
var putObjectRequest = new Amazon.S3.Model.PutObjectRequest()
{
BucketName = awsConfig.BucketName,
InputStream = memoryStream,
Key = ossRelativePath,
};
await amazonS3Client.PutObjectAsync(putObjectRequest);
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
}
catch (Exception ex)
{
throw new BusinessValidationFailedException($"上传发生异常:{ex.Message}");
}
return "/" + ossRelativePath;
}
/// <summary>
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
/// </summary>
/// <param name="localFilePath"></param>
/// <param name="oosFolderPath"></param>
/// <param name="isFileNameAddGuid"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
{
GetObjectStoreTempToken();
var localFileName = Path.GetFileName(localFilePath);
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}" : $"{oosFolderPath}/{localFileName}";
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 result = _ossClient.PutObject(aliConfig.BucketName, ossRelativePath, localFilePath);
}
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 putObjectArgs = new PutObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(ossRelativePath)
.WithFileName(localFilePath);
await minioClient.PutObjectAsync(putObjectArgs);
}
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);
var putObjectRequest = new Amazon.S3.Model.PutObjectRequest()
{
BucketName = awsConfig.BucketName,
FilePath = localFilePath,
Key = ossRelativePath,
};
await amazonS3Client.PutObjectAsync(putObjectRequest);
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
return "/" + ossRelativePath;
}
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
{
GetObjectStoreTempToken();
ossRelativePath = ossRelativePath.TrimStart('/');
try
{
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 result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
// 将下载的文件流保存到本地文件
using (var fs = File.OpenWrite(localFilePath))
{
result.Content.CopyTo(fs);
fs.Close();
}
}
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 getObjectArgs = new GetObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(ossRelativePath)
.WithFile(localFilePath);
await minioClient.GetObjectAsync(getObjectArgs);
}
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);
var getObjectArgs = new Amazon.S3.Model.GetObjectRequest()
{
BucketName = awsConfig.BucketName,
Key = ossRelativePath,
};
await (await amazonS3Client.GetObjectAsync(getObjectArgs)).WriteResponseStreamToFileAsync(localFilePath, true, CancellationToken.None);
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
catch (Exception ex)
{
throw new BusinessValidationFailedException("oss下载失败!" + ex.Message);
}
}
public async Task<string> GetSignedUrl(string ossRelativePath)
{
GetObjectStoreTempToken();
ossRelativePath = ossRelativePath.TrimStart('/');
try
{
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);
// 生成签名URL。
var req = new GeneratePresignedUriRequest(aliConfig.BucketName, ossRelativePath, SignHttpMethod.Get)
{
// 设置签名URL过期时间默认值为3600秒。
Expiration = DateTime.Now.AddHours(1),
};
var uri = _ossClient.GeneratePresignedUri(req);
return uri.PathAndQuery;
}
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 args = new PresignedGetObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(ossRelativePath)
.WithExpiry(3600)
/*.WithHeaders(reqParams)*/;
var presignedUrl = await minioClient.PresignedGetObjectAsync(args);
Uri uri = new Uri(presignedUrl);
string relativePath = uri.PathAndQuery;
return relativePath;
}
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);
var presignedUrl = await amazonS3Client.GetPreSignedURLAsync(new GetPreSignedUrlRequest()
{
BucketName = awsConfig.BucketName,
Key = ossRelativePath,
Expires = DateTime.UtcNow.AddMinutes(120)
});
Uri uri = new Uri(presignedUrl);
string relativePath = uri.PathAndQuery;
return relativePath;
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
catch (Exception ex)
{
throw new BusinessValidationFailedException("oss授权url失败!" + ex.Message);
}
}
/// <summary>
/// 删除某个目录的文件
/// </summary>
/// <param name="prefix"></param>
/// <returns></returns>
public async Task DeleteFromPrefix(string prefix)
{
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);
try
{
ObjectListing objectListing = null;
string nextMarker = null;
do
{
// 使用 prefix 模拟目录结构,设置 MaxKeys 和 NextMarker
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName)
{
Prefix = prefix,
MaxKeys = 1000,
Marker = nextMarker
});
List<string> keys = objectListing.ObjectSummaries.Select(t => t.Key).ToList();
// 删除获取到的文件
if (keys.Count > 0)
{
_ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(aliConfig.BucketName, keys, false));
}
// 设置 NextMarker 以获取下一页的数据
nextMarker = objectListing.NextMarker;
} while (objectListing.IsTruncated);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
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 listArgs = new ListObjectsArgs().WithBucket(minIOConfig.BucketName).WithPrefix(prefix).WithRecursive(true);
// 创建一个空列表用于存储对象键
var objects = new List<string>();
// 使用 await foreach 来异步迭代对象列表
await foreach (var item in minioClient.ListObjectsEnumAsync(listArgs))
{
objects.Add(item.Key);
}
if (objects.Count > 0)
{
var objArgs = new RemoveObjectsArgs()
.WithBucket(minIOConfig.BucketName)
.WithObjects(objects);
// 删除对象
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);
// 列出指定前缀下的所有对象
var listObjectsRequest = new ListObjectsV2Request
{
BucketName = awsConfig.BucketName,
Prefix = prefix
};
var listObjectsResponse = await amazonS3Client.ListObjectsV2Async(listObjectsRequest);
if (listObjectsResponse.S3Objects.Count > 0)
{
// 准备删除请求
var deleteObjectsRequest = new Amazon.S3.Model.DeleteObjectsRequest
{
BucketName = awsConfig.BucketName,
Objects = new List<KeyVersion>()
};
foreach (var s3Object in listObjectsResponse.S3Objects)
{
deleteObjectsRequest.Objects.Add(new KeyVersion
{
Key = s3Object.Key
});
}
// 批量删除对象
var deleteObjectsResponse = await amazonS3Client.DeleteObjectsAsync(deleteObjectsRequest);
}
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
public ObjectStoreDTO GetObjectStoreTempToken()
{
var ossOptions = ObjectStoreServiceOptions.AliyunOSS;
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
{
var client = new Client(new AlibabaCloud.OpenApiClient.Models.Config()
{
AccessKeyId = ossOptions.AccessKeyId,
AccessKeySecret = ossOptions.AccessKeySecret,
//AccessKeyId = "LTAI5tJV76pYX5yPg1N9QVE8",
//AccessKeySecret = "roRNLa9YG1of4pYruJGCNKBXEWTAWa",
Endpoint = "sts.cn-hangzhou.aliyuncs.com"
});
var assumeRoleRequest = new AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleRequest();
// 将<YOUR_ROLE_SESSION_NAME>设置为自定义的会话名称例如oss-role-session。
assumeRoleRequest.RoleSessionName = $"session-name-{NewId.NextGuid()}";
// 将<YOUR_ROLE_ARN>替换为拥有上传文件到指定OSS Bucket权限的RAM角色的ARN。
assumeRoleRequest.RoleArn = ossOptions.RoleArn;
//assumeRoleRequest.RoleArn = "acs:ram::1899121822495495:role/webdirect";
assumeRoleRequest.DurationSeconds = ossOptions.DurationSeconds;
var runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
var response = client.AssumeRoleWithOptions(assumeRoleRequest, runtime);
var credentials = response.Body.Credentials;
var tempToken = new AliyunOSSTempToken()
{
AccessKeyId = credentials.AccessKeyId,
AccessKeySecret = credentials.AccessKeySecret,
//转为服务器时区,最后统一转为客户端时区
Expiration = TimeZoneInfo.ConvertTimeFromUtc(DateTime.Parse(credentials.Expiration), TimeZoneInfo.Local),
SecurityToken = credentials.SecurityToken,
Region = ossOptions.Region,
BucketName = ossOptions.BucketName,
EndPoint = ossOptions.EndPoint,
ViewEndpoint = ossOptions.ViewEndpoint,
};
AliyunOSSTempToken = tempToken;
return new ObjectStoreDTO() { ObjectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse, AliyunOSS = tempToken };
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
{
return new ObjectStoreDTO() { ObjectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse, MinIO = ObjectStoreServiceOptions.MinIO };
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
{
var awsOptions = ObjectStoreServiceOptions.AWS;
//aws 临时凭证
// 创建 STS 客户端
var stsClient = new AmazonSecurityTokenServiceClient(awsOptions.AccessKeyId, awsOptions.SecretAccessKey);
// 使用 AssumeRole 请求临时凭证
var assumeRoleRequest = new AssumeRoleRequest
{
RoleArn = awsOptions.RoleArn, // 角色 ARN
RoleSessionName = $"session-name-{NewId.NextGuid()}",
DurationSeconds = awsOptions.DurationSeconds // 临时凭证有效期
};
var assumeRoleResponse = stsClient.AssumeRoleAsync(assumeRoleRequest).Result;
var credentials = assumeRoleResponse.Credentials;
var tempToken = new AWSTempToken()
{
AccessKeyId = credentials.AccessKeyId,
SecretAccessKey = credentials.SecretAccessKey,
SessionToken = credentials.SessionToken,
Expiration = credentials.Expiration,
Region = awsOptions.Region,
BucketName = awsOptions.BucketName,
EndPoint = awsOptions.EndPoint,
ViewEndpoint = awsOptions.ViewEndpoint,
};
AWSTempToken = tempToken;
return new ObjectStoreDTO() { ObjectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse, AWS = tempToken };
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -7,16 +7,16 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.4" />
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.5" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageReference Include="AWSSDK.S3" Version="3.7.405" />
<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="AWSSDK.S3" Version="3.7.416.8" />
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.401.81" />
<PackageReference Include="DistributedLock.Core" Version="1.0.8" />
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
<PackageReference Include="fo-dicom" Version="5.2.4" />
<PackageReference Include="fo-dicom.Codecs" Version="5.16.4" />
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Minio" Version="6.0.3" />
@ -25,10 +25,10 @@
</PackageReference>
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.1.2" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
</ItemGroup>
<ItemGroup>

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);

View File

@ -20,6 +20,16 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Uat_IRC_SCP"
}
},
"US_Prod_IRC_SCP": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:6200",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "US_Prod_SCP"
}
}
}
}

View File

@ -21,6 +21,8 @@ using FellowOakDicom.Imaging;
using SharpCompress.Common;
using SixLabors.ImageSharp.Formats.Jpeg;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using FellowOakDicom.IO.Buffer;
namespace IRaCIS.Core.SCP.Service
{
@ -39,7 +41,9 @@ namespace IRaCIS.Core.SCP.Service
{
private IServiceProvider _serviceProvider { get; set; }
private List<Guid> _SCPStudyIdList { get; set; } = new List<Guid>();
private List<Guid> _SCPStudyIdList => _ImageUploadList.Where(t => t.SCPStudyId != Guid.Empty).Select(t => t.SCPStudyId).ToList();
private List<ImageUploadInfo> _ImageUploadList { get; set; } = new List<ImageUploadInfo>();
private SCPImageUpload _upload { get; set; }
@ -76,9 +80,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 +97,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>>();
@ -163,27 +166,48 @@ namespace IRaCIS.Core.SCP.Service
public async Task OnReceiveAssociationReleaseRequestAsync()
{
await DataMaintenanceAsaync();
var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();
var @lock = _distributedLockProvider.CreateLock($"{_upload.CallingAE}");
using (await @lock.AcquireAsync())
{
await DataMaintenanceAsaync();
//记录监控
await AddUploadLogAsync();
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
//将检查设置为传输结束
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
}
await SendAssociationReleaseResponseAsync();
}
private async Task AddUploadLogAsync()
{
//记录监控
var _SCPImageUploadRepository = _serviceProvider.GetService<IRepository<SCPImageUpload>>();
_upload.EndTime = DateTime.Now;
_upload.StudyCount = _SCPStudyIdList.Count;
_upload.StudyCount = _ImageUploadList.Count;
_upload.TrialId = _trialId;
_upload.TrialSiteId = _trialSiteId;
await _SCPImageUploadRepository.AddAsync(_upload, true);
_upload.UploadJsonStr = (new SCPImageLog() { UploadList = _ImageUploadList }).ToJsonStr();
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
//将检查设置为传输结束
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
await SendAssociationReleaseResponseAsync();
//可能是测试echo 导致记录了
await _SCPImageUploadRepository.AddAsync(_upload, _upload.FileCount > 0 ? true : false);
}
@ -249,6 +273,11 @@ namespace IRaCIS.Core.SCP.Service
//await _studyRepository.SaveChangesAndClearAllTrackingAsync();
}
else
{
//记录日志
await AddUploadLogAsync();
}
Log.Logger.Warning($"连接关闭 {exception?.Message} {exception?.InnerException?.Message}");
}
@ -259,9 +288,23 @@ namespace IRaCIS.Core.SCP.Service
public async Task<DicomCStoreResponse> OnCStoreRequestAsync(DicomCStoreRequest request)
{
string studyInstanceUid = request.Dataset.GetString(DicomTag.StudyInstanceUID);
string seriesInstanceUid = request.Dataset.GetString(DicomTag.SeriesInstanceUID);
string sopInstanceUid = request.Dataset.GetString(DicomTag.SOPInstanceUID);
string studyInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty);
string seriesInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty);
string sopInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty);
string patientIdStr = request.Dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
if (studyInstanceUid.IsNullOrEmpty() || seriesInstanceUid.IsNullOrEmpty() || sopInstanceUid.IsNullOrEmpty())
{
Log.Logger.Error($"接收数据读取StudyInstanceUID{studyInstanceUid}、SeriesInstanceUID{seriesInstanceUid}、SOPInstanceUID{sopInstanceUid}有空 ");
return new DicomCStoreResponse(request, DicomStatus.Success);
}
//确保来了影像集合存在
if (!_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
{
_ImageUploadList.Add(new ImageUploadInfo() { StudyInstanceUid = studyInstanceUid });
}
//Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid, trialId.ToString());
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, _trialId.ToString());
@ -281,11 +324,70 @@ namespace IRaCIS.Core.SCP.Service
long fileSize = 0;
try
{
using (MemoryStream ms = new MemoryStream())
{
await request.File.SaveAsync(ms);
#region 1帧拆成多个固定大小的方便移动端浏览
// 回到开头,读取 dicom
ms.Position = 0;
var dicomFile = DicomFile.Open(ms);
var pixelData = DicomPixelData.Create(dicomFile.Dataset);
var syntax = pixelData.Syntax;
// 每个 fragment 固定大小 (64KB 示例,可以自己调整)
int fragmentSize = 20 * 1024;
if (syntax.IsEncapsulated)
{
var newFragments = new DicomOtherByteFragment(DicomTag.PixelData);
for (int n = 0; n < pixelData.NumberOfFrames; n++)
{
var frameData = pixelData.GetFrame(n); // 获取完整一帧
var data = frameData.Data;
int offset = 0;
while (offset < data.Length)
{
int size = Math.Min(fragmentSize, data.Length - offset);
var buffer = new byte[size];
Buffer.BlockCopy(data, offset, buffer, 0, size);
newFragments.Fragments.Add(new MemoryByteBuffer(buffer));
offset += size;
}
}
// 替换原 PixelData
dicomFile.Dataset.AddOrUpdate(newFragments);
// 重新保存 dicom 到流
ms.SetLength(0);
dicomFile.Save(ms);
}
ms.Position = 0;
#endregion
#region 本地测试
//// --- 保存到本地文件测试 ---
//var localPath = @"D:\TestDicom.dcm";
//using (var fs = new FileStream(localPath, FileMode.Create, FileAccess.Write))
//{
// ms.CopyTo(fs);
//}
//return new DicomCStoreResponse(request, DicomStatus.Success);
#endregion
//irc 从路径最后一截取Guid
storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false);
@ -308,12 +410,8 @@ namespace IRaCIS.Core.SCP.Service
{
try
{
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.Dataset, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE,fileSize);
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.File, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE,fileSize);
if (!_SCPStudyIdList.Contains(scpStudyId))
{
_SCPStudyIdList.Add(scpStudyId);
}
var series = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
@ -342,12 +440,40 @@ namespace IRaCIS.Core.SCP.Service
await _seriesRepository.SaveChangesAsync();
if (_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
{
var find = _ImageUploadList.FirstOrDefault(t => t.StudyInstanceUid.Equals(studyInstanceUid));
find.SuccessImageCount++;
if (!find.PatientNameList.Any(t => t == patientIdStr) && patientIdStr.IsNotNullOrEmpty())
{
find.PatientNameList.Add(patientIdStr);
}
//首次 默认是Guid 空数据库归档出了Id
if (find.SCPStudyId != scpStudyId)
{
find.SCPStudyId = scpStudyId;
}
}
}
catch (Exception ex)
{
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 传输处理异常:{ex.ToString()}");
if (_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
{
var find = _ImageUploadList.FirstOrDefault(t => t.StudyInstanceUid.Equals(studyInstanceUid));
find.FailedImageCount++;
}
}
}

View File

@ -13,6 +13,7 @@ using IRaCIS.Core.Infra.EFCore;
using MassTransit;
using System.Runtime.Intrinsics.X86;
using Serilog.Sinks.File;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Core.SCP.Service
{
@ -52,8 +53,10 @@ namespace IRaCIS.Core.SCP.Service
/// <param name="dataset"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<Guid> ArchiveDicomFileAsync(DicomDataset dataset, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize)
public async Task<Guid> ArchiveDicomFileAsync(DicomFile dicomFile, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize)
{
var dataset = dicomFile.Dataset;
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
@ -82,7 +85,7 @@ namespace IRaCIS.Core.SCP.Service
DateTime? studyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.StudyTime).TimeOfDay);
//先传输了修改了患者编号的又传输了没有修改患者编号的导致后传输的没有修改患者编号的下面的检查为0
if (findPatient == null && findStudy==null)
if (findPatient == null /*&& findStudy==null*/)
{
isPatientNeedAdd = true;
@ -151,6 +154,32 @@ namespace IRaCIS.Core.SCP.Service
}
findPatient.LatestPushTime = DateTime.Now;
findPatient.PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
findPatient.PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty);
findPatient.PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty);
findPatient.PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty);
if (findPatient.PatientBirthDate.Length == 8)
{
var birthDateStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}-{findPatient.PatientBirthDate[4]}{findPatient.PatientBirthDate[5]}-{findPatient.PatientBirthDate[6]}{findPatient.PatientBirthDate[7]}";
var yearStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}";
int year = 0;
var canParse = int.TryParse(yearStr, out year);
if (canParse && year > 1900)
{
findPatient.PatientBirthDate = birthDateStr;
}
else
{
findPatient.PatientBirthDate = string.Empty;
}
}
}
if (findStudy == null)
@ -167,6 +196,9 @@ namespace IRaCIS.Core.SCP.Service
TrialSiteId = trialSiteId,
StudyInstanceUid = studyInstanceUid,
StudyTime = studyTime,
DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty),
DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty),
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
//ModalityForEdit = modalityForEdit,
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
@ -188,6 +220,12 @@ namespace IRaCIS.Core.SCP.Service
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
Manufacturer = dataset.GetSingleValueOrDefault(DicomTag.Manufacturer, string.Empty),
ManufacturerModelName = dataset.GetSingleValueOrDefault(DicomTag.ManufacturerModelName, string.Empty),
DeviceSerialNumber = dataset.GetSingleValueOrDefault(DicomTag.DeviceSerialNumber, string.Empty),
DeviceUID = dataset.GetSingleValueOrDefault(DicomTag.DeviceUID, string.Empty),
SoftwareVersions = dataset.GetSingleValueOrDefault(DicomTag.SoftwareVersions, string.Empty),
PatientWeight = dataset.GetSingleValueOrDefault(DicomTag.PatientWeight, string.Empty),
//IsDoubleReview = addtionalInfo.IsDoubleReview,
@ -201,6 +239,19 @@ namespace IRaCIS.Core.SCP.Service
findStudy.PatientBirthDate = $"{findStudy.PatientBirthDate[0]}{findStudy.PatientBirthDate[1]}{findStudy.PatientBirthDate[2]}{findStudy.PatientBirthDate[3]}-{findStudy.PatientBirthDate[4]}{findStudy.PatientBirthDate[5]}-{findStudy.PatientBirthDate[6]}{findStudy.PatientBirthDate[7]}";
}
}
else
{
findStudy.DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty);
findStudy.DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty);
findStudy.CalledAE = calledAE;
findStudy.CallingAE = callingAE;
findStudy.PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
findStudy.PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty);
findStudy.PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty);
findStudy.UpdateTime = DateTime.Now;
await _patientRepository.BatchUpdateNoTrackingAsync(t => t.Id == findStudy.PatientId, u => new SCPPatient() { LatestPushTime = DateTime.Now });
}
if (findSerice == null)
@ -218,6 +269,9 @@ namespace IRaCIS.Core.SCP.Service
//SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay),
//SeriesTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.SeriesDate) + dataset.GetSingleValue<string>(DicomTag.SeriesTime), out DateTime dt) ? dt : null,
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay),
DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty),
DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty),
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
@ -233,13 +287,29 @@ namespace IRaCIS.Core.SCP.Service
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
RadiopharmaceuticalInformationSequence = dataset.GetSingleValueOrDefault(DicomTag.RadiopharmaceuticalInformationSequence, string.Empty),
AcquisitionDate = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionDate, string.Empty),
InstanceCount = 0
};
++findStudy.SeriesCount;
}
else
{
findSerice.DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty);
findSerice.DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty);
findSerice.UpdateTime = DateTime.Now;
}
var transferSyntaxUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty);
var isEncapsulated = false;
if (transferSyntaxUID.IsNotNullOrEmpty())
{
isEncapsulated = DicomTransferSyntax.Lookup(DicomUID.Parse(transferSyntaxUID)).IsEncapsulated;
}
if (findInstance == null)
{
@ -271,6 +341,21 @@ namespace IRaCIS.Core.SCP.Service
WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty),
WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty),
PhotometricInterpretation = dataset.GetSingleValueOrDefault(DicomTag.PhotometricInterpretation, string.Empty),
BitsAllocated = dataset.GetSingleValueOrDefault(DicomTag.BitsAllocated, 0),
PixelRepresentation = dataset.GetSingleValueOrDefault(DicomTag.PixelRepresentation, string.Empty),
RescaleIntercept = dataset.GetSingleValueOrDefault(DicomTag.RescaleIntercept, string.Empty),
RescaleSlope = dataset.GetSingleValueOrDefault(DicomTag.RescaleSlope, string.Empty),
ImagePositionPatient = dataset.GetSingleValueOrDefault(DicomTag.ImagePositionPatient, string.Empty),
ImageOrientationPatient = dataset.GetSingleValueOrDefault(DicomTag.ImageOrientationPatient, string.Empty),
SequenceOfUltrasoundRegions = dataset.GetSingleValueOrDefault(DicomTag.SequenceOfUltrasoundRegions, string.Empty),
FrameTime = dataset.GetSingleValueOrDefault(DicomTag.FrameTime, string.Empty),
CorrectedImage = dataset.GetSingleValueOrDefault(DicomTag.CorrectedImage, string.Empty),
Units = dataset.GetSingleValueOrDefault(DicomTag.Units, string.Empty),
DecayCorrection = dataset.GetSingleValueOrDefault(DicomTag.DecayCorrection, string.Empty),
EncapsulatedDocument = dataset.GetSingleValueOrDefault(DicomTag.EncapsulatedDocument, string.Empty),
Path = fileRelativePath,
FileSize= fileSize,
@ -280,6 +365,15 @@ namespace IRaCIS.Core.SCP.Service
++findStudy.InstanceCount;
++findSerice.InstanceCount;
}
else
{
findInstance.SOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty);
findInstance.MediaStorageSOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty);
findInstance.TransferSytaxUID = transferSyntaxUID;
findInstance.MediaStorageSOPInstanceUID = dataset.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty);
findInstance.IsEncapsulated = isEncapsulated;
findInstance.UpdateTime = DateTime.Now;
}
if (isPatientNeedAdd)
{

View File

@ -5,7 +5,7 @@ namespace IRaCIS.Core.SCP.Service
{
public interface IDicomArchiveService
{
Task<Guid> ArchiveDicomFileAsync(DicomDataset dicomDataset,Guid trialId,Guid trialSiteId, string fileRelativePath,string callingAE,string calledAE,long fileSize);
Task<Guid> ArchiveDicomFileAsync(DicomFile dicomFile, Guid trialId,Guid trialSiteId, string fileRelativePath,string callingAE,string calledAE,long fileSize);
}
}

View File

@ -21,8 +21,8 @@
}
},
"ConnectionStrings": {
"RemoteNew": "Server=us-prod-mssql-service,1433;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=us-prod-mssql-service,1433;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
"RemoteNew": "Server=us-mssql-prod,1433;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=us-mssql-prod,1433;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"DicomSCPServiceConfig": {
"CalledAEList": [

View File

@ -19,6 +19,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infrastructure"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRC.Core.SCP", "IRC.Core.SCP\IRC.Core.SCP.csproj", "{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IRC.Core.Dicom", "IRC.Core.Dicom\IRC.Core.Dicom.csproj", "{0545F0A5-D97B-4A47-92A6-A8A02A181322}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -57,6 +59,10 @@ Global
{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}.Release|Any CPU.Build.0 = Release|Any CPU
{0545F0A5-D97B-4A47-92A6-A8A02A181322}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0545F0A5-D97B-4A47-92A6-A8A02A181322}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0545F0A5-D97B-4A47-92A6-A8A02A181322}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0545F0A5-D97B-4A47-92A6-A8A02A181322}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -1,5 +1,7 @@
using Amazon.Auth.AccessControlPolicy;
using AlibabaCloud.SDK.Sts20150401;
using Amazon.Auth.AccessControlPolicy;
using Amazon.SecurityToken;
using AutoMapper;
using Azure.Core;
using IdentityModel.Client;
using IdentityModel.OidcClient;
@ -20,10 +22,12 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Org.BouncyCastle.Tls;
using RestSharp;
using RestSharp.Authenticators;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
@ -105,196 +109,6 @@ namespace IRaCIS.Api.Controllers
/// <summary> 系统用户登录接口[New] </summary>
[HttpPost, Route("user/login")]
[AllowAnonymous]
public async Task<IResponseOutput> Login(UserLoginDTO loginUser,
[FromServices] IFusionCache _fusionCache,
[FromServices] IUserService _userService,
[FromServices] ITokenService _tokenService,
[FromServices] IReadingImageTaskService readingImageTaskService,
[FromServices] IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig,
[FromServices] IOptionsMonitor<SystemEmailSendConfig> _emailConfig,
[FromServices] IMailVerificationService _mailVerificationService)
{
var emailConfig = _emailConfig.CurrentValue;
var companyInfo = new SystemEmailSendConfigView() { CompanyName = emailConfig.CompanyName, CompanyNameCN = emailConfig.CompanyNameCN, CompanyShortName = emailConfig.CompanyShortName, CompanyShortNameCN = emailConfig.CompanyShortNameCN };
//MFA 邮箱验证 前端传递用户Id 和MFACode
if (loginUser.UserId != null && _verifyConfig.CurrentValue.OpenLoginMFA)
{
Guid userId = (Guid)loginUser.UserId;
//验证MFA 编码是否有问题 ,前端要拆开,自己调用验证的逻辑
//await _userService.VerifyMFACodeAsync(userId, loginUser.MFACode);
//var loginUser = await _userRepository.Where(u => u.UserName.Equals(userName) && u.Password == password).ProjectTo<UserBasicInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
var basicInfo = await _userService.GetUserBasicInfo(userId, loginUser.Password);
var loginReturn = new LoginReturnDTO() { BasicInfo = basicInfo };
loginReturn.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(loginReturn.BasicInfo));
// 创建一个 CookieOptions 对象,用于设置 Cookie 的属性
var option = new CookieOptions
{
Expires = DateTime.Now.AddMonths(1), // 设置过期时间为 30 分钟之后
HttpOnly = false, // 确保 cookie 只能通过 HTTP 访问
SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None, // 设置 SameSite 属性
Secure = false // 确保 cookie 只能通过 HTTPS 访问
};
HttpContext.Response.Cookies.Append("access_token", loginReturn.JWTStr, option);
// 验证阅片休息时间
await readingImageTaskService.ResetReadingRestTime(userId);
await _fusionCache.SetAsync(CacheKeys.UserToken(userId), loginReturn.JWTStr, TimeSpan.FromDays(7));
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(userId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(_verifyConfig.CurrentValue.AutoLoginOutMinutes));
loginReturn.CompanyInfo = companyInfo;
return ResponseOutput.Ok(loginReturn);
}
else
{
var returnModel = await _userService.Login(loginUser.UserName, loginUser.Password);
if (returnModel.IsSuccess)
{
#region GRPC 调用鉴权中心因为服务器IIS问题 http/2 故而没法使用
////重试策略
//var defaultMethodConfig = new MethodConfig
//{
// Names = { MethodName.Default },
// RetryPolicy = new RetryPolicy
// {
// MaxAttempts = 3,
// InitialBackoff = TimeSpan.FromSeconds(1),
// MaxBackoff = TimeSpan.FromSeconds(5),
// BackoffMultiplier = 1.5,
// RetryableStatusCodes = { Grpc.Core.StatusCode.Unavailable }
// }
//};
//#region unable to trust the certificate then the gRPC client can be configured to ignore the invalid certificate
//var httpHandler = new HttpClientHandler();
//// Return `true` to allow certificates that are untrusted/invalid
//httpHandler.ServerCertificateCustomValidationCallback =
// HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
//////这一句是让grpc支持本地 http 如果本地访问部署在服务器上,那么是访问不成功的
//AppContext.SetSwitch(
// "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
//#endregion
//var grpcAdress = configuration.GetValue<string>("GrpcAddress");
////var grpcAdress = "http://localhost:7200";
//var channel = GrpcChannel.ForAddress(grpcAdress, new GrpcChannelOptions
//{
// HttpHandler = httpHandler,
// ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
//});
////var channel = GrpcChannel.ForAddress(grpcAdress);
//var grpcClient = new TokenGrpcService.TokenGrpcServiceClient(channel);
//var userInfo = returnModel.Data.BasicInfo;
//var tokenResponse = grpcClient.GetUserToken(new GetTokenReuqest()
//{
// Id = userInfo.Id.ToString(),
// ReviewerCode = userInfo.ReviewerCode,
// IsAdmin = userInfo.IsAdmin,
// RealName = userInfo.RealName,
// UserTypeEnumInt = (int)userInfo.UserTypeEnum,
// UserTypeShortName = userInfo.UserTypeShortName,
// UserName = userInfo.UserName
//});
//returnModel.Data.JWTStr = tokenResponse.Token;
#endregion
var userId = returnModel.Data.BasicInfo.Id;
if (_verifyConfig.CurrentValue.OpenLoginMFA)
{
//MFA 发送邮件
returnModel.Data.IsMFA = true;
var email = returnModel.Data.BasicInfo.EMail;
var hiddenEmail = IRCEmailPasswordHelper.MaskEmail(email);
returnModel.Data.BasicInfo.EMail = hiddenEmail;
//修改密码
if (returnModel.Data.BasicInfo.IsFirstAdd || returnModel.Data.BasicInfo.LoginState == 1)
{
returnModel.Data.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(returnModel.Data.BasicInfo));
}
else
{
//正常登录才发送邮件
await _userService.SendMFAEmail(userId);
}
}
else
{
returnModel.Data.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(returnModel.Data.BasicInfo));
// 创建一个 CookieOptions 对象,用于设置 Cookie 的属性
var option = new CookieOptions
{
Expires = DateTime.Now.AddMonths(1), // 设置过期时间为 30 分钟之后
HttpOnly = false, // 确保 cookie 只能通过 HTTP 访问
SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None, // 设置 SameSite 属性
Secure = false // 确保 cookie 只能通过 HTTPS 访问
};
HttpContext.Response.Cookies.Append("access_token", returnModel.Data.JWTStr, option);
// 验证阅片休息时间
await readingImageTaskService.ResetReadingRestTime(returnModel.Data.BasicInfo.Id);
await _fusionCache.SetAsync(CacheKeys.UserToken(userId), returnModel.Data.JWTStr, TimeSpan.FromDays(7));
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(userId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(_verifyConfig.CurrentValue.AutoLoginOutMinutes));
}
}
returnModel.Data.CompanyInfo = companyInfo;
return returnModel;
}
}
[AllowAnonymous]
[HttpGet, Route("user/getPublicKey")]
public IResponseOutput GetPublicKey([FromServices] IOptionsMonitor<IRCEncreptOption> _IRCEncreptOption)
@ -309,18 +123,13 @@ namespace IRaCIS.Api.Controllers
[AllowAnonymous]
public IResponseOutput ShareImage([FromServices] ITokenService _tokenService)
{
var token = _tokenService.GetToken(IRaCISClaims.Create(new UserBasicInfo()
var token = _tokenService.GetToken(new UserTokenInfo()
{
Id = Guid.NewGuid(),
IsReviewer = false,
IsAdmin = false,
RealName = "Share001",
UserName = "Share001",
Sex = 0,
//UserType = "ShareType",
IdentityUserId = Guid.NewGuid(),
UserName = "ImageShare",
UserTypeEnum = UserTypeEnum.ShareImage,
Code = "ShareCode001",
}));
});
return ResponseOutput.Ok("/showdicom?studyId=f7b67793-8155-0223-2f15-118f2642efb8&type=Share&token=" + token);
}
@ -375,11 +184,74 @@ namespace IRaCIS.Api.Controllers
}
#region 老项目依赖
[HttpGet("user/GenerateSTS")]
public IResponseOutput GenerateSTS([FromServices] IOptionsMonitor<ObjectStoreServiceOptions> options)
{
var ossOptions = options.CurrentValue.AliyunOSS;
var client = new Client(new AlibabaCloud.OpenApiClient.Models.Config()
{
AccessKeyId = ossOptions.AccessKeyId,
AccessKeySecret = ossOptions.AccessKeySecret,
Endpoint = "sts.cn-hangzhou.aliyuncs.com"
});
var assumeRoleRequest = new AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleRequest();
// 将<YOUR_ROLE_SESSION_NAME>设置为自定义的会话名称例如oss-role-session。
assumeRoleRequest.RoleSessionName = $"session-name-{NewId.NextGuid()}";
// 将<YOUR_ROLE_ARN>替换为拥有上传文件到指定OSS Bucket权限的RAM角色的ARN。
assumeRoleRequest.RoleArn = ossOptions.RoleArn;
//assumeRoleRequest.RoleArn = "acs:ram::1899121822495495:role/webdirect";
assumeRoleRequest.DurationSeconds = ossOptions.DurationSeconds;
var runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
var response = client.AssumeRoleWithOptions(assumeRoleRequest, runtime);
var credentials = response.Body.Credentials;
var tempToken = new AliyunOSSTempToken()
{
AccessKeyId = credentials.AccessKeyId,
AccessKeySecret = credentials.AccessKeySecret,
//转为服务器时区,最后统一转为客户端时区
Expiration = TimeZoneInfo.ConvertTimeFromUtc(DateTime.Parse(credentials.Expiration), TimeZoneInfo.Local),
SecurityToken = credentials.SecurityToken,
Region = ossOptions.Region,
BucketName = ossOptions.BucketName,
EndPoint = ossOptions.EndPoint,
ViewEndpoint = ossOptions.ViewEndpoint,
PreviewEndpoint = ossOptions.PreviewEndpoint
};
// 返回STS令牌信息给前端
var stsToken = new
{
AccessKeyId = credentials.AccessKeyId,
AccessKeySecret = credentials.AccessKeySecret,
SecurityToken = credentials.SecurityToken,
Expiration = credentials.Expiration,
Region = ossOptions.Region,
BucketName = ossOptions.BucketName,
ViewEndpoint = ossOptions.ViewEndpoint,
};
return ResponseOutput.Ok(stsToken);
}
#endregion
[HttpGet("User/UserRedirect")]
[AllowAnonymous]
public async Task<IActionResult> UserRedirect([FromServices] IRepository<User> _userRepository, 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);
@ -394,10 +266,22 @@ namespace IRaCIS.Api.Controllers
var errorUrl = domainStrList[0] + "//" + domainStrList[2] + "/error";
if (!await _userRepository.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. Return")} ";
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);

View File

@ -51,30 +51,30 @@ namespace IRaCIS.Core.API.Controllers.Special
[TrialGlobalLimit( "AddOrUpdateTrial", "BeforeOngoingCantOpt", "AfterStopCannNotOpt" )]
public async Task<IResponseOutput<Trial>> AddOrUpdateTrial(TrialCommand param)
{
var userId = Guid.Parse(User.FindFirst("id").Value);
//var userId = Guid.Parse(User.FindFirst("id").Value);
var result = await _trialService.AddOrUpdateTrial(param);
if (_trialService.TrialExpeditedChange)
{
var needCalReviewerIds = await _trialService.GetTrialEnrollmentReviewerIds(param.Id.Value);
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
//if (_trialService.TrialExpeditedChange)
//{
// var needCalReviewerIds = await _trialService.GetTrialEnrollmentReviewerIds(param.Id.Value);
// var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
calcList.ForEach(t =>
{
if (needCalReviewerIds.Contains(t.DoctorId))
{
_calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
{
NeedCalculateReviewers = new List<Guid>()
{
t.DoctorId
},
CalculateMonth = DateTime.Parse(t.YearMonth)
}, User.FindFirst("id").Value);
// calcList.ForEach(t =>
// {
// if (needCalReviewerIds.Contains(t.DoctorId))
// {
// _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
// {
// NeedCalculateReviewers = new List<Guid>()
// {
// t.DoctorId
// },
// CalculateMonth = DateTime.Parse(t.YearMonth)
// }, User.FindFirst("id").Value);
}
});
}
// }
// });
//}
return result;
}

View File

@ -2,6 +2,7 @@
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Application.BusinessFilter;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Contracts.DTO;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.Image.QA;
using IRaCIS.Core.Application.Service;
@ -34,6 +35,31 @@ namespace IRaCIS.Core.API.Controllers
) : ControllerBase
{
[HttpPost, Route("Inspection/NoneDicomStudy/UpdateNoneDicomStudy")]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> UpdateNoneDicomStudy(DataInspectionDto<NoneDicomEdit> opt, [FromServices] INoneDicomStudyService _noneDicomStudyService)
{
var singId = await _inspectionService.RecordSing(opt.SignInfo);
var result = await _noneDicomStudyService.UpdateNoneDicomStudy(opt.Data);
await _inspectionService.CompletedSign(singId, result);
return result;
}
[HttpPost, Route("Inspection/QCOperation/UpdateDicomStudyInfo")]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> UpdateDicomStudyInfo(DataInspectionDto<DicomStudyEdit> opt, [FromServices] IQCOperationService _qcOperationService)
{
var singId = await _inspectionService.RecordSing(opt.SignInfo);
var result = await _qcOperationService.UpdateDicomStudyInfo(opt.Data);
await _inspectionService.CompletedSign(singId, result);
return result;
}
#region 获取稽查数据
/// <summary>
/// 获取稽查数据
@ -52,7 +78,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingImageTask/SubmitOncologyReadingInfo")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SetOncologyReadingInfo(DataInspectionDto<SubmitOncologyReadingInfoInDto> opt)
@ -69,7 +95,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingImageTask/SubmitDicomVisitTask")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SubmitDicomVisitTask(DataInspectionDto<SubmitDicomVisitTaskInDto> opt)
@ -88,7 +114,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingImageTask/SubmitGlobalReadingInfo")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SubmitGlobalReadingInfo(DataInspectionDto<SubmitGlobalReadingInfoInDto> opt)
@ -107,7 +133,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/configTrialBasicInfo/TrialReadingInfoSign")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> TrialReadingInfoSign(DataInspectionDto<TrialReadingInfoSignInDto> opt)
@ -126,7 +152,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingMedicalReview/FinishMedicalReview")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> FinishMedicalReview(DataInspectionDto<FinishMedicalReviewInDto> opt)
@ -143,7 +169,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingMedicineQuestion/ConfirmReadingMedicineQuestion")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> ConfirmReadingMedicineQuestion(DataInspectionDto<ConfirmReadingMedicineQuestionInDto> opt)
@ -161,7 +187,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingImageTask/SubmitVisitTaskQuestions")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SubmitVisitTaskQuestions(DataInspectionDto<SubmitVisitTaskQuestionsInDto> opt)
@ -179,7 +205,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ClinicalAnswer/CRCSignClinicalData")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> CRCSignClinicalData(DataInspectionDto<CRCSignClinicalDataInDto> opt)
@ -197,7 +223,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ClinicalAnswer/CRCConfirmClinical")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> CRCConfirmClinical(DataInspectionDto<CRCConfirmClinicalInDto> opt)
@ -214,7 +240,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ClinicalAnswer/CRCCancelConfirmClinical")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> CRCCancelConfirmClinical(DataInspectionDto<CRCCancelConfirmClinicalInDto> opt)
@ -232,7 +258,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ClinicalAnswer/PMConfirmClinical")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> PMConfirmClinical(DataInspectionDto<CRCConfirmClinicalInDto> opt)
@ -250,7 +276,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingClinicalData/SignConsistencyAnalysisReadingClinicalData")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SignConsistencyAnalysisReadingClinicalData(DataInspectionDto<SignConsistencyAnalysisReadingClinicalDataInDto> opt)
@ -267,7 +293,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ClinicalAnswer/SubmitClinicalFormAndSign")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SubmitClinicalFormAndSign(DataInspectionDto<SubmitClinicalFormInDto> opt)
@ -284,7 +310,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingImageTask/SubmitJudgeVisitTaskResult")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SubmitJudgeVisitTaskResult(DataInspectionDto<SaveJudgeVisitTaskResult> opt)
@ -303,7 +329,7 @@ namespace IRaCIS.Core.API.Controllers
/// <returns></returns>
[HttpPost, Route("Inspection/configTrialBasicInfo/ConfigTrialBasicInfoConfirm")]
[UnitOfWork]
[TrialGlobalLimit( "BeforeOngoingCantOpt" )]
[TrialGlobalLimit("BeforeOngoingCantOpt")]
public async Task<IResponseOutput> ConfigTrialBasicInfoConfirm(DataInspectionDto<BasicTrialConfig> opt)
{
@ -345,7 +371,7 @@ namespace IRaCIS.Core.API.Controllers
/// <returns></returns>
[HttpPost, Route("Inspection/configTrialBasicInfo/ConfigTrialUrgentInfoConfirm")]
[UnitOfWork]
[TrialGlobalLimit( "BeforeOngoingCantOpt" )]
[TrialGlobalLimit("BeforeOngoingCantOpt")]
public async Task<IResponseOutput> ConfigTrialUrgentInfoConfirm(DataInspectionDto<TrialUrgentConfig> opt)
{
opt.Data.IsTrialUrgentConfirmed = true;
@ -358,7 +384,7 @@ namespace IRaCIS.Core.API.Controllers
[HttpPost, Route("Inspection/configTrialBasicInfo/ConfigTrialPACSInfoConfirm")]
[UnitOfWork]
[TrialGlobalLimit( "BeforeOngoingCantOpt" )]
[TrialGlobalLimit("BeforeOngoingCantOpt")]
public async Task<IResponseOutput> ConfigTrialPACSInfoConfirm(DataInspectionDto<TrialPACSConfig> opt)
{
opt.Data.IsTrialPACSConfirmed = true;
@ -374,7 +400,7 @@ namespace IRaCIS.Core.API.Controllers
/// <returns></returns>
[HttpPost, Route("Inspection/configTrialBasicInfo/TrialConfigSignatureConfirm")]
[UnitOfWork]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> TrialConfigSignatureConfirm(DataInspectionDto<SignConfirmDTO> opt)
{
@ -391,7 +417,7 @@ namespace IRaCIS.Core.API.Controllers
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingCriterion/ResetAndAsyncCriterion")]
[UnitOfWork]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> ResetAndAsyncCriterion(DataInspectionDto<ResetAndAsyncCriterionInDto> opt)
{
@ -409,7 +435,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/QCOperation/CRCRequestToQC")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> CRCRequestToQC(DataInspectionDto<CRCRequestToQCCommand> opt)
{
@ -424,21 +450,31 @@ namespace IRaCIS.Core.API.Controllers
/// 设置QC 通过或者不通过 7:QC failed 8QC passed
/// </summary>
[HttpPost, Route("Inspection/QCOperation/QCPassedOrFailed")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> QCPassedOrFailed(DataInspectionDto<QCPassedOrFailedDto> opt)
{
var singid = await _inspectionService.RecordSing(opt.SignInfo);
var result = await _qCOperationService.QCPassedOrFailed(opt.Data.trialId, opt.Data.subjectVisitId, opt.Data.auditState);
await _inspectionService.CompletedSign(singid, result);
return result;
if (opt.Data.IsSecondPass != null)
{
var result = await _qCOperationService.QCSecondReviewPassedOrFailed(opt.Data.trialId, opt.Data.subjectVisitId, (bool)opt.Data.IsSecondPass);
await _inspectionService.CompletedSign(singid, result);
return result;
}
else
{
var result = await _qCOperationService.QCPassedOrFailed(opt.Data.trialId, opt.Data.subjectVisitId, opt.Data.auditState);
await _inspectionService.CompletedSign(singid, result);
return result;
}
}
/// <summary>
/// 一致性核查 回退 对话记录不清除 只允许PM回退
/// </summary>
[HttpPost, Route("Inspection/QCOperation/CheckBack")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> CheckBack(DataInspectionDto<IDDto> opt)
{
@ -455,7 +491,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadClinicalData/ReadClinicalDataSign")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> ReadClinicalDataSign(DataInspectionDto<ReadingClinicalDataSignIndto> opt)
{
@ -470,7 +506,7 @@ namespace IRaCIS.Core.API.Controllers
/// CRC 设置已经重传完成
/// </summary>
[HttpPost, Route("Inspection/QCOperation/SetReuploadFinished")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SetReuploadFinished(DataInspectionDto<CRCReuploadFinishedCommand> opt)
{
@ -486,7 +522,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/TrialConfig/updateTrialState")]
[TrialGlobalLimit( "BeforeOngoingCantOpt")]
[TrialGlobalLimit("BeforeOngoingCantOpt")]
[UnitOfWork]
public async Task<IResponseOutput> UpdateTrialState(DataInspectionDto<UpdateTrialStateDto> opt)
{
@ -502,7 +538,7 @@ namespace IRaCIS.Core.API.Controllers
/// </summary>
/// <returns></returns>
[HttpPost, Route("Inspection/TrialDocument/userConfirm")]
[TrialGlobalLimit( "BeforeOngoingCantOpt", "SignSystemDocNoTrialId", "AfterStopCannNotOpt" )]
[TrialGlobalLimit("BeforeOngoingCantOpt", "SignSystemDocNoTrialId", "AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> UserConfirm(DataInspectionDto<UserConfirmCommand> opt)
{
@ -519,10 +555,10 @@ namespace IRaCIS.Core.API.Controllers
/// </summary>
/// <returns></returns>
[HttpPost, Route("Inspection/VisitTask/ConfirmReReading")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> ConfirmReReading(DataInspectionDto<ConfirmReReadingCommand> opt, [FromServices] IVisitTaskService _visitTaskService)
public async Task<IResponseOutput> ConfirmReReading(DataInspectionDto<ConfirmReReadingCommand> opt, [FromServices] IVisitTaskService _visitTaskService)
{
var singId = await _inspectionService.RecordSing(opt.SignInfo);
var result = await _visitTaskService.ConfirmReReading(opt.Data);

View File

@ -27,6 +27,7 @@ using Microsoft.AspNetCore.WebUtilities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using MiniExcelLibs;
using Newtonsoft.Json;
@ -38,6 +39,7 @@ using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Path = System.IO.Path;
@ -271,6 +273,7 @@ namespace IRaCIS.Core.API.Controllers
public List<OSSFileDTO> UploadedFileList { get; set; } = new List<OSSFileDTO>();
public bool? IsImageSegmentLabel { get; set; }
public class OSSFileDTO
{
@ -297,7 +300,7 @@ namespace IRaCIS.Core.API.Controllers
[HttpPost, Route("Study/ArchiveStudy")]
[DisableFormValueModelBinding]
[DisableRequestSizeLimit]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> ArchiveStudyNew(Guid trialId, Guid subjectVisitId, string studyInstanceUid, Guid? abandonStudyId, Guid studyMonitorId,
[FromServices] ILogger<UploadDownLoadController> _logger,
[FromServices] IStudyService _studyService,
@ -370,7 +373,7 @@ namespace IRaCIS.Core.API.Controllers
//await _uploadHub.Clients.All.ReceivProgressAsync(archiveStudyCommand.StudyInstanceUid, receivedCount);
await _uploadHub.Clients.User(_userInfo.Id.ToString()).ReceivProgressAsync(archiveStudyCommand.StudyInstanceUid, receivedCount);
await _uploadHub.Clients.User(_userInfo.UserRoleId.ToString()).ReceivProgressAsync(archiveStudyCommand.StudyInstanceUid, receivedCount);
archiveResult.ReceivedFileCount = receivedCount;
@ -452,7 +455,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="_studyMonitorRepository"></param>
/// <returns></returns>
[HttpPost, Route("Study/PreArchiveStudy")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> PreArchiveStudy(PreArchiveStudyCommand preArchiveStudyCommand,
[FromServices] IStudyService _studyService,
[FromServices] IRepository<StudyMonitor> _studyMonitorRepository)
@ -488,7 +491,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="_noneDicomStudyFileRepository"></param>
/// <returns></returns>
[HttpPost("NoneDicomStudy/UploadNoneDicomFile")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> UploadNoneDicomFile(UploadNoneDicomFileCommand incommand,
[FromServices] IRepository<NoneDicomStudy> _noneDicomStudyRepository,
[FromServices] IRepository<StudyMonitor> _studyMonitorRepository,
@ -519,7 +522,17 @@ namespace IRaCIS.Core.API.Controllers
}
else
{
await _noneDicomStudyFileRepository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, NoneDicomStudyId = noneDicomStudyId.Value, FileType = item.FileType, FileSize = item.FileFize });
if (incommand.IsImageSegmentLabel == true)
{
await _noneDicomStudyFileRepository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, ImageLabelNoneDicomStudyId = noneDicomStudyId.Value, FileType = item.FileType, FileSize = item.FileFize });
}
else
{
await _noneDicomStudyFileRepository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, NoneDicomStudyId = noneDicomStudyId.Value, FileType = item.FileType, FileSize = item.FileFize });
}
}
@ -527,7 +540,7 @@ namespace IRaCIS.Core.API.Controllers
}
var uploadFinishedTime = DateTime.Now;
var noneDicomStudy = await _noneDicomStudyRepository.FirstOrDefaultAsync((t => t.Id == noneDicomStudyId));
var noneDicomStudy = await _noneDicomStudyRepository.FirstOrDefaultAsync(t => t.Id == noneDicomStudyId, true);
noneDicomStudy.FileCount = noneDicomStudy.FileCount + (incommand.VisitTaskId != null ? 0 : incommand.UploadedFileList.Count);
@ -555,19 +568,22 @@ namespace IRaCIS.Core.API.Controllers
/// 一致性核查 excel上传 支持三种格式
/// </summary>
/// <param name="trialId"></param>
/// <param name="isFullCheck"></param>
/// <param name="oSSService"></param>
/// <param name="_inspectionFileRepository"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[HttpPost("QCOperation/UploadVisitCheckExcel/{trialId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> UploadVisitCheckExcel(Guid trialId, [FromServices] IOSSService oSSService, [FromServices] IRepository<InspectionFile> _inspectionFileRepository)
public async Task<IResponseOutput> UploadVisitCheckExcel(Guid trialId, bool isFullCheck, [FromServices] IOSSService oSSService, [FromServices] IRepository<InspectionFile> _inspectionFileRepository)
{
var fileName = string.Empty;
var templateFileStream = new MemoryStream();
var inspectionFileId = Guid.Empty;
await FileUploadToOSSAsync(async (realFileName, fileStream) =>
{
fileName = realFileName;
@ -582,9 +598,11 @@ namespace IRaCIS.Core.API.Controllers
templateFileStream.Seek(0, SeekOrigin.Begin);
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/Check", realFileName);
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, $"{trialId.ToString()}/InspectionUpload/DataReconciliation", realFileName);
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId });
var addEntity = await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId }, true);
inspectionFileId = addEntity.Id;
return ossRelativePath;
@ -730,8 +748,11 @@ namespace IRaCIS.Core.API.Controllers
if (etcCheckList == null || etcCheckList.Count == 0)
{
await _inspectionFileRepository.BatchUpdateNoTrackingAsync(t => t.Id == inspectionFileId, u => new InspectionFile() { CheckState = EDCCheckState.Failed });
//---请保证上传数据符合模板文件中的样式,且存在有效数据。
return ResponseOutput.NotOk(_localizer["UploadDownLoad_InvalidData"]);
}
else
{
@ -751,6 +772,8 @@ namespace IRaCIS.Core.API.Controllers
if (etcCheckList.Count == 0)
{
await _inspectionFileRepository.BatchUpdateNoTrackingAsync(t => t.Id == inspectionFileId, u => new InspectionFile() { CheckState = EDCCheckState.Failed });
//---请保证上传数据符合模板文件中的样式,且存在有效数据。
return ResponseOutput.NotOk(_localizer["UploadDownLoad_InvalidData"]);
}
@ -762,8 +785,19 @@ namespace IRaCIS.Core.API.Controllers
//var client = _mediator.CreateRequestClient<ConsistenCheckCommand>();
//await client.GetResponse<ConsistenCheckResult>(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
//不获取结果,不用定义返回类型
await _mediator.Send(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
if (isFullCheck)
{
await _mediator.Send(new ConsistenFullCheckCommand() { ETCList = etcCheckList, TrialId = trialId, InspectionFileId = inspectionFileId });
}
else
{
//不获取结果,不用定义返回类型
await _mediator.Send(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
}
return ResponseOutput.Ok();
@ -799,12 +833,13 @@ namespace IRaCIS.Core.API.Controllers
[HttpPost, Route("TrialSiteSurvey/UploadTrialSiteSurveyUser")]
[DisableFormValueModelBinding]
[UnitOfWork]
public async Task<IResponseOutput> UploadTrialSiteSurveyUser(Guid trialId, string baseUrl, string routeUrl,
[FromServices] IRepository<TrialSite> _trialSiteRepository,
[FromServices] IRepository<UserType> _usertypeRepository,
[FromServices] ITrialSiteSurveyService _trialSiteSurveyService,
[FromServices] IOSSService oSSService,
[FromServices] IOptionsMonitor<SystemEmailSendConfig> _systemEmailConfig,
[FromServices] IRepository<InspectionFile> _inspectionFileRepository)
{
var templateFileStream = new MemoryStream();
@ -821,9 +856,9 @@ namespace IRaCIS.Core.API.Controllers
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_TemplateUploadData"]);
}
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/SiteSurvey", realFileName);
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, $"{trialId.ToString()}/InspectionUpload/SiteSurvey", realFileName);
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId });
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId }, true);
@ -836,6 +871,26 @@ namespace IRaCIS.Core.API.Controllers
.Where(t => !(string.IsNullOrWhiteSpace(t.TrialSiteCode) && string.IsNullOrWhiteSpace(t.FirstName) && string.IsNullOrWhiteSpace(t.LastName) && string.IsNullOrWhiteSpace(t.Email)
&& string.IsNullOrWhiteSpace(t.Phone) && string.IsNullOrWhiteSpace(t.UserTypeStr) && string.IsNullOrWhiteSpace(t.OrganizationName))).ToList();
//处理前后空格
foreach (var excel in excelList)
{
excel.Email = excel.Email.Trim();
excel.Phone = excel.Phone.Trim();
excel.OrganizationName = excel.OrganizationName.Trim();
excel.UserTypeStr = excel.UserTypeStr?.Trim();
excel.TrialSiteCode = excel.TrialSiteCode.Trim();
excel.FirstName = excel.FirstName.Trim();
excel.LastName = excel.LastName.Trim();
}
var emailRegexStr = _systemEmailConfig.CurrentValue.EmailRegexStr;
if (excelList.Any(t => !Regex.IsMatch(t.Email, emailRegexStr)))
{
var errorList = excelList.Where(t => !Regex.IsMatch(t.Email, emailRegexStr)).Select(t => t.Email).ToList();
//有邮箱不符合邮箱格式,请核查Excel数据
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_InvalidEmail"] + string.Join(" | ", errorList));
}
if (excelList.Any(t => string.IsNullOrWhiteSpace(t.TrialSiteCode) || string.IsNullOrWhiteSpace(t.FirstName) || string.IsNullOrWhiteSpace(t.LastName) || string.IsNullOrWhiteSpace(t.Email) || string.IsNullOrWhiteSpace(t.UserTypeStr)))
{
//请确保Excel中 每一行的 中心编号,姓名,邮箱,用户类型数据记录完整再进行上传
@ -850,18 +905,20 @@ namespace IRaCIS.Core.API.Controllers
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_InvalidCenters"]);
}
if (excelList.GroupBy(t => new { t.TrialSiteCode, t.UserTypeStr, t.Email }).Any(g => g.Count() > 1))
foreach (var item in excelList.GroupBy(t => t.Email.Trim()))
{
// 同一邮箱,同一用户类型,只能生成一个账户,请核查Excel数据
var itemList = item.ToList();
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_CheckDuplicateAccounts"]);
var first = item.First();
if (itemList.Any(t => t.Email.Trim() != first.Email.Trim() || t.Phone.Trim() != first.Phone.Trim() || t.OrganizationName.Trim() != first.OrganizationName.Trim() || t.FirstName.Trim() != first.FirstName.Trim() || t.LastName.Trim() != first.LastName.Trim()))
{
//同一邮箱,用户信息应该保持一致!
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_CheckDuplicateAccounts"]);
}
}
if (excelList.Any(t => !t.Email.Contains("@")))
{
//有邮箱不符合邮箱格式,请核查Excel数据
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_InvalidEmail"]);
}
var generateUserTypeList = new List<string>() { "CRC", "CRA" };
//if (excelList.Any(t => !generateUserTypeList.Contains(t.UserTypeStr.ToUpper())))
@ -879,7 +936,7 @@ namespace IRaCIS.Core.API.Controllers
foreach (var item in excelList)
{
switch (item.UserTypeStr.ToUpper())
switch (item.UserTypeStr.Trim().ToUpper())
{
case "CRC":
@ -896,7 +953,7 @@ namespace IRaCIS.Core.API.Controllers
}
item.TrialSiteId = siteList.FirstOrDefault(t => t.TrialSiteCode.ToUpper() == item.TrialSiteCode.ToUpper()).TrialSiteId;
item.TrialSiteId = siteList.FirstOrDefault(t => t.TrialSiteCode.Trim().ToUpper() == item.TrialSiteCode.Trim().ToUpper()).TrialSiteId;
}
var list = excelList.Where(t => t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator || t.UserTypeEnum == UserTypeEnum.CRA).ToList();
@ -947,7 +1004,11 @@ namespace IRaCIS.Core.API.Controllers
EmailBodyHtml = 4,
Other = 5
ReadKeyFile = 5,
Other = 6,
}
/// <summary>
@ -979,6 +1040,9 @@ namespace IRaCIS.Core.API.Controllers
case UploadFileType.EmailBodyHtml:
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.EmailTemplate, fileName));
break;
case UploadFileType.ReadKeyFile:
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.ReadKetFile, fileName));
break;
default:
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetOtherFileUploadPath(_hostEnvironment, StaticData.Folder.TempFile, fileName));

View File

@ -20,6 +20,8 @@ namespace IRaCIS.Core.API.HostService;
public class HangfireHostService(IRecurringMessageScheduler _recurringMessageScheduler,
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IMediator _mediator,
ILogger<HangfireHostService> _logger) : IHostedService
{
@ -39,7 +41,22 @@ public class HangfireHostService(IRecurringMessageScheduler _recurringMessageSch
HangfireJobHelper.RemoveCronJob(jobId);
}
// 清除所有可能存在的定时任务,防止类型加载错误
var allJobIdList = JobStorage.Current.GetConnection().GetRecurringJobs().Select(t => t.Id).ToList();
foreach (var jobId in allJobIdList)
{
try
{
HangfireJobHelper.RemoveCronJob(jobId);
_logger.LogInformation($"已清除定时任务: {jobId}");
}
catch (Exception ex)
{
_logger.LogWarning($"清除定时任务 {jobId} 时出错: {ex.Message}");
}
}
// 项目手动选择,周期性邮件
var taskInfoList = await _trialEmailNoticeConfigRepository.Where(t => t.Trial.TrialStatusStr == StaticData.TrialState.TrialOngoing && t.EmailCron != string.Empty && t.IsAutoSend)
.Select(t => new { t.Id, t.Code, TrialCode = t.Trial.TrialCode, t.EmailCron, t.BusinessScenarioEnum, t.TrialId })
.ToListAsync();
@ -55,6 +72,20 @@ public class HangfireHostService(IRecurringMessageScheduler _recurringMessageSch
}
// 系统邮件定时任务
var systemTaskInfoList = await _emailNoticeConfigrepository.Where(t => t.EmailCron != string.Empty && t.IsAutoSend)
.Select(t => new { t.Id, t.Code, t.EmailCron, t.BusinessScenarioEnum, })
.ToListAsync();
foreach (var task in systemTaskInfoList)
{
//利用主键作为任务Id
var jobId = $"{task.Id}_({task.BusinessScenarioEnum})";
HangfireJobHelper.AddOrUpdateTimingCronJob(jobId, task.BusinessScenarioEnum, task.EmailCron);
}
//await _recurringMessageScheduler.ScheduleRecurringPublish(new QCImageQuestionSchedule() { CronExpression = "0/3 * * * * ? " }, new MasstransiTestCommand { value = "message at " + DateTime.Now.ToString() });

View File

@ -69,24 +69,22 @@
<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">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.15">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="ConfigMapFileProvider" Version="2.0.1" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.14" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.20" />
<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="Hangfire.SqlServer" Version="1.8.20" />
<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" />
<PackageReference Include="Serilog.Sinks.Email" Version="4.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.9.0" />
<PackageReference Include="Serilog.Sinks.Email" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="9.0.1" />
</ItemGroup>
<ItemGroup>
@ -114,6 +112,12 @@
</Content>
</ItemGroup>
<ItemGroup>
<None Update="Resources\GeoLite2-City.mmdb">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ProjectExtensions>
<VisualStudio>
<UserProperties properties_4launchsettings_1json__JsonSchema="" />

View File

@ -34,9 +34,6 @@
<param name="doctorId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Api.Controllers.ExtraController.Login(IRaCIS.Application.Contracts.UserLoginDTO,ZiggyCreatures.Caching.Fusion.IFusionCache,IRaCIS.Core.Application.Service.IUserService,IRaCIS.Core.Application.Auth.ITokenService,IRaCIS.Core.Application.Contracts.IReadingImageTaskService,Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.ServiceVerifyConfigOption},Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.SystemEmailSendConfig},IRaCIS.Core.Application.Service.IMailVerificationService)">
<summary> 系统用户登录接口[New] </summary>
</member>
<member name="M:IRaCIS.Api.Controllers.ExtraController.OAuthCallBack(System.String,System.String)">
<summary>
回调到前端,前端调用后端的接口
@ -321,11 +318,12 @@
<param name="_noneDicomStudyFileRepository"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadVisitCheckExcel(System.Guid,IRaCIS.Core.Application.Helper.IOSSService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.InspectionFile})">
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadVisitCheckExcel(System.Guid,System.Boolean,IRaCIS.Core.Application.Helper.IOSSService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.InspectionFile})">
<summary>
一致性核查 excel上传 支持三种格式
</summary>
<param name="trialId"></param>
<param name="isFullCheck"></param>
<param name="oSSService"></param>
<param name="_inspectionFileRepository"></param>
<returns></returns>

View File

@ -1,13 +1,13 @@
using IRaCIS.Core.API;
using IRaCIS.Core.API.HostService;
using IRaCIS.Core.Application.BusinessFilter;
using IRaCIS.Core.Application.BusinessFilter.LegacyController.Database.Api;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.MassTransit.Consumer;
using IRaCIS.Core.Application.Service;
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 +37,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))
{
@ -96,6 +101,7 @@ builder.Services.AddControllers(options =>
options.Filters.Add<UnitOfWorkFilter>();
options.Filters.Add<LimitUserRequestAuthorization>();
options.Filters.Add<TrialGlobalLimitActionFilter>();
options.Filters.Add<RequestDuplicationFilter>();
})
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
@ -111,8 +117,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 +137,7 @@ builder.Services.AddFusionCache();
builder.Services.AddhangfireSetup(_configuration);
//Serilog 日志可视化 LogDashboard日志
builder.Services.AddLogDashboardSetup();
//builder.Services.AddLogDashboardSetup();
//Dicom影像渲染图片 跨平台
builder.Services.AddDicomSetup();
@ -211,13 +222,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);

View File

@ -20,7 +20,8 @@
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Test_IRC"
"ASPNETCORE_ENVIRONMENT": "Test_IRC",
"ASPNETCORE_OpenSwagger": "true"
},
"applicationUrl": "http://localhost:6100"
},
@ -69,6 +70,14 @@
"ASPNETCORE_ENVIRONMENT": "US_Uat_IRC"
},
"applicationUrl": "http://localhost:6100"
},
"IRaCIS.US_Prod_IRC": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "US_Prod_IRC"
},
"applicationUrl": "http://localhost:6100"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 MiB

View File

@ -1,2 +1,3 @@
{
}

View File

@ -17,7 +17,7 @@ namespace IRaCIS.Core.API
{
public virtual string GetUserId(HubConnectionContext connection)
{
return connection.User?.FindFirst(JwtIRaCISClaimType.Id)?.Value!;
return connection.User?.FindFirst(JwtIRaCISClaimType.IdentityUserId)?.Value!;
}
}

View File

@ -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;
// }
// }
//}

View File

@ -38,7 +38,7 @@ namespace IRaCIS.Core.API
diagnosticContext.Set("QueryString", request.QueryString.Value);
}
diagnosticContext.Set("FullName", httpContext?.User?.FindFirst(JwtIRaCISClaimType.RealName)?.Value);
diagnosticContext.Set("FullName", httpContext?.User?.FindFirst(JwtIRaCISClaimType.FullName)?.Value);
diagnosticContext.Set("UserType", httpContext?.User?.FindFirst(JwtIRaCISClaimType.UserTypeShortName)?.Value);

View File

@ -1,5 +1,6 @@
using EntityFramework.Exceptions.SqlServer;
using IRaCIS.Core.Application.Triggers;
using IRaCIS.Core.Application.Triggers.AfterSaveTrigger;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Infra.EFCore.Interceptor;
@ -80,6 +81,11 @@ namespace IRaCIS.Core.API
triggerOptions.AddTrigger<UserLogTrigger>();
triggerOptions.AddTrigger<UserAddTrigger>();
triggerOptions.AddTrigger<UserLogAfterTrigger>();
triggerOptions.AddTrigger<IdenttiyUserRoleInfoTrigger>();
});

View File

@ -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());
});
// });
}
}
}
// }
// }
//}

View File

@ -126,6 +126,51 @@ namespace IRaCIS.Core.API
}
public class DateOnlyUniversalJsonConverter : JsonConverter
{
private readonly string _format;
public DateOnlyUniversalJsonConverter(string format = "yyyy-MM-dd")
{
_format = format;
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateOnly) || objectType == typeof(DateOnly?);
}
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value == null)
{
writer.WriteValue(""); // null -> 空字符串
return;
}
var date = (DateOnly)value;
if (date == default)
{
writer.WriteValue(""); // default(DateOnly) -> 空字符串
}
else
{
writer.WriteValue(date.ToString(_format));
}
}
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
var str = reader.TokenType == JsonToken.Null ? null : reader.Value?.ToString();
if (string.IsNullOrWhiteSpace(str) || !DateOnly.TryParse(str, out var date))
{
return objectType == typeof(DateOnly?) ? null : default(DateOnly);
}
return date;
}
}
#region 废弃

View File

@ -49,6 +49,8 @@ namespace IRaCIS.Core.API
//必须放在后面
options.SerializerSettings.Converters.Add(services.BuildServiceProvider().GetService<JSONTimeZoneConverter>());
//options.SerializerSettings.Converters.Add(new DateOnlyUniversalJsonConverter("yyyy-MM-dd"));
})
.AddControllersAsServices()//动态webApi属性注入需要

View File

@ -22,16 +22,20 @@ namespace IRaCIS.Core.API
var config = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.MinimumLevel.Override("MassTransit", LogEventLevel.Warning)
//https://github.com/ZiggyCreatures/FusionCache/blob/main/docs/Logging.md
.MinimumLevel.Override("ZiggyCreatures.Caching.Fusion", LogEventLevel.Warning)
// Filter out ASP.NET Core infrastructre logs that are Information and below 日志太多了 一个请求 记录好几条
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.AspNetCore.Mvc", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.AspNetCore.Routing", LogEventLevel.Warning)
.MinimumLevel.Override("Hangfire", LogEventLevel.Warning)
.Enrich.FromLogContext()
.Enrich.FromLogContext()
.Filter.ByExcluding(logEvent => logEvent.Properties.ContainsKey("RequestPath") && logEvent.Properties["RequestPath"].ToString().Contains("/health"))
.WriteTo.Console()
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day);
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day,retainedFileCountLimit:60);
#region 根据环境配置是否打开错误发送邮件通知

View File

@ -28,12 +28,13 @@ public static class ServiceCollectionSetup
services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
services.AddOptions().Configure<IRCEncreptOption>(_configuration.GetSection("EncrypteResponseConfig"));
services.AddOptions().Configure<RequestDuplicationOptions>(_configuration.GetSection("RequestDuplicationOptions"));
services.AddOptions().Configure<SystemPacsConfig>(_configuration.GetSection("SystemPacsConfig"));
services.Configure<IRaCISBasicConfigOption>(_configuration.GetSection("IRaCISBasicConfig"));
services.Configure<ServiceVerifyConfigOption>(_configuration.GetSection("BasicSystemConfig"));
//转发头设置 获取真实IP
//ת<EFBFBD><EFBFBD>ͷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȡ<EFBFBD><C8A1>ʵIP
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
@ -51,7 +52,7 @@ public static class ServiceCollectionSetup
services.AddScoped<IObtainTaskAutoCancelJob, ObtainTaskAutoCancelJob>();
// 注册以Service 结尾的服务
// ע<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Service <20><>β<EFBFBD>ķ<EFBFBD><C4B7><EFBFBD>
services.Scan(scan => scan
.FromAssemblies(typeof(BaseService).Assembly)
.AddClasses(classes => classes.Where(t => t.Name.Contains("Service")))
@ -70,23 +71,23 @@ public static class ServiceCollectionSetup
#endregion
// MediatR 进程内消息 事件解耦 从程序集中 注册命令和handler对应关系
// MediatR <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ <20>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD> <20>ӳ<EFBFBD><D3B3><EFBFBD><EFBFBD><EFBFBD> ע<><D7A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>handler<65><72>Ӧ<EFBFBD><D3A6>ϵ
//builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<ConsistencyVerificationHandler>());
#region 历史废弃配置
#region <EFBFBD><EFBFBD>ʷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//builder.Services.AddMemoryCache();
////上传限制 配置
////<EFBFBD>ϴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
//builder.Services.Configure<FormOptions>(options =>
//{
// options.MultipartBodyLengthLimit = int.MaxValue;
// options.ValueCountLimit = int.MaxValue;
// options.ValueLengthLimit = int.MaxValue;
//});
//IP 限流 可设置白名单 或者黑名单
//IP <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ð<EFBFBD><C3B0><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>ߺ<EFBFBD><DFBA><EFBFBD><EFBFBD><EFBFBD>
//services.AddIpPolicyRateLimitSetup(_configuration);
// 用户类型 策略授权
// <EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ
//services.AddAuthorizationPolicySetup(_configuration);
#endregion
}
@ -94,25 +95,25 @@ public static class ServiceCollectionSetup
}
#region Autofac 废弃
#region Autofac <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//public class AutofacModuleSetup : Autofac.Module
//{
// protected override void Load(ContainerBuilder containerBuilder)
// {
// #region byzhouhang 20210917 此处注册泛型仓储 可以减少Domain层 和Infra.EFcore 两层 空的仓储接口定义和 仓储文件定义
// #region byzhouhang 20210917 <EFBFBD>˴<EFBFBD>ע<EFBFBD><EFBFBD>Ͳִ<EFBFBD> <20><><EFBFBD>Լ<EFBFBD><D4BC><EFBFBD>Domain<69><6E> <20><>Infra.EFcore <20><><EFBFBD><EFBFBD> <20>յIJִ<C4B2><D6B4>ӿڶ<D3BF><DAB6><EFBFBD><EFBFBD> <20>ִ<EFBFBD><D6B4>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD>
// containerBuilder.RegisterGeneric(typeof(Repository<>))
// .As(typeof(IRepository<>)).InstancePerLifetimeScope();//注册泛型仓储
// .As(typeof(IRepository<>)).InstancePerLifetimeScope();//ע<EFBFBD><EFBFBD>Ͳִ<EFBFBD>
// containerBuilder.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
// #endregion
// #region 指定控制器也由autofac 来进行实例获取 https://www.cnblogs.com/xwhqwer/p/15320838.html
// #region ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><EFBFBD>autofac <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD>ȡ https://www.cnblogs.com/xwhqwer/p/15320838.html
// //获取所有控制器类型并使用属性注入
// //<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>п<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD>
// containerBuilder.RegisterAssemblyTypes(typeof(BaseService).Assembly)
// .Where(type => typeof(IDynamicWebApi).IsAssignableFrom(type))
// .PropertiesAutowired();
@ -128,7 +129,7 @@ public static class ServiceCollectionSetup
// //containerBuilder.RegisterType<UserInfo>().As<IUserInfo>().InstancePerLifetimeScope();
// //注册hangfire任务 依赖注入
// //ע<EFBFBD><EFBFBD>hangfire<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>ע<EFBFBD><D7A2>
// containerBuilder.RegisterType<ObtainTaskAutoCancelJob>().As<IObtainTaskAutoCancelJob>().InstancePerDependency();
// }

View File

@ -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
};

View File

@ -27,7 +27,8 @@ namespace IRaCIS.Core.API
hangFireConfig.UseSqlServerStorage(hangFireConnStr, new SqlServerStorageOptions()
{
SchemaName = "dbo",
}).UseRecommendedSerializerSettings().UseSimpleAssemblyNameTypeSerializer();
}).UseRecommendedSerializerSettings();
// 移除 UseSimpleAssemblyNameTypeSerializer() 以避免类型加载问题
}

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",
@ -16,11 +16,11 @@
"RegionId": "cn-shanghai",
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
"AccessKeyId": "LTAI5tNRTsqL6aWmHkDmTwoH",
"AccessKeySecret": "7mtGz3qrYWI6JMMBZiLeC119VWicZH",
"RoleArn": "acs:ram::1899121822495495:role/irc-oss-access",
"BucketName": "zy-irc-store",
"ViewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
"AccessKeyId": "LTAI5tFUCCmz5TwghZHsj45Y",
"AccessKeySecret": "8evrBy1fVfzJG25i67Jm0xqn9Xcw2T",
"RoleArn": "acs:ram::1078130221702011:role/uat-oss-access",
"BucketName": "tl-med-irc-event-store",
"ViewEndpoint": "https://tl-med-irc-event-store.oss-cn-shanghai.aliyuncs.com",
"Region": "oss-cn-shanghai",
"DurationSeconds": 7200
},
@ -52,11 +52,18 @@
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90
"ChangePassWordDays": 90,
// 1 Elevate 2 Extensive
"TemplateType": 2,
//MFA
"UserMFAVerifyDays": 1
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"Imap": "imap.qiye.aliyun.com",
"ImapPort": 993,
"FromEmail": "uat@extimaging.com",
"FromName": "UAT_IRC",
"AuthorizationCode": "SHzyyl2021",
@ -66,7 +73,13 @@
"CompanyShortName": "Extensive Imaging",
"CompanyShortNameCN": "展影医疗",
"IsEnv_US": false
},
"RequestDuplicationOptions": {
"IsEnabled": true,
"DuplicationWindowMs": 200,
"CacheTimeSeconds": 5,
"ExcludedPaths": [
]
}
}

View File

@ -7,10 +7,10 @@
}
},
"ConnectionStrings": {
//"RemoteNew": "Server=101.132.193.237,1434;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
//"Hangfire": "Server=101.132.193.237,1434;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
"RemoteNew": "Server=prod_mssql_standard,1433;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
"Hangfire": "Server=prod_mssql_standard,1433;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
"RemoteNew": "Server=101.132.193.237,1434;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
"Hangfire": "Server=101.132.193.237,1434;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
//"RemoteNew": "Server=prod_mssql_standard,1433;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
//"Hangfire": "Server=prod_mssql_standard,1433;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
},
"ObjectStoreService": {
"ObjectStoreUse": "AliyunOSS",
@ -43,40 +43,51 @@
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 360,
"AutoLoginOutMinutes": 120,
"OpenLoginMFA": false,
"ContinuousReadingTimeMin": 120,
"ReadingRestTimeMin": 10,
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90
"ChangePassWordDays": 90,
// 1 Elevate 2 Extensive
"TemplateType": 2,
//MFA
"UserMFAVerifyDays": 1
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "IRC@extimaging.com",
"FromName": "IRC",
"Imap": "imap.qiye.aliyun.com",
"ImapPort": 993,
"FromEmail": "irc@extimaging.com",
"FromName": "IRC Imaging System",
"AuthorizationCode": "ExtImg@2022",
"SiteUrl": "http://irc.extimaging.com/login",
"OrganizationName": "Extlmaging",
"OrganizationNameCN": "Extlmaging",
"SystemShortName": "IRC",
"OrganizationName": "ExtImaging",
"OrganizationNameCN": "ExtImaging",
"CompanyName": "Extensive Imaging",
"CompanyNameCN": "上海展影医疗科技有限公司",
"CompanyShortName": "Extensive Imaging",
"CompanyShortNameCN": "展影医疗",
"IsEnv_US": false,
"IsOpenErrorNoticeEmail": false,
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
},
"SystemPacsConfig": {
"Port": "11113",
"IP": "101.132.193.237"
},
"RequestDuplicationOptions": {
"IsEnabled": true,
"DuplicationWindowMs": 200,
"CacheTimeSeconds": 5,
"ExcludedPaths": [
]
}
}

View File

@ -1,103 +1,181 @@
{
//
"Logging": {
//
"LogLevel": {
//
"Default": "Information",
//
"Microsoft": "Warning",
// ASP.NET Core
"Microsoft.Hosting.Lifetime": "Information"
}
},
//
"ConnectionStrings": {
//
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
// Hangfire
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
//
"ObjectStoreService": {
// 使
"ObjectStoreUse": "AliyunOSS",
//
"AliyunOSS": {
// OSS Region ID
"RegionId": "cn-shanghai",
// OSS 访
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
// OSS 访
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
// OSS 访 ID
"AccessKeyId": "LTAI5tRRZehUp2V9pyTPtAJm",
// OSS 访 Secret
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
// OSS ARN
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
// OSS Bucket
"BucketName": "zy-irc-test-store",
"ViewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
// OSS 访
"ViewEndpoint": "https://zy-irc-test-dev-cache.oss-cn-shanghai.aliyuncs.com",
// OSS
"Region": "oss-cn-shanghai",
"DurationSeconds": 7200
// OSS 访
"DurationSeconds": 7200,
// OSS
"PreviewEndpoint": "https://test-oss.test.extimaging.com"
},
// MinIO
"MinIO": {
// MinIO 访
"EndPoint": "hir-oss.test.extimaging.com",
// MinIO
"Port": "443",
// 使 SSL
"UseSSL": true,
// MinIO ARN
"AccessKey": "fbStsVYCIPKHQneeqMwD",
// MinIO 访
"SecretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
// MinIO BucketName
"BucketName": "irc-test",
// MinIO 访
"ViewEndpoint": "https://hir-oss.test.extimaging.com/irc-test"
},
// AWS S3
"AWS": {
// AWS S3 Region
"Region": "us-east-1",
// AWS S3 访
"EndPoint": "s3.us-east-1.amazonaws.com",
// 使 SSL
"UseSSL": true,
// AWS S3 ARN
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
// AWS S3 访 ID
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
// AWS S3 访 Secret
"SecretAccessKey": "Pgrg3le5jPxZQ7MR1yYNS30J0XRyJeKVyIIjElXc",
// AWS S3 Bucket
"BucketName": "ei-med-s3-lili-uat-store",
// AWS S3 访
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com",
// AWS S3
"DurationSeconds": 7200
}
},
//
"BasicSystemConfig": {
//
"OpenUserComplexPassword": false,
//
"OpenSignDocumentBeforeWork": false,
"OpenTrialRelationDelete": true,
//
"OpenLoginLimit": false,
//
"LoginMaxFailCount": 5,
//
"LoginFailLockMinutes": 1,
"AutoLoginOutMinutes": 1,
//
"AutoLoginOutMinutes": 10,
// MFA
"OpenLoginMFA": false,
//
"ContinuousReadingTimeMin": 120,
//
"ReadingRestTimeMin": 10,
//
"IsNeedChangePassWord": true,
//
"ChangePassWordDays": 90,
"ThirdPdfUrl": "http://106.14.89.110:30088/api/v1/convert/file/pdf"
// 1 Elevate 2 Extensive
"TemplateType": 2,
//
"OpenTrialRelationDelete": true,
// PDF
"ThirdPdfUrl": "http://106.14.89.110:30088/api/v1/convert/file/pdf",
//MFA
"UserMFAVerifyMinutes": 1440
},
//
"SystemEmailSendConfig": {
// SMTP
"Port": 465,
// SMTP
"Host": "smtp.qiye.aliyun.com",
"Imap": "imap.qiye.aliyun.com",
"ImapPort": 993,
//
"FromEmail": "test@extimaging.com",
"FromName": "Test_IRC",
//
"FromName": "Test IRC Imaging System",
// SMTP
"AuthorizationCode": "SHzyyl2021",
// 访
"SiteUrl": "http://irc.test.extimaging.com/login",
"OrganizationName": "Extlmaging",
"OrganizationNameCN": "Extlmaging",
//
"SystemShortName": "IRC",
//
"OrganizationName": "ExtImaging",
//
"OrganizationNameCN": "ExtImaging",
//
"CompanyName": "Extensive Imaging",
//
"CompanyNameCN": "上海展影医疗科技有限公司",
//
"CompanyShortName": "Extensive Imaging",
//
"CompanyShortNameCN": "展影医疗",
//
"IsEnv_US": false,
//
"IsOpenErrorNoticeEmail": false,
"ErrorNoticeEmailList": ["872297557@qq.com"]
//
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
//
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
},
// PACS
"SystemPacsConfig": {
// PACS
"Port": "11113",
// PACSIP
"IP": "106.14.89.110"
},
//
"RequestDuplicationOptions": {
//
"IsEnabled": true,
//
"DuplicationWindowMs": 200,
//
"CacheTimeSeconds": 5,
"ExcludedPaths": [
]
}
}

View File

@ -75,13 +75,15 @@
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"Imap": "imap.qiye.aliyun.com",
"ImapPort": 993,
"FromEmail": "test@extimaging.com",
"FromName": "Test_IRC",
"AuthorizationCode": "SHzyyl2021",
"SiteUrl": "http://irc.test.extimaging.com/login",
"OrganizationName": "Extlmaging",
"OrganizationNameCN": "Extlmaging",
"OrganizationName": "ExtImaging",
"OrganizationNameCN": "ExtImaging",
"CompanyName": "Extensive Imaging",
"CompanyNameCN": "上海展影医疗科技有限公司",
"CompanyShortName": "Extensive Imaging",
@ -91,5 +93,12 @@
"SystemPacsConfig": {
"Port": "11113",
"IP": "106.14.89.110"
},
"RequestDuplicationOptions": {
"IsEnabled": true,
"DuplicationWindowMs": 200,
"CacheTimeSeconds": 5,
"ExcludedPaths": [
]
}
}

View File

@ -7,8 +7,8 @@
}
},
"ConnectionStrings": {
"RemoteNew": "Server=us-prod-mssql-service,1433;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=us-prod-mssql-service,1433;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
"RemoteNew": "Server=us-mssql-prod,1433;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=us-mssql-prod,1433;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
//"RemoteNew": "Server=44.210.231.169,1435;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
//"Hangfire": "Server=44.210.231.169,1435;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
},
@ -39,34 +39,40 @@
},
"BasicSystemConfig": {
"OpenUserComplexPassword": false,
"OpenSignDocumentBeforeWork": false,
"OpenTrialRelationDelete": true,
"OpenLoginLimit": false,
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": true,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 60,
"AutoLoginOutMinutes": 120,
"OpenLoginMFA": true,
"ContinuousReadingTimeMin": 120,
"ReadingRestTimeMin": 10,
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90,
// 1 Elevate 2 Extensive
"TemplateType": 1,
"OpenTrialRelationDelete": false,
//MFA
"UserMFAVerifyDays": 1
},
"SystemEmailSendConfig": {
"Port": 587,
"Host": "smtp-mail.outlook.com",
"Imap": "imap-mail.outlook.com",
"ImapPort": 993,
"FromEmail": "donotreply@elevateimaging.ai",
"FromName": "LiLi",
"FromName": "LiLi System",
"AuthorizationCode": "Q#669869497420ul",
"SystemShortName": "LiLi",
"OrganizationName": "Elevate Imaging",
"OrganizationNameCN": "Elevate Imaging",
"CompanyName": "Elevate Imaging Inc.",
@ -75,13 +81,21 @@
"CompanyShortNameCN": "展影医疗",
"SiteUrl": "https://lili.elevateimaging.ai/login",
"IsEnv_US": true,
"IsOpenErrorNoticeEmail": true,
"IsOpenErrorNoticeEmail": false,
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
},
"SystemPacsConfig": {
"Port": "104",
"IP": "44.210.231.169"
},
"RequestDuplicationOptions": {
"IsEnabled": true,
"DuplicationWindowMs": 200,
"CacheTimeSeconds": 5,
"ExcludedPaths": [
]
}
}

View File

@ -64,17 +64,23 @@
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90,
"OpenLoginMFA": true
// 1 Elevate 2 Extensive
"TemplateType": 1,
"OpenLoginMFA": true,
//MFA
"UserMFAVerifyDays": 1
},
"SystemEmailSendConfig": {
"Port": 587,
"Host": "smtp-mail.outlook.com",
"Imap": "imap-mail.outlook.com",
"ImapPort": 993,
"FromEmail": "donotreply@elevateimaging.ai",
"FromName": "LiLi",
"FromName": "LiLi System",
"AuthorizationCode": "Q#669869497420ul",
"SystemShortName": "LiLi",
"OrganizationName": "Elevate Imaging",
"OrganizationNameCN": "Elevate Imaging",
"CompanyName": "Elevate Imaging Inc.",
@ -90,6 +96,13 @@
"SystemPacsConfig": {
"Port": "104",
"IP": "3.226.182.187"
},
"RequestDuplicationOptions": {
"IsEnabled": true,
"DuplicationWindowMs": 200,
"CacheTimeSeconds": 5,
"ExcludedPaths": [
]
}
}

View File

@ -50,50 +50,58 @@
"BasicSystemConfig": {
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": true,
"OpenTrialRelationDelete": true,
"OpenLoginLimit": false,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 60,
"AutoLoginOutMinutes": 120,
"OpenLoginMFA": true,
"ContinuousReadingTimeMin": 120,
"ReadingRestTimeMin": 10,
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90,
"OpenLoginMFA": false
// 1 Elevate 2 Extensive
"TemplateType": 1,
//MFA
"UserMFAVerifyDays": 1
},
"SystemEmailSendConfig": {
"Port": 587,
"Host": "smtp-mail.outlook.com",
"Imap": "imap-mail.outlook.com",
"ImapPort": 993,
"FromEmail": "donotreply@elevateimaging.ai",
"FromName": "LiLi",
"FromName": "LiLi System",
"AuthorizationCode": "Q#669869497420ul",
"SystemShortName": "LiLi",
"OrganizationName": "Elevate Imaging",
"OrganizationNameCN": "Elevate Imaging",
"CompanyName": "Elevate Imaging Inc.",
"CompanyNameCN": "上海展影医疗科技有限公司",
"CompanyShortName": "Elevate Imaging",
"CompanyShortNameCN": "展影医疗",
"SiteUrl": "https://lili.test.elevateimaging.ai/login",
"SiteUrl": "https://lili.uat.elevateimaging.ai/login",
"IsEnv_US": true,
"IsOpenErrorNoticeEmail": false,
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
},
"SystemPacsConfig": {
"Port": "104",
"IP": "3.226.182.187"
},
"RequestDuplicationOptions": {
"IsEnabled": true,
"DuplicationWindowMs": 200,
"CacheTimeSeconds": 5,
"ExcludedPaths": [
]
}
}

View File

@ -56,45 +56,60 @@
"BasicSystemConfig": {
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": true,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 60,
"AutoLoginOutMinutes": 120,
"OpenLoginMFA": false,
"ContinuousReadingTimeMin": 120,
"ReadingRestTimeMin": 10,
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90,
// 1 Elevate 2 Extensive
"TemplateType": 2,
//MFA
"UserMFAVerifyDays": 1
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"Imap": "imap.qiye.aliyun.com",
"ImapPort": 993,
"FromEmail": "uat@extimaging.com",
"FromName": "UAT_IRC",
"FromName": "Uat IRC Imaging System",
"AuthorizationCode": "SHzyyl2021",
"SiteUrl": "http://irc.uat.extimaging.com/login",
"OrganizationName": "Extlmaging",
"OrganizationNameCN": "Extlmaging",
"SystemShortName": "IRC",
"OrganizationName": "ExtImaging",
"OrganizationNameCN": "ExtImaging",
"CompanyName": "Extensive Imaging",
"CompanyNameCN": "上海展影医疗科技有限公司",
"CompanyShortName": "Extensive Imaging",
"CompanyShortNameCN": "展影医疗",
"IsEnv_US": false,
"IsOpenErrorNoticeEmail": false,
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
},
"SystemPacsConfig": {
"Port": "11113",
"IP": "47.117.164.182"
"IP": "101.132.253.119"
},
"RequestDuplicationOptions": {
"IsEnabled": true,
"DuplicationWindowMs": 200,
"CacheTimeSeconds": 5,
"ExcludedPaths": [
]
}
}

View File

@ -3,7 +3,7 @@
"SecurityKey": "ShangHaiZhanYing_SecurityKey_SHzyyl@2021",
"Issuer": "Extimaging",
"Audience": "EICS",
"TokenExpireDays": "7"
"TokenExpireMinute": "10080"//7
},
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
@ -74,5 +74,12 @@
"redirect_uri": "https://oauthlogin.net/oauth/githubcallback",
"scope": "repo"
}
},
"RequestDuplicationOptions": {
"IsEnabled": true,
"DuplicationWindowMs": 200,
"CacheTimeSeconds": 5,
"ExcludedPaths": [
]
}
}

View File

@ -268,12 +268,12 @@ var abp = abp || {};
}
function loginUserInternal(tenantId, callback) {
var usernameOrEmailAddress = document.getElementById('userName').value;
if (!usernameOrEmailAddress) {
alert('UserName Can Not Be Null');
return false;
}
// if (!usernameOrEmailAddress) {
// alert('UserName Can Not Be Null');
// return false;
// }
var password = document.getElementById('password').value;
var pwdMd5 = document.getElementById('pwdMd5').value;
@ -286,12 +286,12 @@ var abp = abp || {};
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
debugger;
// debugger;
if (xhr.status === 200) {
debugger;
// debugger;
var resultdata = JSON.parse(xhr.responseText);
if (resultdata.ErrorMessage != '') {
alert(resultdata.ErrorMessage);
@ -303,18 +303,23 @@ var abp = abp || {};
else {
var responseJSON = JSON.parse(xhr.responseText);
var result = responseJSON;
var expireDate = new Date(Date.now() + (60*60*24 * 1000));
var expireDate = new Date(Date.now() + (60 * 60 * 24 * 1000));
abp.auth.setToken(result.Result.JWTStr, expireDate);
callback();
let selectDom = document.getElementById("roleSelect")
selectDom.options.length = 0;
result.Result.BasicInfo.AccountList.forEach(item => {
selectDom.options.add(new Option(item.UserTypeShortName, item.Id));
})
// callback();
}
} else {
alert('Login failed !');
}
}
};
xhr.open('POST', '/user/login', true);
xhr.open('POST', '/User/getUserLoginRoleList', true);
xhr.setRequestHeader('Abp.TenantId', tenantId);
xhr.setRequestHeader('Content-type', 'application/json');
var parm = {
@ -330,7 +335,63 @@ var abp = abp || {};
//xhr.send("{" + "userName:'" + usernameOrEmailAddress + "'," + "passWord:'" + password + "'}");
};
function loginUserInternalRole(tenantId, callback) {
var usernameOrEmailAddress = document.getElementById('roleSelect').value;
//if (!usernameOrEmailAddress) {
// alert('UserName Can Not Be Null');
// return false;
//}
var password = document.getElementById('password').value;
var pwdMd5 = document.getElementById('pwdMd5').value;
console.log(pwdMd5);
if (!password && !pwdMd5) {
alert('PassWord And Md5 Can Not Be Null');
return false;
}
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
// debugger;
if (xhr.status === 200) {
// debugger;
var resultdata = JSON.parse(xhr.responseText);
if (resultdata.ErrorMessage != '') {
alert(resultdata.ErrorMessage);
return false;
}
if (resultdata.code == 300) {
alert(resultdata.message);
}
else {
var responseJSON = JSON.parse(xhr.responseText);
var result = responseJSON;
var expireDate = new Date(Date.now() + (60 * 60 * 24 * 1000));
abp.auth.setToken(result.Result, expireDate);
callback();
}
} else {
alert('Login failed !');
}
}
};
xhr.open('get', `/User/loginSelectUserRole?userRoleId=${usernameOrEmailAddress}`, true);
xhr.setRequestHeader('Abp.TenantId', tenantId);
xhr.setRequestHeader('Content-type', 'application/json');
var authToken = abp.auth.getToken();
xhr.setRequestHeader('Authorization', `Bearer ${authToken}`);
xhr.send();
//xhr.send("{" + "userName:'" + usernameOrEmailAddress + "'," + "passWord:'" + password + "'}");
};
abp.swagger.login = function (callback) {
//Get TenantId first
var tenancyName = document.getElementById('tenancyName').value;
@ -356,6 +417,31 @@ var abp = abp || {};
loginUserInternal(null, callback); // Login for host
}
};
abp.swagger.loginRole = function (callback) {
//Get TenantId first
var tenancyName = document.getElementById('tenancyName').value;
if (tenancyName) {
var xhrTenancyName = new XMLHttpRequest();
xhrTenancyName.onreadystatechange = function () {
if (xhrTenancyName.readyState === XMLHttpRequest.DONE && xhrTenancyName.status === 200) {
var responseJSON = JSON.parse(xhrTenancyName.responseText);
var result = responseJSON.result;
if (result.state === 1) { // Tenant exists and active.
loginUserInternalRole(result.tenantId, callback); // Login for tenant
} else {
alert('There is no such tenant or tenant is not active !');
}
}
};
xhrTenancyName.open('POST', '/api/services/app/Account/IsTenantAvailable', true);
xhrTenancyName.setRequestHeader('Content-type', 'application/json');
xhrTenancyName.send("{" + "tenancyName:'" + tenancyName + "'}");
} else {
loginUserInternalRole(null, callback); // Login for host
}
};
abp.swagger.logout = function () {
abp.auth.clearToken();
@ -419,9 +505,10 @@ var abp = abp || {};
//Inputs
createInput(modalUxContent, 'tenancyName', 'Tenancy Name (Leave empty for Host)');
createInput(modalUxContent, 'userName', 'Username or email address','text','cyldev');
createInput(modalUxContent, 'userName', 'Username or email address', 'text', 'cyldev');
createInput(modalUxContent, 'password', 'Password', 'password', '123456');
createInput(modalUxContent, 'pwdMd5', 'PwdMd5', 'text', '');
createSelect(modalUxContent, 'roleSelect', 'role', [])
//Buttons
var authBtnWrapper = document.createElement('div');
@ -444,9 +531,18 @@ var abp = abp || {};
abp.swagger.login(loginCallback);
};
authBtnWrapper.appendChild(authorizeButton);
// login role
var authorizeButton = document.createElement('button');
authorizeButton.className = 'btn modal-btn auth authorize button';
authorizeButton.innerText = 'LoginRole';
authorizeButton.onclick = function () {
abp.swagger.loginRole(loginCallback);
};
authBtnWrapper.appendChild(authorizeButton);
}
function createInput(container, id, title, type, value="") {
function createInput(container, id, title, type, value = "") {
var wrapper = document.createElement('div');
wrapper.className = 'wrapper';
if (id == "tenancyName") {
@ -470,6 +566,31 @@ var abp = abp || {};
input.autocomplete = "off";
section.appendChild(input);
}
function createSelect(container, id, title, option = []) {
var wrapper = document.createElement('div');
wrapper.className = 'wrapper';
if (id == "tenancyName") {
wrapper.style.display = 'none';
}
container.appendChild(wrapper);
var label = document.createElement('label');
label.innerText = title;
wrapper.appendChild(label);
var section = document.createElement('section');
section.className = 'block-tablet col-10-tablet block-desktop col-10-desktop';
wrapper.appendChild(section);
var input = document.createElement('select');
input.id = id;
input.style.width = '100%';
option.forEach(item => {
input.options.add(new Option(item.UserTypeShortName, item.Id));
})
section.appendChild(input);
}

View File

@ -1,46 +0,0 @@
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Domain.Share;
namespace IRaCIS.Core.Application.Auth
{
public class IRaCISClaims
{
public Guid Id { get; set; }
public string FullName { get; set; } = String.Empty;
public string Code { get; set; } = String.Empty;
public string RealName { get; set; } = String.Empty;
public string UserTypeShortName { get; set; } = String.Empty;
public UserTypeEnum UserTypeEnum { get; set; }
public string PermissionStr { get; set; } = String.Empty;
public Guid UserTypeId { get; set; }
public int IsAdmin { get; }
public bool IsTestUser { get; set; }
public bool IsZhiZhun { get; set; }
public string Phone { get; set; } = String.Empty;
public static IRaCISClaims Create(UserBasicInfo user)
{
return new IRaCISClaims
{
Id = user.Id,
FullName = user.UserName,
RealName = user.RealName,
UserTypeEnum = user.UserTypeEnum,
UserTypeId = user.UserTypeId,
IsTestUser = user.IsTestUser,
Code = user.Code,
PermissionStr = user.PermissionStr,
IsZhiZhun = user.IsZhiZhun,
UserTypeShortName = user.UserTypeShortName
};
}
}
}

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; }

View File

@ -8,7 +8,9 @@ namespace IRaCIS.Core.Application.Auth
public interface ITokenService
{
string GetToken(IRaCISClaims user);
string GetToken(UserTokenInfo user);
bool IsTokenExpired(string token);
}
@ -21,16 +23,16 @@ namespace IRaCIS.Core.Application.Auth
_jwtSetting = option.Value;
}
public string GetToken(IRaCISClaims user)
public string GetToken(UserTokenInfo user)
{
//创建用户身份标识,可按需要添加更多信息
var claims = new Claim[]
{
new Claim(Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtIRaCISClaimType.Id, user.Id.ToString()),
new Claim(JwtIRaCISClaimType.Name, user.FullName),
new Claim(JwtIRaCISClaimType.RealName, user.RealName),
new Claim(JwtIRaCISClaimType.Code,user.Code),
new Claim(JwtIRaCISClaimType.IdentityUserId, user.IdentityUserId.ToString()),
new Claim(JwtIRaCISClaimType.UserRoleId, user.UserRoleId.ToString()),
new Claim(JwtIRaCISClaimType.UserName, user.UserName),
new Claim(JwtIRaCISClaimType.FullName, user.FullName),
new Claim(JwtIRaCISClaimType.UserTypeId,user.UserTypeId.ToString()),
new Claim(JwtIRaCISClaimType.UserTypeEnum,user.UserTypeEnum.ToString()),
new Claim(JwtIRaCISClaimType.UserTypeEnumInt,((int)user.UserTypeEnum).ToString()),
@ -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 也视为已过期
}
}
}

View File

@ -0,0 +1,27 @@
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Domain.Share;
namespace IRaCIS.Core.Application.Auth
{
public class UserTokenInfo
{
public Guid IdentityUserId { get; set; }
public Guid UserRoleId { get; set; }
public Guid UserTypeId { get; set; }
public UserTypeEnum UserTypeEnum { get; set; }
public string UserName { get; set; } = string.Empty;
public string FullName { get; set; } = string.Empty;
public string PermissionStr { get; set; } = string.Empty;
public bool IsTestUser { get; set; }
public bool IsZhiZhun { get; set; }
public string UserTypeShortName { get; set; } = string.Empty;
}
}

View File

@ -48,7 +48,7 @@ public class LimitUserRequestAuthorization(
//2、在这里取缓存 进行比较 看是否有其他人进行了登陆,如果其他人登陆了,就把之前用户挤掉
var cacheUserToken = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserToken(_userInfo.Id));
var cacheUserToken = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserToken(_userInfo.IdentityUserId));
@ -58,17 +58,17 @@ public class LimitUserRequestAuthorization(
cacheUserToken = _userInfo.UserToken;
//设置当前用户最新Token
await _fusionCache.SetAsync(CacheKeys.UserToken(_userInfo.Id), _userInfo.UserToken, TimeSpan.FromDays(7));
await _fusionCache.SetAsync(CacheKeys.UserToken(_userInfo.IdentityUserId), _userInfo.UserToken, TimeSpan.FromDays(7));
//重启应用程序,所有人续期,不一下子踢出所有人
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.Id), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.IdentityUserId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
}
//是同一个人
else if (cacheUserToken == _userInfo.UserToken)
{
var cacheTime = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserAutoLoginOut(_userInfo.Id));
var cacheTime = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserAutoLoginOut(_userInfo.IdentityUserId));
//过期了 需要自动退出
if (string.IsNullOrEmpty(cacheTime))
@ -80,7 +80,7 @@ public class LimitUserRequestAuthorization(
}
else
{
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.Id), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.IdentityUserId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
}
}
else
@ -93,6 +93,21 @@ public class LimitUserRequestAuthorization(
}
//用户或者角色禁用,那么操作的人退出
var isDisable = await _fusionCache.GetOrDefaultAsync<bool>(CacheKeys.UserDisable(_userInfo.IdentityUserId),false);
var isRoleDisable = await _fusionCache.GetOrDefaultAsync<bool>(CacheKeys.UserRoleDisable(_userInfo.UserRoleId),false);
if (isDisable == true || isRoleDisable == true)
{
context.HttpContext.Response.ContentType = "application/json";
context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
// 用户或者角色被禁用。
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["LimitUser_AccountOrRoleDisable"], ApiResponseCodeEnum.AutoLoginOut));
}
}
}

View File

@ -0,0 +1,137 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.BusinessFilter.LegacyController
{
using Database.Api;
using DocumentFormat.OpenXml.InkML;
using IRaCIS.Core.Application.Service.Common;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Components.Endpoints;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Minio.Helper;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace Database.Api
{
/// <summary>
/// 请求拦截 请求前后的操作
/// </summary>
/// <param name="logger">logger</param>
/// <param name="accessor">loggerHelper</param>
public class RequestDuplicationFilter(ILogger<RequestDuplicationFilter> logger, IHttpContextAccessor accessor, IUserInfo _userInfo, IStringLocalizer _localizer, IOptionsMonitor<RequestDuplicationOptions> RequestDuplicationOptionsMonitor) : ExceptionFilterAttribute, IAsyncActionFilter
{
/// <summary>
/// 传入的参数
/// </summary>
public string Intoparam { get; set; }
/// <summary>
/// 这个是正常记录(请求刚进入的时候)
/// </summary>
/// <param name="context">context</param>
/// <param name="next">next</param>
/// <returns>返回的对象</returns>
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
if (RequestDuplicationOptionsMonitor.CurrentValue.IsEnabled)
{
Dictionary<string, object?> dic = new Dictionary<string, object?>();
var desc = context.ActionDescriptor as ControllerActionDescriptor;
foreach (var p in desc.Parameters)
{
// 关键判断:绑定源是否是 Services
if (p.BindingInfo?.BindingSource == BindingSource.Services) continue;
// 普通参数,取值
if (context.ActionArguments.TryGetValue(p.Name, out var value) && value != null)
{
dic.Add(p.Name, value);
}
}
this.Intoparam = JsonConvert.SerializeObject(dic);
try
{
this.RequestDuplication();
}
catch (Exception)
{
}
}
var resultContext = await next();
}
/// <summary>
///
/// </summary>
private void RequestDuplication()
{
var requestPath = accessor?.HttpContext?.Request?.Path.ToString() ?? string.Empty;
// 验证请求频繁情况
if (
!requestPath
.Split("/", StringSplitOptions.RemoveEmptyEntries)
.Any(segment => segment.StartsWith("get", StringComparison.OrdinalIgnoreCase)) &&
_userInfo.UserRoleId != default(Guid)&&
RequestDuplicationOptionsMonitor.CurrentValue.IsEnabled &&
!RequestDuplicationOptionsMonitor.CurrentValue.ExcludePaths.Contains(requestPath))
{
RequestInfo requestInfo = new RequestInfo
{
UserRoleId = _userInfo.UserRoleId,
RequestPath = requestPath,
ParameterHash = GenerateParameterHash(this.Intoparam),
RequestTime = DateTime.Now
};
IRCSystemInfo.RequestRecordList= IRCSystemInfo.RequestRecordList.Where(x => x.RequestTime >= DateTime.Now.AddSeconds(-RequestDuplicationOptionsMonitor.CurrentValue.CacheTimeSeconds)).ToList();
var requestsTimes = IRCSystemInfo.RequestRecordList.Any(x=>
x.RequestTime>= requestInfo.RequestTime.AddMilliseconds(-RequestDuplicationOptionsMonitor.CurrentValue.DuplicationWindowMs)&&
x.RequestKey== requestInfo.RequestKey);
if (requestsTimes)
{
throw new BusinessValidationFailedException(_localizer["RequestDuplicationFilter_RequestDuplication"], ApiResponseCodeEnum.BusinessValidationFailed);
}
IRCSystemInfo.RequestRecordList.Add(requestInfo);
}
}
public string GenerateParameterHash(string parameters)
{
if (string.IsNullOrEmpty(parameters))
return string.Empty;
using var sha256 = SHA256.Create();
var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(parameters));
return Convert.ToBase64String(hashBytes);
}
}
}
}

View File

@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace IRaCIS.Core.Application.Service.BusinessFilter;

View File

@ -41,19 +41,19 @@ public class LimitUserRequestAuthorizationEndpointFilter(
}
// 获取缓存中的用户 token
var cacheUserToken = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserToken(_userInfo.Id));
var cacheUserToken = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserToken(_userInfo.IdentityUserId));
// 缓存中没有取到 token
if (string.IsNullOrWhiteSpace(cacheUserToken))
{
// 设置当前用户最新 token
await _fusionCache.SetAsync(CacheKeys.UserToken(_userInfo.Id), _userInfo.UserToken, TimeSpan.FromDays(7));
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.Id), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
await _fusionCache.SetAsync(CacheKeys.UserToken(_userInfo.IdentityUserId), _userInfo.UserToken, TimeSpan.FromDays(7));
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.IdentityUserId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
}
// 如果是同一个用户
else if (cacheUserToken == _userInfo.UserToken)
{
var cacheTime = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserAutoLoginOut(_userInfo.Id));
var cacheTime = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserAutoLoginOut(_userInfo.IdentityUserId));
// 如果过期,自动登出
if (string.IsNullOrEmpty(cacheTime))
@ -63,7 +63,7 @@ public class LimitUserRequestAuthorizationEndpointFilter(
}
else
{
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.Id), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.IdentityUserId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
}
}
else

View File

@ -34,8 +34,12 @@ public class ServiceVerifyConfigOption
[Description("修改密码的天数")]
public int ChangePassWordDays { get; set; }
public SysTemplateType TemplateType { get; set; }
public string ThirdPdfUrl { get; set; }
public int UserMFAVerifyMinutes { get; set; } = 1440;
}
public class SystemEmailSendConfig
@ -43,6 +47,10 @@ public class SystemEmailSendConfig
public int Port { get; set; }
public string Host { get; set; } = string.Empty;
public string Imap { get; set; } = string.Empty;
public int ImapPort { get; set; }
public string FromEmail { get; set; } = string.Empty;
public string FromName { get; set; } = string.Empty;
@ -51,6 +59,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;
@ -66,11 +76,14 @@ public class SystemEmailSendConfig
public bool IsOpenErrorNoticeEmail { get; set; }
public List<string> ErrorNoticeEmailList { get; set; } =new List<string>();
public string EmailRegexStr { get; set; }
public List<string> ErrorNoticeEmailList { get; set; } = new List<string>();
}
public class SystemEmailSendConfigView
{
public string SystemShortName { get; set; } = string.Empty;
public string CompanyName { get; set; } = string.Empty;
public string CompanyNameCN { get; set; } = string.Empty;
@ -78,6 +91,8 @@ public class SystemEmailSendConfigView
public string CompanyShortName { get; set; } = string.Empty;
public string CompanyShortNameCN { get; set; } = string.Empty;
public string EmailRegexStr { get; set; }
}
public class SystemPacsConfig
@ -96,6 +111,54 @@ public class IRCEncreptOption
public List<string> ApiPathList { get; set; }
}
/// <summary>
/// 请求缓存配置
/// </summary>
public class RequestDuplicationOptions
{
/// <summary>
/// 缓存时间默认5秒
/// </summary>
public int CacheTimeSeconds { get; set; } = 5;
/// <summary>
/// 重复请求检测时间窗口毫秒默认500毫秒
/// </summary>
public int DuplicationWindowMs { get; set; } = 500;
/// <summary>
/// 是否启用防重复请求
/// </summary>
public bool IsEnabled { get; set; } = true;
/// <summary>
/// 需要排除的路径(不进行重复检测)
/// </summary>
public List<string> ExcludePaths { get; set; } = new List<string>();
}
public static class IRCSystemInfo
{
public static List<RequestInfo> RequestRecordList { get; set; } = new List<RequestInfo>();
}
public class RequestInfo
{
public Guid UserRoleId { get; set; }
public string RequestPath { get; set; } = string.Empty;
public string ParameterHash { get; set; } = string.Empty;
public DateTime RequestTime { get; set; }
/// <summary>
/// 请求的唯一标识
/// </summary>
public string RequestKey => $"{UserRoleId}_{RequestPath}_{ParameterHash}";
}
public class IRaCISBasicConfigOption
{
public string DoctorCodePrefix { get; set; }
@ -140,7 +203,7 @@ public static class AppSettings
case nameof(Doctor):
return IRaCISBasicConfig.DoctorCodePrefix + codeInt.ToString("D4");
case nameof(User):
case nameof(IdentityUser):
return IRaCISBasicConfig.UserCodePrefix + codeInt.ToString("D4");
case nameof(QCChallenge):

View File

@ -10,5 +10,7 @@ global using Microsoft.Extensions.Localization;
global using AutoMapper;
global using IRaCIS.Core.Domain.Share;
global using IRaCIS.Core.Application.BusinessFilter;
global using IdentityUser = IRaCIS.Core.Domain.Models.IdentityUser;
global using Serilog;

View File

@ -27,6 +27,11 @@ public static class CacheKeys
//超时没请求接口自动退出
public static string UserAutoLoginOut(Guid userId) => $"UserAutoLoginOut:{userId}";
public static string UserDisable(Guid userId) => $"UserDisable:{userId}";
public static string UserRoleDisable(Guid userRoleId) => $"UserRoleDisable:{userRoleId}";
/// <summary>
/// 用户登录错误 限制登录
/// </summary>
@ -56,6 +61,9 @@ public static class CacheKeys
/// <returns></returns>
public static string StartRestTime(Guid userId) => $"{userId}StartRestTime";
//每个用户 每个浏览器独立时间
public static string UserMFAVerifyPass(Guid userId,string browserFingerprint) => $"UserMFAVerifyPass:{userId}:{browserFingerprint}";
}
public static class CacheHelper

View File

@ -0,0 +1,193 @@
using FellowOakDicom;
using FellowOakDicom.Media;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Helper
{
public class StudyDIRInfo
{
public Guid SubjectId { get; set; }
public bool IsTaskStudy { get; set; }
public Guid SubjectVisitId { get; set; }
// Study
public Guid DicomStudyId { get; set; }
public string PatientId { get; set; }
public string PatientName { get; set; }
public string PatientBirthDate { get; set; }
public string PatientSex { get; set; }
public string StudyInstanceUid { get; set; }
public string StudyId { get; set; }
public string DicomStudyDate { get; set; }
public string DicomStudyTime { get; set; }
public string AccessionNumber { get; set; }
public string StudyDescription { get; set; }
// Series
public string SeriesInstanceUid { get; set; }
public string Modality { get; set; }
public string DicomSeriesDate { get; set; }
public string DicomSeriesTime { get; set; }
public int SeriesNumber { get; set; }
public string SeriesDescription { get; set; }
// Instance
public Guid InstanceId { get; set; }
public string SopInstanceUid { get; set; }
public string SOPClassUID { get; set; }
public int InstanceNumber { get; set; }
public string MediaStorageSOPClassUID { get; set; }
public string MediaStorageSOPInstanceUID { get; set; }
public string TransferSytaxUID { get; set; }
}
public static class DicomDIRHelper
{
public static async Task GenerateStudyDIRAndUploadAsync(List<StudyDIRInfo> list, Dictionary<string, string> dic, string ossFolder, IOSSService _oSSService)
{
var mappings = new List<string>();
int index = 1;
var dicomDir = new DicomDirectory();
foreach (var item in list.OrderBy(t => t.SeriesNumber).ThenBy(t => t.InstanceNumber))
{
var dicomUid = DicomUID.Enumerate().FirstOrDefault(uid => uid.UID == item.TransferSytaxUID);
if (dicomUid != null)
{
var ts = DicomTransferSyntax.Query(dicomUid);
var dataset = new DicomDataset(ts)
{
{ DicomTag.PatientID, item.PatientId ?? string.Empty },
{ DicomTag.PatientName, item.PatientName ?? string.Empty },
{ DicomTag.PatientBirthDate, item.PatientBirthDate ?? string.Empty },
{ DicomTag.PatientSex, item.PatientSex ?? string.Empty },
{ DicomTag.StudyInstanceUID, item.StudyInstanceUid ?? string.Empty },
{ DicomTag.StudyID, item.StudyId ?? string.Empty },
{ DicomTag.StudyDate, item.DicomStudyDate ?? string.Empty },
{ DicomTag.StudyTime, item.DicomStudyTime ?? string.Empty },
{ DicomTag.AccessionNumber, item.AccessionNumber ?? string.Empty },
{ DicomTag.StudyDescription, item.StudyDescription ?? string.Empty },
{ DicomTag.SeriesInstanceUID, item.SeriesInstanceUid ?? string.Empty },
{ DicomTag.Modality, item.Modality ?? string.Empty },
{ DicomTag.SeriesDate, item.DicomSeriesDate ?? string.Empty },
{ DicomTag.SeriesTime, item.DicomSeriesTime ?? string.Empty },
{ DicomTag.SeriesNumber, item.SeriesNumber.ToString() ?? string.Empty },
{ DicomTag.SeriesDescription, item.SeriesDescription ?? string.Empty },
{ DicomTag.SOPInstanceUID, item.SopInstanceUid ?? string.Empty },
{ DicomTag.SOPClassUID, item.SOPClassUID ?? string.Empty },
{ DicomTag.InstanceNumber, item.InstanceNumber.ToString() ?? string.Empty },
{ DicomTag.MediaStorageSOPClassUID, item.MediaStorageSOPClassUID ?? string.Empty },
{ DicomTag.MediaStorageSOPInstanceUID, item.MediaStorageSOPInstanceUID ?? string.Empty },
{ DicomTag.TransferSyntaxUID, item.TransferSytaxUID ?? string.Empty },
};
var dicomFile = new DicomFile(dataset);
// 文件名递增格式IM_00001, IM_00002, ...
string filename = $@"IMAGE/IM_{index:D5}"; // :D5 表示补足5位
mappings.Add($"{filename} => {item.InstanceId}");
dic.Add(item.InstanceId.ToString(), Path.GetFileName(filename));
dicomDir.AddFile(dicomFile, filename);
index++;
}
}
//有实际的文件
if (mappings.Count > 0)
{
#region 写入临时路径
var tempFilePath = Path.GetTempFileName();
// 保存 DICOMDIR 到临时文件 不能直接写入到流种
await dicomDir.SaveAsync(tempFilePath);
using (var memoryStream = new MemoryStream(File.ReadAllBytes(tempFilePath)))
{
// 重置流位置
memoryStream.Position = 0;
await _oSSService.UploadToOSSAsync(memoryStream, ossFolder, "DICOMDIR", false);
}
//清理临时文件
File.Delete(tempFilePath);
#endregion
#region 映射上传
// 将映射写入内存流
var mappingText = string.Join(Environment.NewLine, mappings);
await using var mappingStream = new MemoryStream(Encoding.UTF8.GetBytes(mappingText));
await _oSSService.UploadToOSSAsync(mappingStream, ossFolder, $"Download_{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}", false);
#endregion
}
}
public static StudyDIRInfo ReadDicomDIRInfo(DicomFile dicomFile)
{
var dataset = dicomFile.Dataset;
var info = new StudyDIRInfo
{
PatientId = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
StudyInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty),
StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty),
DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty),
AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),
StudyDescription = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
SeriesInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty),
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty),
DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty),
SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
SeriesDescription = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
SopInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty),
SOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty),
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
MediaStorageSOPClassUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty),
MediaStorageSOPInstanceUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty),
TransferSytaxUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty)
};
return info;
}
}
}

View File

@ -1,4 +1,7 @@
namespace IRaCIS.Core.Application.Helper;
using System.Globalization;
using System.Text.RegularExpressions;
namespace IRaCIS.Core.Application.Helper;
public static class IRCEmailPasswordHelper
{
@ -74,4 +77,56 @@ public static class IRCEmailPasswordHelper
// 随机打乱密码字符顺序
return new string(password.OrderBy(_ => Random.Next()).ToArray());
}
// https://learn.microsoft.com/zh-cn/dotnet/standard/base-types/how-to-verify-that-strings-are-in-valid-email-format
/// <summary>
/// 微软官方邮件验证 很宽松
/// </summary>
/// <param name="email"></param>
/// <returns></returns>
public static bool IsValidEmail(string email)
{
if (string.IsNullOrWhiteSpace(email))
return false;
try
{
// Normalize the domain
email = Regex.Replace(email, @"(@)(.+)$", DomainMapper,
RegexOptions.None, TimeSpan.FromMilliseconds(200));
// Examines the domain part of the email and normalizes it.
string DomainMapper(Match match)
{
// Use IdnMapping class to convert Unicode domain names.
var idn = new IdnMapping();
// Pull out and process domain name (throws ArgumentException on invalid)
string domainName = idn.GetAscii(match.Groups[2].Value);
return match.Groups[1].Value + domainName;
}
}
catch (RegexMatchTimeoutException e)
{
return false;
}
catch (ArgumentException e)
{
return false;
}
try
{
return Regex.IsMatch(email,
@"^[^@\s]+@[^@\s]+\.[^@\s]+$",
RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250));
}
catch (RegexMatchTimeoutException)
{
return false;
}
}
}

View File

@ -2,6 +2,7 @@
using MailKit;
using MailKit.Security;
using MimeKit;
using Org.BouncyCastle.Tls;
namespace IRaCIS.Core.Application.Helper;
@ -9,8 +10,17 @@ namespace IRaCIS.Core.Application.Helper;
public static class SendEmailHelper
{
public static async Task SendEmailAsync(MimeMessage messageToSend, SystemEmailSendConfig _systemEmailConfig, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
public static async Task<string> SendEmailAsync(MimeMessage messageToSend, SystemEmailSendConfig _systemEmailConfig, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
{
string result = string.Empty;
result = messageToSend.MessageId;
//没有收件人 那么不发送
if (messageToSend.To.Count == 0)
{
return string.Empty;
}
try
{
using (var smtp = new MailKit.Net.Smtp.SmtpClient())
@ -36,6 +46,7 @@ public static class SendEmailHelper
await smtp.DisconnectAsync(true);
}
}
catch (Exception ex)
@ -45,7 +56,76 @@ public static class SendEmailHelper
throw new Exception(I18n.T("SendEmail_SendFail"), new Exception(ex.Message));
}
return result;
}
public static async Task<string> SendEmailAsync(MimeMessage messageToSend, Trial trial, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
{
// 项目的需要重设 发件地址与邮件地址
var fromAddress = messageToSend.From.Mailboxes.FirstOrDefault();
if (fromAddress != null)
{
messageToSend.From.Clear();
messageToSend.From.Add(new MailboxAddress(trial.EmailFromName, trial.EmailSMTPServerAddress));
}
string result = string.Empty;
result = messageToSend.MessageId;
//没有收件人 那么不发送
if (messageToSend.To.Count == 0)
{
return string.Empty;
}
try
{
using (var smtp = new MailKit.Net.Smtp.SmtpClient())
{
if (messageSentSuccess != null)
{
smtp.MessageSent += messageSentSuccess;
}
smtp.ServerCertificateValidationCallback = (s, c, h, e) => true;
//await smtp.ConnectAsync("smtp.qq.com", 465, SecureSocketOptions.SslOnConnect);
//await smtp.AuthenticateAsync("zhou941003@qq.com", "sqfhlpfdvnexbcab");
//await smtp.ConnectAsync(_systemEmailConfig.Host, _systemEmailConfig.Port, SecureSocketOptions.Auto);
//await smtp.AuthenticateAsync(_systemEmailConfig.FromEmail, _systemEmailConfig.AuthorizationCode);
await smtp.ConnectAsync(trial.EmailSMTPServerAddress, trial.EmailSMTPServerPort, SecureSocketOptions.Auto);
await smtp.AuthenticateAsync(trial.EmailFromEmail, trial.EmailAuthorizationCode);
await smtp.SendAsync(messageToSend);
await smtp.DisconnectAsync(true);
}
}
catch (Exception ex)
{
//---邮件发送失败,您进行的操作未能成功,请检查邮箱或联系维护人员
throw new Exception(I18n.T("SendEmail_SendFail"), new Exception(ex.Message));
}
return result;
}
public static async Task<bool> TestEmailConfigAsync(SystemEmailSendConfig _systemEmailConfig)
@ -67,7 +147,7 @@ public static class SendEmailHelper
return true;
}
public static async Task SendEmailAsync(SMTPEmailConfig sMTPEmailConfig, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
public static async Task SendEmailAsync(SMTPEmailConfig sMTPEmailConfig,Trial? trial, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
{
var messageToSend = new MimeMessage();
@ -137,7 +217,7 @@ public static class SendEmailHelper
await smtp.ConnectAsync(sMTPEmailConfig.Host, sMTPEmailConfig.Port, SecureSocketOptions.Auto);
await smtp.AuthenticateAsync(sMTPEmailConfig.UserName, sMTPEmailConfig.AuthorizationCode);
await smtp.AuthenticateAsync(trial.EmailFromEmail, trial.EmailAuthorizationCode);
await smtp.SendAsync(messageToSend);

View File

@ -60,4 +60,16 @@ namespace IRaCIS.Core.Application.Helper
}
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class DateTimeTranaslateAttribute : Attribute
{
public string Formart { get; set; }
public DateTimeTranaslateAttribute(string formart)
{
Formart = formart;
}
}
}

View File

@ -1,15 +1,19 @@
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Wordprocessing;
using FellowOakDicom.Imaging.LUT;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore.Migrations;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
using MiniExcelLibs;
using MiniExcelLibs.OpenXml;
using Newtonsoft.Json;
using NPOI.HSSF.UserModel;
using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
@ -64,7 +68,7 @@ public static class ExcelExportHelper
foreach (var key in dic.Keys)
{
//是数组 那么找到对应的属性 进行翻译
if (dic[key]!=null && dic[key].GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>)))
if (dic[key] != null && dic[key].GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>)))
{
var newObjList = new List<object>();
@ -243,6 +247,7 @@ public static class ExcelExportHelper
}
public class DynamicColumnConfig
{
/// <summary>
@ -255,13 +260,19 @@ public static class ExcelExportHelper
/// </summary>
public int AutoColumnTitleRowIndex { get; set; }
/// <summary>
/// 模板列最后的索引
/// </summary>
public int TempalteLastColumnIndex { get; set; }
public bool IsCDISCExport { get; set; } = false;
//public List<string> CDISCList { get; set; } = new List<string>();
/// <summary>
/// 动态的列名
/// 动态的列名 如果Id 重复那么就按照名称填充否则就按照Id 填充列数据
/// </summary>
public List<string> ColumnNameList { get; set; } = new List<string>();
public List<ColumItem> ColumnIdNameList { get; set; }
/// <summary>
/// 动态翻译的字典名
@ -288,7 +299,31 @@ public static class ExcelExportHelper
/// </summary>
public string DynamicItemTitleName { get; set; }
public string DynamicItemTitleId { get; set; }
public List<int> RemoveColunmIndexList { get; set; } = new List<int>();
public class ColumItem
{
public Guid Id { get; set; }
public string Name { get; set; }
public string CDISCCode { 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();
public List<string> ColumnNameList => ColumnIdNameList == null ? new List<string>() : ColumnIdNameList.Select(t => t.Name).ToList();
}
@ -421,7 +456,7 @@ public static class ExcelExportHelper
workbook.RemoveSheetAt(1);
}
//中文替换项目术语
#region 中文替换项目术语
if (data.TrialObjectNameList?.Count > 0)
{
var replaceObjectList = data.TrialObjectNameList;
@ -457,21 +492,414 @@ public static class ExcelExportHelper
}
}
}
#endregion
if (dynamicColumnConfig != null)
{
//var isCdics = dynamicColumnConfig.CDISCList.Count > 0;
var isCdics = dynamicColumnConfig.IsCDISCExport;
var sheet = workbook.GetSheetAt(0);
var cdicsRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex - 1);
var titelRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex);
var templateRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex + 1);
//动态移除列的数量
var dynamicRemoveColunmCount = dynamicColumnConfig.RemoveColunmIndexList.Count();
//在动态列开始前移除的数量
var beforeDynamicRemoveCount = dynamicColumnConfig.RemoveColunmIndexList.Where(t => t < dynamicColumnConfig.AutoColumnStartIndex).Count();
//动态添加列的数量
var needAddCount = dynamicColumnConfig.ColumnNameList.Count;
var needAddCount = dynamicColumnConfig.ColumnIdNameList.Count;
//原始表 最终索引
var originTotalEndIndex = dynamicColumnConfig.TempalteLastColumnIndex;
//减去动态移除后原始结束索引
var originRemoveEndIndex = originTotalEndIndex - dynamicRemoveColunmCount;
//最终表 动态列开始索引
var dynamicColunmStartIndex = dynamicColumnConfig.AutoColumnStartIndex - beforeDynamicRemoveCount;
//最终表 动态列的终止索引
var dynamicColunmEndIndex = dynamicColunmStartIndex + needAddCount - 1;
//最终表 最终索引
var totalColunmEndIndex = originTotalEndIndex + needAddCount - dynamicRemoveColunmCount;
//动态列后需要移动的数量
var backMoveCount = totalColunmEndIndex - dynamicColunmEndIndex;
//删除需要动态删除的列 从大到小移除,否则索引会变
foreach (var removeIndex in dynamicColumnConfig.RemoveColunmIndexList.OrderByDescending(t => t))
{
//将后面的列向前移动
for (var i = 0; i < originTotalEndIndex - removeIndex; i++)
{
Console.WriteLine(titelRow.GetCell(removeIndex + i + 1).StringCellValue);
titelRow.GetCell(removeIndex + i).SetCellValue(titelRow.GetCell(removeIndex + i + 1).StringCellValue);
templateRow.GetCell(removeIndex + i).SetCellValue(templateRow.GetCell(removeIndex + i + 1).StringCellValue);
//后面的数据要清空
titelRow.GetCell(removeIndex + i + 1).SetCellValue("");
templateRow.GetCell(removeIndex + i + 1).SetCellValue("");
}
}
//创建新的列
for (int i = originRemoveEndIndex; i < originRemoveEndIndex + needAddCount; i++)
{
titelRow.CreateCell(i + 1);
templateRow.CreateCell(i + 1);
if (isCdics)
{
cdicsRow.CreateCell(i + 1);
}
}
//移动Title 和下面的模板标识
var gap = totalColunmEndIndex - originRemoveEndIndex;
for (int i = totalColunmEndIndex; i > dynamicColunmEndIndex; i--)
{
titelRow.GetCell(i).SetCellValue(titelRow.GetCell(i - gap).StringCellValue);
templateRow.GetCell(i).SetCellValue(templateRow.GetCell(i - gap).StringCellValue);
if (isCdics)
{
cdicsRow.GetCell(i).SetCellValue(cdicsRow.GetCell(i - gap).StringCellValue);
}
}
//设置动态Tilte
for (int i = dynamicColunmStartIndex; i < dynamicColunmStartIndex + needAddCount; i++)
{
var name = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].Name;
titelRow.GetCell(i).SetCellValue(name);
templateRow.GetCell(i).SetCellValue("");
if (isCdics)
{
var cdicsCode = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].CDISCCode;
cdicsRow.GetCell(i).SetCellValue(cdicsCode);
}
}
}
using (var memoryStream2 = new MemoryStream())
{
workbook.Write(memoryStream2, true);
memoryStream2.Seek(0, SeekOrigin.Begin);
templateStream = memoryStream2;
}
}
#endregion
#region MiniExcel
var memoryStream = new MemoryStream();
var config = new OpenXmlConfiguration()
{
IgnoreTemplateParameterMissing = true,
};
//await MiniExcel.SaveAsByTemplateAsync("testmini.xlsx", templateStream.ToArray(), translateData);
await MiniExcel.SaveAsByTemplateAsync(memoryStream, templateStream.ToArray(), translateData, config);
memoryStream.Seek(0, SeekOrigin.Begin);
if (dynamicColumnConfig != null)
{
//Excel 列是按照名称填充 还是Id 填充
var isExcelAddDataWithName = dynamicColumnConfig.ColumnIdNameList.Select(t => t.Id).Distinct().Count() == 1;
var dynamicTranslateDataList = await _dictionaryService.GetBasicDataSelect(dynamicColumnConfig.TranslateDicNameList.ToArray());
// 使用NPOI 进行二次处理
var wb = new XSSFWorkbook(memoryStream);
var sheet = wb.GetSheetAt(0);
var list = translatedDic["List"] as IList;
foreach (var itemResult in list)
{
var index = list.IndexOf(itemResult);
//从第四行开始处理动态列
var row = sheet.GetRow(index + dynamicColumnConfig.AutoColumnTitleRowIndex + 1);
var itemDic = itemResult.ToDictionary();
var itemList = itemDic[dynamicColumnConfig.DynamicListName] as IList;
//这个数组是动态的有的多有的少所以在此对比Title 一致才赋值
foreach (var itemObj in itemList)
{
var iteObjDic = itemObj.ToDictionary();
var itemDicName = iteObjDic.ContainsKey(dynamicColumnConfig.DynamicItemDicName) ? iteObjDic[dynamicColumnConfig.DynamicItemDicName]?.ToString() : "";
var itemValue = iteObjDic[dynamicColumnConfig.DynamicItemValueName]?.ToString();
//var writeIndex = itemList.IndexOf(itemObj) + dynamicColumnConfig.AutoColumnStartIndex;
var writeIndex = 0;
if (isExcelAddDataWithName)
{
writeIndex = dynamicColumnConfig.ColumnNameList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleName].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
}
else
{
writeIndex = dynamicColumnConfig.ColumnIdList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleId].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
}
if (itemDicName.IsNotNullOrEmpty())
{
var optionTypeEnumStr = iteObjDic.ContainsKey("OptionTypeEnum") ? iteObjDic["OptionTypeEnum"]?.ToString() : "0";
var translatedItemData = "";
//多选
if (optionTypeEnumStr == "1")
{
int[] enumValues = new int[0];
// 1. 反序列化 JSON 数组 (字符串枚举)
if (!itemValue.StartsWith("[") || !itemValue.EndsWith("]"))
{
enumValues = new int[1] { int.Parse(itemValue) };
}
else
{
enumValues = JsonConvert.DeserializeObject<int[]>(itemValue)?? new int[0];
}
// 2. 翻译每一项并输出逗号拼接字符串
translatedItemData = string.Join(",",
enumValues.Select(code =>
dynamicTranslateDataList[itemDicName]
.FirstOrDefault(t =>
string.Equals(code.ToString(),t.Code, StringComparison.OrdinalIgnoreCase)
) is var r && r != null
? (isEn_US ? r.Value : r.ValueCN)
: string.Empty
));
}
else
{
translatedItemData = dynamicTranslateDataList[itemDicName].Where(t => t.Code.ToLower() == itemValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
}
row.GetCell(writeIndex).SetCellValue(translatedItemData);
}
else
{
row.GetCell(writeIndex).SetCellValue(itemValue);
}
}
}
var memoryStream2 = new MemoryStream();
wb.Write(memoryStream2, true);
memoryStream2.Seek(0, SeekOrigin.Begin);
memoryStream = memoryStream2;
}
return (memoryStream, fileName);
#endregion
}
/// <summary>
/// 暂时废弃--合并到上面
/// </summary>
/// <param name="code"></param>
/// <param name="data"></param>
/// <param name="_commonDocumentRepository"></param>
/// <param name="_hostEnvironment"></param>
/// <param name="_dictionaryService"></param>
/// <param name="translateType"></param>
/// <param name="criterionType"></param>
/// <param name="dynamicColumnConfig"></param>
/// <returns></returns>
public static async Task<(MemoryStream, string)> CDISC_DataExport_Async(string code, ExcelExportInfo data, IRepository<CommonDocument> _commonDocumentRepository, IWebHostEnvironment _hostEnvironment, IDictionaryService? _dictionaryService = null, Type? translateType = null, CriterionType? criterionType = null, DynamicColumnConfig? dynamicColumnConfig = null)
{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
//判断是否有字典翻译
object translateData = data;
Dictionary<string, object> translatedDic = default;
if (_dictionaryService != null && translateType != null)
{
//一个值 对应不同的字典翻译
var needTranslatePropertyList = translateType.GetProperties().Where(t => t.IsDefined(typeof(DictionaryTranslateAttribute), true))
.SelectMany(c =>
c.GetCustomAttributes(typeof(DictionaryTranslateAttribute), false).Select(f => (DictionaryTranslateAttribute?)f).Where(t => t.CriterionType == criterionType || t.CriterionType == null)
.Select(k => new { c.Name, k.DicParentCode, k.IsTranslateDenpendOtherProperty, k.DependPropertyName, k.DependPropertyValueStr })
).ToList();
//字典表查询出所有需要翻译的数据
var translateDataList = await _dictionaryService.GetBasicDataSelect(needTranslatePropertyList.Select(t => t.DicParentCode).Distinct().ToArray());
var dic = data.ConvertToDictionary();
//var dic = (JsonConvert.DeserializeObject<IDictionary<string, object>>(data.ToJsonNotIgnoreNull())).IfNullThrowException();
foreach (var key in dic.Keys)
{
//是数组 那么找到对应的属性 进行翻译
if (dic[key] != null && dic[key].GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>)))
//if (dic[key].GetType().IsAssignableFrom(typeof(JArray)))
{
var newObjList = new List<object>();
var no = 1;
foreach (var item in dic[key] as IList)
//foreach (var item in dic[key] as JArray)
{
//var itemDic = JsonConvert.DeserializeObject<IDictionary<string, object>>(item.ToJsonNotIgnoreNull());
var itemDic = item.ConvertToDictionary();
foreach (var needTranslateProperty in needTranslatePropertyList)
{
if (itemDic.Keys.Any(t => t == needTranslateProperty.Name))
{
//翻译的属性依赖其他属性
if (needTranslateProperty.IsTranslateDenpendOtherProperty)
{
if (itemDic[needTranslateProperty.DependPropertyName]?.ToString().ToLower() == needTranslateProperty.DependPropertyValueStr.ToLower())
{
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
}
}
//普通翻译 或者某一标准翻译
else
{
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
}
}
}
itemDic.Add("No", no++);
newObjList.Add(itemDic);
}
dic[key] = newObjList;
}
}
//data = dic;
translateData = dic;
translatedDic = dic;
}
var (physicalPath, fileName) = await FileStoreHelper.GetCommonDocPhysicalFilePathAsync(_hostEnvironment, _commonDocumentRepository, code);
//模板路径
var tplPath = physicalPath;
#region 根据中英文 删除模板sheet
// 打开模板文件
var templateFile = new FileStream(tplPath, FileMode.Open, FileAccess.Read);
// 获取文件流
var templateStream = new MemoryStream();
templateFile.CopyTo(templateStream);
templateStream.Seek(0, SeekOrigin.Begin);
var workbook = new XSSFWorkbook(templateStream);
int sheetCount = workbook.NumberOfSheets;
if (sheetCount == 2)
{
if (isEn_US)
{
workbook.RemoveSheetAt(0);
}
else
{
workbook.RemoveSheetAt(1);
}
if (dynamicColumnConfig != null)
{
var sheet = workbook.GetSheetAt(0);
var cdicsRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex - 1);
var titelRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex);
var templateRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex + 1);
//动态移除列的数量
var dynamicRemoveColunmCount = dynamicColumnConfig.RemoveColunmIndexList.Count();
//在动态列开始前移除的数量
var beforeDynamicRemoveCount = dynamicColumnConfig.RemoveColunmIndexList.Where(t => t < dynamicColumnConfig.AutoColumnStartIndex).Count();
//动态添加列的数量
var needAddCount = dynamicColumnConfig.ColumnIdNameList.Count;
//原始表 最终索引
var originTotalEndIndex = dynamicColumnConfig.TempalteLastColumnIndex;
@ -513,6 +941,7 @@ public static class ExcelExportHelper
//创建新的列
for (int i = originTotalEndIndex; i < originTotalEndIndex + needAddCount; i++)
{
cdicsRow.CreateCell(i + 1);
titelRow.CreateCell(i + 1);
templateRow.CreateCell(i + 1);
}
@ -534,8 +963,11 @@ public static class ExcelExportHelper
for (int i = dynamicColunmStartIndex; i < dynamicColunmStartIndex + needAddCount; i++)
{
var name = dynamicColumnConfig.ColumnNameList[i - dynamicColunmStartIndex];
var name = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].Name;
var cdicsCode = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].CDISCCode;
cdicsRow.GetCell(i).SetCellValue(cdicsCode);
titelRow.GetCell(i).SetCellValue(name);
templateRow.GetCell(i).SetCellValue("");
}
@ -569,6 +1001,8 @@ public static class ExcelExportHelper
if (dynamicColumnConfig != null)
{
var isExcelAddDataWithName = dynamicColumnConfig.ColumnIdNameList.Select(t => t.Id).Count() == 1;
var dynamicTranslateDataList = await _dictionaryService.GetBasicDataSelect(dynamicColumnConfig.TranslateDicNameList.ToArray());
// 使用NPOI 进行二次处理
@ -599,7 +1033,15 @@ public static class ExcelExportHelper
//var writeIndex = itemList.IndexOf(itemObj) + dynamicColumnConfig.AutoColumnStartIndex;
var writeIndex = dynamicColumnConfig.ColumnNameList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleName].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
var writeIndex = 0;
if (isExcelAddDataWithName)
{
writeIndex = dynamicColumnConfig.ColumnNameList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleName].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
}
else
{
writeIndex = dynamicColumnConfig.ColumnIdList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleId].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
}
if (itemDicName.IsNotNullOrEmpty())
{
@ -635,6 +1077,35 @@ public static class ExcelExportHelper
}
public static async Task<IActionResult> MutiSheetDataExportAsync(string code, object data, string exportFileNamePrefix, IRepository<CommonDocument> _commonDocumentRepository, IWebHostEnvironment _hostEnvironment)
{
var (physicalPath, fileName) = await FileStoreHelper.GetCommonDocPhysicalFilePathAsync(_hostEnvironment, _commonDocumentRepository, code);
//模板路径
var tplPath = physicalPath;
var memoryStream = new MemoryStream();
var config = new OpenXmlConfiguration()
{
IgnoreTemplateParameterMissing = true,
};
await MiniExcel.SaveAsByTemplateAsync(memoryStream, tplPath, data, config);
memoryStream.Seek(0, SeekOrigin.Begin);
return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
{
FileDownloadName = $"{(string.IsNullOrEmpty(exportFileNamePrefix) ? "" : exportFileNamePrefix + "_")}{Path.GetFileNameWithoutExtension(fileName)}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
};
}
/// <summary>
/// 导出文件模板
/// </summary>
@ -716,4 +1187,7 @@ public static class ExcelExportHelper
};
}
}

View File

@ -69,6 +69,15 @@ public static class FileStoreHelper
return rootFolder;
}
public static string GetDonwnloadImageFolder(IWebHostEnvironment _hostEnvironment)
{
var rootPath = GetIRaCISRootPath(_hostEnvironment);
var rootFolder = Path.Combine(rootPath, StaticData.Folder.DownloadIamgeFolder);
return rootFolder;
}
//根据相对路径 获取具体文件物理地址
public static string GetPhysicalFilePath(IWebHostEnvironment _hostEnvironment, string relativePath)
{

View File

@ -20,12 +20,12 @@ namespace IRaCIS.Core.Application.Helper
//添加 或者更新定时任务 Id 要唯一标识一个定义任务
public static void AddOrUpdateCronJob<T>(string jobId, Expression<Action<T>> methodCall, string cron, string queueName = "default")
{
RecurringJob.AddOrUpdate<T>(jobId, queueName, methodCall, cron);
RecurringJob.AddOrUpdate<T>(jobId, queueName, methodCall, cron, new RecurringJobOptions() { TimeZone = TimeZoneInfo.Local });
}
public static void AddOrUpdateInitCronJob<T>(string jobId, Expression<Action<T>> methodCall, string cron)
{
RecurringJob.AddOrUpdate<T>(jobId, "sys_init", methodCall, cron);
RecurringJob.AddOrUpdate<T>(jobId, "sys_init", methodCall, cron, new RecurringJobOptions() { TimeZone = TimeZoneInfo.Local });
}
public static void RemoveCronJob(string jobId)
@ -73,17 +73,36 @@ namespace IRaCIS.Core.Application.Helper
case EmailBusinessScenario.QCToCRCImageQuestion:
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new QCImageQuestionRecurringEvent() { TrialId = trialId }, default), emailCron);
break;
//加急阅片 10分钟
//加急阅片 10分钟
case EmailBusinessScenario.ExpeditedReading:
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new UrgentIRUnReadTaskRecurringEvent() { TrialId = trialId }, default), emailCron);
break;
default:
break;
}
}
public static void AddOrUpdateTimingCronJob(string jobId, EmailBusinessScenario businessScenario, string emailCron)
{
switch (businessScenario)
{
case EmailBusinessScenario.GeneralTraining_ExpirationNotification:
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new SystemDocumentErverDayEvent() { }, default), emailCron);
break;
case EmailBusinessScenario.TrialTraining_ExpirationNotification:
Console.WriteLine("更新项目到期job");
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new TrialDocumentErverDayEvent() { }, default), emailCron);
break;
default:
break;
}
}
}
}

View File

@ -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}";
}
}
}
}

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,11 +10,15 @@ 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;
using System.Web;
namespace IRaCIS.Core.Application.Helper;
@ -59,7 +64,7 @@ public class AliyunOSSOptions
public int DurationSeconds { get; set; }
public string PreviewEndpoint { get; set; }
}
@ -105,6 +110,9 @@ public class AliyunOSSTempToken
public string SecurityToken { get; set; }
public DateTime Expiration { get; set; }
public string PreviewEndpoint { get; set; }
public string DownloadEndPoint => EndPoint.Insert(EndPoint.IndexOf("//") + 2, BucketName + ".");
}
@ -118,7 +126,7 @@ public class AWSTempToken
public string SecretAccessKey { get; set; }
public string BucketName { get; set; }
public string ViewEndpoint { get; set; }
public DateTime Expiration { get; set; }
public DateTime? Expiration { get; set; }
}
public enum ObjectStoreUse
@ -135,17 +143,27 @@ public enum ObjectStoreUse
public interface IOSSService
{
public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true);
public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true);
public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true, bool randomFileName = false);
public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);
public Task<Stream> GetStreamFromOSSAsync(string ossRelativePath);
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
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);
}
@ -176,7 +194,7 @@ public class OSSService : IOSSService
/// <returns></returns>
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
{
GetObjectStoreTempToken();
BackBatchGetToken();
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
@ -266,6 +284,37 @@ public class OSSService : IOSSService
}
//后端批量上传 或者下载不每个文件获取临时token
private void BackBatchGetToken()
{
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
{
if (AliyunOSSTempToken == null)
{
GetObjectStoreTempToken();
}
//token 过期了
if (AliyunOSSTempToken?.Expiration.AddSeconds(10) <= DateTime.Now)
{
GetObjectStoreTempToken();
}
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
{
if (AWSTempToken == null)
{
GetObjectStoreTempToken();
}
//token 过期了
if (AWSTempToken.Expiration?.AddSeconds(10) <= DateTime.Now)
{
GetObjectStoreTempToken();
}
}
}
/// <summary>
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
@ -273,16 +322,22 @@ public class OSSService : IOSSService
/// <param name="localFilePath"></param>
/// <param name="oosFolderPath"></param>
/// <param name="isFileNameAddGuid"></param>
/// <param name="randomFileName">随机文件名</param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true, bool randomFileName = false)
{
GetObjectStoreTempToken();
BackBatchGetToken();
var localFileName = Path.GetFileName(localFilePath);
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}" : $"{oosFolderPath}/{localFileName}";
if (randomFileName)
{
var fileExtension = localFileName.Split(".").LastOrDefault();
ossRelativePath = $"{oosFolderPath}/{Guid.NewGuid()}.{fileExtension}";
}
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
{
@ -347,7 +402,7 @@ public class OSSService : IOSSService
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
{
GetObjectStoreTempToken();
BackBatchGetToken();
ossRelativePath = ossRelativePath.TrimStart('/');
try
@ -360,14 +415,12 @@ public class OSSService : IOSSService
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
// 上传文件
var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
// 将下载的文件流保存到本地文件
using (var fs = File.OpenWrite(localFilePath))
{
result.Content.CopyTo(fs);
fs.Close();
await result.Content.CopyToAsync(fs);
}
}
@ -431,6 +484,96 @@ public class OSSService : IOSSService
}
public async Task<Stream> GetStreamFromOSSAsync(string ossRelativePath)
{
BackBatchGetToken();
ossRelativePath = ossRelativePath.TrimStart('/');
try
{
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 result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
// 将OSS返回的流复制到内存流中并返回
var memoryStream = new MemoryStream();
await result.Content.CopyToAsync(memoryStream);
memoryStream.Position = 0; // 重置位置以便读取
return memoryStream;
}
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 memoryStream = new MemoryStream();
var getObjectArgs = new GetObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(ossRelativePath)
.WithCallbackStream(stream => stream.CopyToAsync(memoryStream));
await minioClient.GetObjectAsync(getObjectArgs);
memoryStream.Position = 0;
return memoryStream;
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "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);
var getObjectRequest = new Amazon.S3.Model.GetObjectRequest
{
BucketName = awsConfig.BucketName,
Key = ossRelativePath
};
var response = await amazonS3Client.GetObjectAsync(getObjectRequest);
var memoryStream = new MemoryStream();
await response.ResponseStream.CopyToAsync(memoryStream);
memoryStream.Position = 0;
return memoryStream;
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
catch (Exception ex)
{
throw new BusinessValidationFailedException("oss流获取失败! " + ex.Message);
}
}
public async Task<string> GetSignedUrl(string ossRelativePath)
{
GetObjectStoreTempToken();
@ -526,12 +669,240 @@ 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>
/// <returns></returns>
public List<string> GetRootFolderNames()
{
GetObjectStoreTempToken();
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint,
AliyunOSSTempToken.AccessKeyId,
AliyunOSSTempToken.AccessKeySecret,
AliyunOSSTempToken.SecurityToken);
List<string> rootFolders = new List<string>();
string nextMarker = null;
try
{
ObjectListing objectListing = null;
do
{
// 列出根目录下的对象和文件夹
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName)
{
MaxKeys = 1000,
Marker = nextMarker,
Delimiter = "/" // 使用分隔符来模拟文件夹
});
// 遍历 CommonPrefixes 获取根文件夹名称
foreach (var prefix in objectListing.CommonPrefixes)
{
rootFolders.Add(prefix.TrimEnd('/')); // 去掉末尾的斜杠
}
// 设置 NextMarker 以获取下一页的数据
nextMarker = objectListing.NextMarker;
} while (objectListing.IsTruncated);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
return rootFolders;
}
/// <summary>
/// 删除某个目录的文件
/// </summary>
/// <param name="prefix"></param>
/// <returns></returns>
public async Task DeleteFromPrefix(string prefix)
public async Task DeleteFromPrefix(string prefix, bool isCache = false)
{
GetObjectStoreTempToken();
@ -541,6 +912,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
{
@ -549,7 +935,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,
@ -561,7 +947,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 以获取下一页的数据
@ -618,7 +1004,6 @@ public class OSSService : IOSSService
var awsConfig = ObjectStoreServiceOptions.AWS;
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
@ -670,6 +1055,155 @@ 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("未定义的存储介质类型");
}
}
public async Task<long> GetObjectSizeAsync(string sourcePath)
{
BackBatchGetToken();
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 key = HttpUtility.UrlDecode(objectkey);
var metadata = _ossClient.GetObjectMetadata(aliConfig.BucketName, key);
long fileSize = metadata?.ContentLength ?? 0; // 文件大小(字节)
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()
{
@ -713,6 +1247,7 @@ public class OSSService : IOSSService
BucketName = ossOptions.BucketName,
EndPoint = ossOptions.EndPoint,
ViewEndpoint = ossOptions.ViewEndpoint,
PreviewEndpoint = ossOptions.PreviewEndpoint
};

View File

@ -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());
}
}

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Helper
{
public static class SafeBussinessHelper
{
public static async Task<bool> RunAsync(Func<Task> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
{
try
{
await func();
return true;
}
catch (Exception ex)
{
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
return false;
}
}
public static async Task<(bool Success, T? Result)> RunAsync<T>(Func<Task<T>> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
{
try
{
var result = await func();
return (true, result);
}
catch (Exception ex)
{
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
return (false, default);
}
}
}
}

View File

@ -33,37 +33,37 @@
<ItemGroup>
<PackageReference Include="IdentityModel.OidcClient" Version="6.0.0" />
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.4" />
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.400.36" />
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.6" />
<PackageReference Include="AWSSDK.SecurityToken" Version="4.0.1.3" />
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageReference Include="AWSSDK.S3" Version="3.7.405" />
<PackageReference Include="DocX" Version="3.0.1" />
<PackageReference Include="AWSSDK.S3" Version="4.0.4.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="DistributedLock.Redis" Version="1.1.0" />
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
<PackageReference Include="fo-dicom" Version="5.2.2" />
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.2" />
<PackageReference Include="fo-dicom.Codecs" Version="5.16.4" />
<PackageReference Include="IP2Region.Net" Version="2.0.2" />
<PackageReference Include="MailKit" Version="4.7.1.1" />
<PackageReference Include="MailKit" Version="4.11.0" />
<PackageReference Include="Masa.Contrib.Service.MinimalAPIs" Version="1.0.0" />
<PackageReference Include="MaxMind.GeoIP2" Version="5.3.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="MimeKit" Version="4.11.0" />
<PackageReference Include="MiniExcel" Version="1.41.2" />
<PackageReference Include="Minio" Version="6.0.3" />
<PackageReference Include="MiniWord" Version="0.8.0" />
<PackageReference Include="MiniWord" Version="0.9.2" />
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
<PackageReference Include="NPOI" Version="2.7.1" />
<PackageReference Include="NPOI" Version="2.7.4" />
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
<PackageReference Include="RestSharp" Version="112.1.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.2" />
<PackageReference Include="ZiggyCreatures.FusionCache" Version="1.4.0" />
</ItemGroup>
<ItemGroup>
@ -74,4 +74,8 @@
<Folder Include="Service\MinimalApiService\CodeTemplate\FrontTemplate\" />
</ItemGroup>
<ItemGroup>
<None Include="Service\TrialSiteUser\TrialStatService.cs" />
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,21 @@
using MiniExcelLibs.Attributes;
using IRaCIS.Core.Application.Helper;
using MiniExcelLibs.Attributes;
using System.ComponentModel.DataAnnotations;
namespace IRaCIS.Core.Application.MassTransit.Command
{
/// <summary>
/// 全量一致性核查
/// </summary>
public record ConsistenFullCheckCommand
{
public List<CheckViewModel> ETCList { get; set; } = new List<CheckViewModel>();
public Guid TrialId { get; set; }
public Guid InspectionFileId { get; set; }
}
public record ConsistenCheckCommand
{
public List<CheckViewModel> ETCList { get; set; } = new List<CheckViewModel>();
@ -17,13 +30,24 @@ namespace IRaCIS.Core.Application.MassTransit.Command
public class CheckDBModel : CheckViewModel
{
public Guid SubjectVisitId { get; set; }
public Guid StudyId { get; set; }
}
public class FullCheckResult: CheckViewModel
{
public string LatestScanDateStr { get; set; } = string.Empty;
public string Modalitys { get; set; } = string.Empty;
public DateTime CheckTime { get; set; }
public string CheckResult { get; set; }
[DictionaryTranslateAttribute("CheckState")]
public CheckStateEnum CheckState { get; set; }
}
//[ExcelImporter(/*ImportResultFilter = typeof(ImportResultFilteTest),*/ IsLabelingError = true)]
@ -62,8 +86,13 @@ namespace IRaCIS.Core.Application.MassTransit.Command
[ExcelColumnName("Modality")]
public string Modality { get; set; } = string.Empty;
#region 全量一致性核查加入
[DictionaryTranslateAttribute("Subject_Visit_Status")]
public SubjectStatus SubjectStatus { get; set; }
#endregion
public override bool Equals(object? obj)
{

View File

@ -14,19 +14,20 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer;
public static class CommonEmailHelper
{
public static async Task<EmailNoticeConfig> GetEmailSubejctAndHtmlInfoAndBuildAsync(IRepository<EmailNoticeConfig> _emailNoticeConfigrepository, EmailBusinessScenario scenario, MimeMessage messageToSend,
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailFunc)
/// <summary>
/// 系统默认邮件 + 项目默认邮件 (不用添加到项目邮件配置中,才发送)
/// </summary>
/// <param name="configInfo"></param>
/// <param name="messageToSend"></param>
/// <param name="emailFunc"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
public static async Task<EmailNoticeConfig> GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailNoticeConfig configInfo, MimeMessage messageToSend,
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailFunc)
{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
var configInfo = await _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario).FirstOrDefaultAsync();
if (configInfo == null)
{
throw new BusinessValidationFailedException("系统未找到当前场景邮件配置信息,请联系运维人员核查");
}
var (topicStr, htmlBodyStr) = isEn_US ? (configInfo.EmailTopic, configInfo.EmailHtmlContent) : (configInfo.EmailTopicCN, configInfo.EmailHtmlContentCN);
try
@ -36,8 +37,9 @@ public static class CommonEmailHelper
}
catch (Exception ex)
{
//"邮件模板内容有误,填充内容出现问题,请联系运维人员核查"
throw new BusinessValidationFailedException("邮件模板内容有误,填充内容出现问题,请联系运维人员核查");
throw new BusinessValidationFailedException(I18n.T("CommonEmail_ConfigError"));
}
@ -52,6 +54,49 @@ public static class CommonEmailHelper
return configInfo;
}
/// <summary>
/// 项目手动邮件 (需要添加到项目邮件配置中,才发送)
/// </summary>
/// <param name="configInfo"></param>
/// <param name="messageToSend"></param>
/// <param name="emailFunc"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
public static async Task<TrialEmailNoticeConfig> GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(TrialEmailNoticeConfig configInfo, MimeMessage messageToSend,
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailFunc)
{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
var (topicStr, htmlBodyStr) = isEn_US ? (configInfo.EmailTopic, configInfo.EmailHtmlContent) : (configInfo.EmailTopicCN, configInfo.EmailHtmlContentCN);
try
{
//每个场景修改主题 和body的逻辑不一样
(topicStr, htmlBodyStr) = emailFunc((topicStr, htmlBodyStr));
}
catch (Exception ex)
{
//"邮件模板内容有误,填充内容出现问题,请联系运维人员核查"
throw new BusinessValidationFailedException(I18n.T("CommonEmail_ConfigError"));
}
messageToSend.Subject = topicStr;
var builder = new BodyBuilder();
builder.HtmlBody = htmlBodyStr;
messageToSend.Body = builder.ToMessageBody();
return configInfo;
}
public static string ReplaceCompanyName(SystemEmailSendConfig _systemEmailConfig, string needDealtxt)
{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
@ -74,12 +119,13 @@ public static class CommonEmailHelper
var enumValueList = inDto.DictionaryList.Select(x => x.EnumValue).ToList();
var dicList =await inDto.DictionaryRepository.Where(x => dictionaryCodelist.Contains(x.Parent.Code) && enumValueList.Contains(x.Code)).Select(x=>new DictionaryData() {
DictionaryCode=x.Parent.Code,
EnumValue=x.Code,
Value=x.Value,
ValueCN=x.ValueCN
var dicList = await inDto.DictionaryRepository.Where(x => dictionaryCodelist.Contains(x.Parent.Code) && enumValueList.Contains(x.Code)).Select(x => new DictionaryData()
{
DictionaryCode = x.Parent.Code,
EnumValue = x.Code,
Value = x.Value,
ValueCN = x.ValueCN
}).ToListAsync();
@ -88,7 +134,7 @@ public static class CommonEmailHelper
inDto.DictionaryList.ForEach(x =>
{
var dic = dicList.Where(y => y.EnumValue == x.EnumValue && y.DictionaryCode == x.DictionaryCode).FirstOrDefault();
var dic = dicList.Where(y => y.EnumValue == x.EnumValue && y.DictionaryCode.Equals(x.DictionaryCode,StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
result.Add(dic == null ? string.Empty : (inDto.IsEn_US ? dic.Value : dic.ValueCN));
});

View File

@ -1,44 +1,49 @@
using AutoMapper;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Contracts.DTO;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.MassTransit.Command;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using MassTransit;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.IO;
using System.Text;
namespace IRaCIS.Core.Application.MassTransit.Consumer
{
public class ConsistencyCheckConsumer : IConsumer<ConsistenCheckCommand>
public class ConsistencyCheckConsumer(
IRepository<DicomStudy> _studyRepository,
IUserInfo _userInfo,
IRepository<Subject> _subjectRepository,
IRepository<NoneDicomStudy> _noneDicomStudyRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<Dictionary> _dictionaryRepository,
IOSSService _oSSService,
IMapper _mapper,
IDictionaryService _dictionaryService,
IRepository<CommonDocument> _commonDocumentRepository,
IStringLocalizer _localizer,
IWebHostEnvironment _hostEnvironment,
IRepository<InspectionFile> _inspectionFileRepository,
IOptionsMonitor<SystemEmailSendConfig> _systemEmailSendConfig
) : IConsumer<ConsistenCheckCommand>, IConsumer<ConsistenFullCheckCommand>
{
private readonly IRepository<DicomStudy> _studyRepository;
private readonly IUserInfo _userInfo;
private readonly IRepository<Subject> _subjectRepository;
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
private readonly IRepository<TrialSite> _trialSiteRepository;
private readonly IMapper _mapper;
private readonly IRepository<NoneDicomStudy> _noneDicomStudyRepository;
public IStringLocalizer _localizer { get; set; }
/// <summary>
/// 构造函数注入
/// </summary>
public ConsistencyCheckConsumer(IRepository<DicomStudy> studyRepository, IUserInfo userInfo,
IRepository<Subject> subjectRepository, IRepository<SubjectVisit> subjectVisitRepository,
IRepository<TrialSite> trialSiteRepository, IRepository<NoneDicomStudy> noneDicomStudyRepository,
IMapper mapper, IStringLocalizer localizer)
{
_noneDicomStudyRepository = noneDicomStudyRepository;
_studyRepository = studyRepository;
_userInfo = userInfo;
_subjectRepository = subjectRepository;
_subjectVisitRepository = subjectVisitRepository;
_trialSiteRepository = trialSiteRepository;
_mapper = mapper;
_localizer = localizer;
}
private readonly SystemEmailSendConfig _systemEmailConfig = _systemEmailSendConfig.CurrentValue;
@ -47,6 +52,9 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
var trialId = context.Message.TrialId;
//系统定义MRI 到底是MR 还是MRI
var mriModality = await _dictionaryRepository.Where(t => t.Parent.Code == "Modality").Where(t => t.Code == "MRI").Select(t => t.Value).FirstNotNullAsync();
//处理Excel大小写
context.Message.ETCList.ForEach(t => { t.Modality = t.Modality.ToUpper().Trim(); t.StudyDate = Convert.ToDateTime(t.StudyDate).ToString("yyyy-MM-dd"); t.SiteCode = t.SiteCode.ToUpper().Trim(); t.VisitName = t.VisitName.ToUpper().Trim(); t.SubjectCode = t.SubjectCode.ToUpper().Trim(); });
var etcList = context.Message.ETCList;
@ -55,8 +63,8 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
//subjectVisitLambda2= subjectVisitLambda2.And(x => x.CheckState == CheckStateEnum.ToCheck && x.AuditState == AuditStateEnum.QCPassed || (x.CheckState == CheckStateEnum.CVIng && x.AuditState == AuditStateEnum.QCPassed));
Expression<Func<SubjectVisit, bool>> subjectVisitLambda = x => x.TrialId == trialId &&
(x.CheckState == CheckStateEnum.ToCheck && x.AuditState == AuditStateEnum.QCPassed || (x.CheckState == CheckStateEnum.CVIng && x.AuditState == AuditStateEnum.QCPassed));
Expression<Func<SubjectVisit, bool>> subjectVisitLambda = x => x.TrialId == trialId && x.Subject.IsSubjectQuit == false && x.AuditState == AuditStateEnum.QCPassed &&
(x.CheckState == CheckStateEnum.ToCheck || x.CheckState == CheckStateEnum.CVIng);
var dicomQuery = from sv in _subjectVisitRepository.Where(subjectVisitLambda)
join subject in _subjectRepository.AsQueryable() on sv.SubjectId equals subject.Id
@ -105,7 +113,7 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
foreach (var sv in svExcelGroup)
{
//Excel 的数据 在IRC 中可以找到该访视
//Excel 的数据 在IRC 中可以找到该访视(一致性核查中,或者待核查)
if (dbCheckList.Any(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName))
{
@ -115,6 +123,16 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
var etcVisitStudyList = etcList.Where(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName).ToList();
//以我们系统数据库为准 判断是MR 还是MRI, 把Excel 里的MR 或者MRI 处理成一致MR MRI 是一致的
foreach (var item in etcVisitStudyList)
{
if (item.Modality == "MR" || item.Modality == "MRI")
{
item.Modality = mriModality;
}
}
StringBuilder dialogMsg = new StringBuilder();
//---您好,根据本系统自动识别该受试者当前访视在IRC系统中已提交的影像检查情况如下
@ -179,24 +197,24 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
var dbExceptExcel = dbVisitStudyList.Except(etcVisitStudyList);
// excel 存在
var excelExceptDB = etcVisitStudyList.Except(dbCheckList);
var excelExceptDB = etcVisitStudyList.Except(dbVisitStudyList);
//ETC 和系统的完全一致 两者没有差别
if (dbExceptExcel.Count() == 0 && excelExceptDB.Count() == 0)
{
dialogMsg.AppendLine($"<br/>");
//---核对EDC数据完全一致, 审核通过
dialogMsg.AppendLine(_localizer["ConsistencyVerification_EDCA"]);
dialogMsg.AppendLine(_localizer["ConsistencyVerification_EDCA", _systemEmailConfig.SystemShortName]);
// dialogMsg.AppendLine(@$"<br>说明:为高效解决/处理以上全部质疑问题麻烦您准确核实实际影像检查情况。请注意影像日期与实际检查的日期可能会不一致部分检查如PET -CT)可能同时存在多种模态影像。准确核实后,请回复该访视正确的影像检查情况。");
dbSV.CheckState = CheckStateEnum.CVPassed;
dbSV.CheckUserId = _userInfo.Id;
dbSV.CheckUserId = _userInfo.UserRoleId;
dbSV.CheckPassedTime = DateTime.Now;
dbSV.CheckChallengeState = CheckChanllengeTypeEnum.Closed;
//---核对EDC数据完全一致
dbSV.CheckResult = _localizer["ConsistencyVerification_EDCB"];
dbSV.CheckResult = _localizer["ConsistencyVerification_EDCB", _systemEmailConfig.SystemShortName];
//---自动核查通过
dbSV.ManualPassReason = _localizer["ConsistencyVerification_Auto"];
@ -217,14 +235,14 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
else
{
//"Problems are as follows:
dialogMsg.AppendLine($"<br/><div style='color: red'>{_localizer["ConsistencyVerification_Prob"]}</div>");
dialogMsg.AppendLine($"<br/><div>{_localizer["ConsistencyVerification_Prob"]}</div>");
num = 0;
foreach (var item in dbExceptExcel)
{
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 +250,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]}"));
//新增一致性核查质疑记录
@ -279,12 +297,169 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
}
await _subjectVisitRepository.SaveChangesAsync();
//await context.RespondAsync<ConsistenCheckResult>(new
//{
//});
}
public async Task Consume(ConsumeContext<ConsistenFullCheckCommand> context)
{
var inspectionFileId = context.Message.InspectionFileId;
var trialId = context.Message.TrialId;
//系统定义MRI 到底是MR 还是MRI
var mriModality = await _dictionaryRepository.Where(t => t.Parent.Code == "Modality").Where(t => t.Code == "MRI").Select(t => t.Value).FirstNotNullAsync();
//处理Excel大小写
context.Message.ETCList.ForEach(t => { t.Modality = t.Modality.ToUpper().Trim(); t.StudyDate = Convert.ToDateTime(t.StudyDate).ToString("yyyy-MM-dd"); t.SiteCode = t.SiteCode.ToUpper().Trim(); t.VisitName = t.VisitName.ToUpper().Trim(); t.SubjectCode = t.SubjectCode.ToUpper().Trim(); });
var etcList = context.Message.ETCList;
Expression<Func<SubjectVisit, bool>> subjectVisitLambda = x => x.TrialId == trialId /*&& x.Subject.IsSubjectQuit == false*/ && x.AuditState == AuditStateEnum.QCPassed;
var dicomQuery = from sv in _subjectVisitRepository.Where(subjectVisitLambda)
join subject in _subjectRepository.AsQueryable() on sv.SubjectId equals subject.Id
join study in _studyRepository.AsQueryable() on sv.Id equals study.SubjectVisitId
select new CheckDBModel()
{
SubjectStatus = sv.Subject.Status,
SubjectVisitId = sv.Id,
SiteCode = sv.TrialSite.TrialSiteCode,
StudyDate = study.StudyTime == null ? string.Empty : ((DateTime)study.StudyTime).ToString("yyyy-MM-dd"),
StudyId = study.Id,
Modality = study.ModalityForEdit,
SubjectCode = subject.Code,
VisitName = sv.VisitName,
};
var noneDicomQuey = from sv in _subjectVisitRepository.Where(subjectVisitLambda)
join subject in _subjectRepository.AsQueryable() on sv.SubjectId equals subject.Id
join noneDicomStudy in _noneDicomStudyRepository.AsQueryable() on sv.Id equals noneDicomStudy.SubjectVisitId
select new CheckDBModel()
{
SubjectStatus = sv.Subject.Status,
SubjectVisitId = sv.Id,
SiteCode = sv.TrialSite.TrialSiteCode,
StudyDate = noneDicomStudy.ImageDate.ToString("yyyy-MM-dd"),
StudyId = noneDicomStudy.Id,
Modality = noneDicomStudy.Modality,
SubjectCode = subject.Code,
VisitName = sv.VisitName,
};
var dbList = (await dicomQuery.ToListAsync()).Union(await noneDicomQuey.ToListAsync()).ToList();
//处理数据库 大小写
dbList.ForEach(t => { t.Modality = t.Modality.ToUpper().Trim(); t.SiteCode = t.SiteCode.ToUpper().Trim(); t.VisitName = t.VisitName.ToUpper().Trim(); t.SubjectCode = t.SubjectCode.ToUpper().Trim(); });
var dbCheckList = _mapper.Map<List<CheckViewModel>>(dbList);
//按照Excel数据访视分组 按照数据库的数据 一个个的访视对比
var svExcelGroup = etcList.GroupBy(t => new { t.SiteCode, t.SubjectCode, t.VisitName })
.Select(g => new { g.Key.SubjectCode, g.Key.VisitName, g.Key.SiteCode, ExcelStudyList = g.ToList() }).ToList();
var fullCheckResultList = new List<FullCheckResult>();
foreach (var sv in svExcelGroup)
{
//Excel 的数据 在IRC 中可以找到该访视(一致性核查中,或者待核查)
if (dbCheckList.Any(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName))
{
var dbVisitStudyList = dbList.Where(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName).ToList();
//找到etc 当前visit site 和subject 一致的检查列表
var etcVisitStudyList = etcList.Where(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName).ToList();
//以我们系统数据库为准 判断是MR 还是MRI, 把Excel 里的MR 或者MRI 处理成一致MR MRI 是一致的
foreach (var item in etcVisitStudyList)
{
if (item.Modality == "MR" || item.Modality == "MRI")
{
item.Modality = mriModality;
}
}
//etc 和数据库 并集
var unionList = dbVisitStudyList.Union(etcVisitStudyList);
// 数据库存在
var dbExceptExcel = dbVisitStudyList.Except(etcVisitStudyList);
// excel 存在
var excelExceptDB = etcVisitStudyList.Except(dbVisitStudyList);
var dbCurrentVisitFirst = dbVisitStudyList.First();
//ETC 和系统的完全一致 两者没有差别
if (dbExceptExcel.Count() == 0 && excelExceptDB.Count() == 0)
{
//每个受试者每个访视加一条记录
fullCheckResultList.Add(new FullCheckResult()
{
SubjectStatus = dbCurrentVisitFirst.SubjectStatus,
CheckTime = DateTime.Now,
CheckState=CheckStateEnum.CVPassed,
SiteCode = dbCurrentVisitFirst.SiteCode,
SubjectCode = dbCurrentVisitFirst.SubjectCode,
VisitName = dbCurrentVisitFirst.VisitName,
Modalitys = string.Join('、', dbVisitStudyList.Select(t => t.Modality)),
LatestScanDateStr = dbVisitStudyList.Select(t => t.StudyDate).MaxBy(d => DateTime.Parse(d)) ?? ""
});
}
else
{
var checkResult =
String.Join(" | ", dbExceptExcel.Select(t => $"{_localizer["ConsistencyVerification_EdcL", t.StudyDate, t.Modality/*, _systemEmailConfig.SystemShortName*/]}")) + " | "
+ String.Join(" | ", excelExceptDB.Select(t => $"{_localizer["ConsistencyVerification_IrcLi", t.StudyDate, t.Modality, _systemEmailConfig.SystemShortName]}"));
//每个受试者每个访视加一条记录
fullCheckResultList.Add(new FullCheckResult()
{
SubjectStatus = dbCurrentVisitFirst.SubjectStatus,
CheckState = CheckStateEnum.None,
CheckTime = DateTime.Now,
SiteCode = dbCurrentVisitFirst.SiteCode,
SubjectCode = dbCurrentVisitFirst.SubjectCode,
VisitName = dbCurrentVisitFirst.VisitName,
Modalitys = string.Join('、', dbVisitStudyList.Select(t => t.Modality)),
LatestScanDateStr = dbVisitStudyList.Select(t => t.StudyDate).MaxBy(d => DateTime.Parse(d)) ?? "",
CheckResult = checkResult
});
}
}
}
//导到Excel 上传oss 回更记录状态
var list = fullCheckResultList;
var exportInfo = new ExcelExportInfo();
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list, _userInfo.TimeZoneId);
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
var fileStreamResult = (FileStreamResult)await ExcelExportHelper.DataExportAsync(StaticData.Export.TrialConsistentFUllCheckList_Export, exportInfo, exportInfo.TrialCode, _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(FullCheckResult));
var ossRelativePath = await _oSSService.UploadToOSSAsync(fileStreamResult.FileStream, $"{trialId.ToString()}/InspectionUpload/DataReconciliation", "DataReconciliation");
//var add = await _inspectionFileRepository.FindAsync(inspectionFileId);
//add.CheckState = EDCCheckState.Success;
//add.ResultPath = ossRelativePath;
//更新
await _inspectionFileRepository.BatchUpdateNoTrackingAsync(t => t.Id == inspectionFileId, u => new InspectionFile() { CheckState = EDCCheckState.Success, ResultPath = ossRelativePath });
await _subjectVisitRepository.SaveChangesAsync();
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.MassTransit.Consumer.Dto
{
public class SendImageReuploadEmailInDto
{
public EmailNoticeConfig EmailNoticeConfig { get; set; }
public EmailBusinessScenario Scenario { get; set; }
public SubjectVisit SubjectVisit { get; set; }
public Guid TrialId { get; set; }
public List<UserTypeEnum> UserTypes { get; set; } = null;
public ImageBackStateEnum ImageBackStateEnum { get; set; } = ImageBackStateEnum.None;
public RequestBackStateEnum RequestBackStateEnum { get; set; } = RequestBackStateEnum.NotRequest;
public ReReadingApplyState ReReadingApplyState { get; set; } = ReReadingApplyState.Default;
}
}

View File

@ -0,0 +1,510 @@
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.MassTransit.Command;
using IRaCIS.Core.Application.MassTransit.Consumer.Dto;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Domain;
using IRaCIS.Core.Domain._DomainEvent;
using IRaCIS.Core.Domain.BaseModel;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore.Common;
using MassTransit;
using MassTransit.Mediator;
using MassTransit.Scheduling;
using Medallion.Threading;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Options;
using MimeKit;
using Newtonsoft.Json;
using Panda.DynamicWebApi.Attributes;
using RestSharp;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.MassTransit.Consumer;
/// <summary>
/// 影像重传和阅片人筛选相关邮件发送
/// </summary>
public class ImageConsumer(
IRepository<UserRole> _userRoleRepository,
IRepository<TrialUserRole> _trialUseRoleRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<Trial> _trialRepository,
IRepository<Enroll> _enrollRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<ReadModule> _readModuleRepository,
IRepository<EmailNoticeUserType> _emailNoticeUserTypeRepository,
IRepository<TrialSite> _trialSiteRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) :
IConsumer<DirectApplyReupdloadEvent>,
IConsumer<CheckReuploadEvent>,
IConsumer<QCChanllengeReuploadEvent>,
IConsumer<HaveReadVisitTaskReReading>,
IConsumer<ReviewerPMApplyEvent>,
IConsumer<ReviewerSPMApprovedEvent>
{
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
/// <summary>
/// 处理直接申请流程的重传事件
/// </summary>
public async Task Consume(ConsumeContext<DirectApplyReupdloadEvent> context)
{
Console.WriteLine("发送【影像重传-直接申请流程】邮件!!!");
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
var subjectVisitId = context.Message.SubjectVisitId;
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == subjectVisitId).Include(x => x.Subject).FirstNotNullAsync();
var trialId = subjectVisit.TrialId;
List<UserTypeEnum> userTypes = null;
// 根据申请角色和状态确定邮件场景
EmailBusinessScenario scenario;
if (context.Message.ImageBackState == ImageBackStateEnum.None)
{
switch (context.Message.ApplyUserRole)
{
case ImageBackApplyEnum.IQCRequestBack:
scenario = EmailBusinessScenario.ImageQC_IQCApplyRe_Uploading; // 64
break;
case ImageBackApplyEnum.CRCRequestBack:
scenario = EmailBusinessScenario.ImageUploadCRCApplyRe_Uploading; // 65
break;
default:
scenario = EmailBusinessScenario.ImageQC_IQCApplyRe_Uploading; // 64
break;
}
}
else
{
scenario = EmailBusinessScenario.ImageReUpload_PMApprovalRe_Uploading; // 66
if (context.Message.ApplyUserRole == ImageBackApplyEnum.IQCRequestBack)
{
userTypes = new List<UserTypeEnum>() { UserTypeEnum.IQC, UserTypeEnum.ClinicalResearchCoordinator };
}
else if (context.Message.ApplyUserRole == ImageBackApplyEnum.CRCRequestBack)
{
userTypes = new List<UserTypeEnum>() { UserTypeEnum.ClinicalResearchCoordinator };
}
}
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsEnable && t.IsAutoSend).FirstOrDefault();
if (emailConfig != null)
{
var inDto = new SendImageReuploadEmailInDto
{
EmailNoticeConfig = emailConfig,
Scenario = scenario,
SubjectVisit = subjectVisit,
TrialId = trialId,
UserTypes = userTypes,
ImageBackStateEnum = context.Message.ImageBackState
};
await SendImageReuploadEmail(inDto);
}
}
/// <summary>
/// 处理一致性核查申请重传事件
/// </summary>
public async Task Consume(ConsumeContext<CheckReuploadEvent> context)
{
Console.WriteLine("发送【一致性核查-影像重传】邮件!!!");
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
var subjectVisitId = context.Message.SubjectVisitId;
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == subjectVisitId).Include(x => x.Subject).FirstNotNullAsync();
var trialId = subjectVisit.TrialId;
// 根据状态确定邮件场景
EmailBusinessScenario scenario;
switch (context.Message.RequestBackState)
{
case RequestBackStateEnum.CRC_RequestBack:
scenario = EmailBusinessScenario.DataReconciliation_CRCApplyRe_Uploading; // 62
break;
case RequestBackStateEnum.PM_AgressBack:
case RequestBackStateEnum.PM_NotAgree:
scenario = EmailBusinessScenario.DataReconciliation_PMApprovalRe_Uploading; // 63
break;
default:
return; // 其他状态不发送邮件
}
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsEnable && t.IsAutoSend).FirstOrDefault();
if (emailConfig != null)
{
var inDto = new SendImageReuploadEmailInDto
{
EmailNoticeConfig = emailConfig,
Scenario = scenario,
SubjectVisit = subjectVisit,
TrialId = trialId,
RequestBackStateEnum = context.Message.RequestBackState,
};
await SendImageReuploadEmail(inDto);
}
}
/// <summary>
/// 处理质疑CRC申请重传事件
/// </summary>
public async Task Consume(ConsumeContext<QCChanllengeReuploadEvent> context)
{
Console.WriteLine("发送【影像质疑-影像重传】邮件!!!");
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
var subjectVisitId = context.Message.SubjectVisitId;
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == subjectVisitId).Include(x => x.Subject).FirstNotNullAsync();
var trialId = subjectVisit.TrialId;
// 根据状态确定邮件场景
EmailBusinessScenario scenario;
switch (context.Message.ReuploadEnum)
{
case QCChanllengeReuploadEnum.CRCRequestReupload:
scenario = EmailBusinessScenario.ImageQueryCRCApplyRe_Uploading; // 60
break;
case QCChanllengeReuploadEnum.QCAgreeUpload:
scenario = EmailBusinessScenario.ImageQuery_IQCApprovalRe_Uploading; // 61
break;
default:
return; // 其他状态不发送邮件
}
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsEnable && t.IsAutoSend).FirstOrDefault();
if (emailConfig != null)
{
var inDto = new SendImageReuploadEmailInDto
{
EmailNoticeConfig = emailConfig,
Scenario = scenario,
SubjectVisit = subjectVisit,
TrialId = trialId
};
await SendImageReuploadEmail(inDto);
}
}
/// <summary>
/// 处理已阅任务重阅申请事件
/// </summary>
public async Task Consume(ConsumeContext<HaveReadVisitTaskReReading> context)
{
Console.WriteLine("发送【重阅-影像重传】邮件!!!");
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
var visitTaskId = context.Message.VisitTaskId;
// 获取VisitTask关联的SubjectVisit
var visitTask = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x => x.Subject).Include(x => x.SourceSubjectVisit).FirstNotNullAsync();
var subjectVisit = new SubjectVisit() { };
if (visitTask.SourceSubjectVisitId != null)
{
subjectVisit = visitTask.SourceSubjectVisit;
}
else if (visitTask.SouceReadModuleId != null)
{
var readModule = await _readModuleRepository.Where(x => x.Id == visitTask.SouceReadModuleId).Include(x => x.SubjectVisit).FirstOrDefaultAsync();
subjectVisit = readModule.SubjectVisit;
}
var trialId = subjectVisit.TrialId;
// 根据状态确定邮件场景
EmailBusinessScenario scenario;
switch (context.Message.ReReadingApplyState)
{
case ReReadingApplyState.TrialGroupHaveApplyed:
scenario = EmailBusinessScenario.ReadTracking_PMApplyRe_Reading; // 67
break;
case ReReadingApplyState.Agree:
case ReReadingApplyState.Reject:
scenario = EmailBusinessScenario.Re_ReadApproval_SPMCPMApprovalRe_Reading; // 68
break;
default:
return; // 其他状态不发送邮件
}
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsEnable && t.IsAutoSend).FirstOrDefault();
if (emailConfig != null)
{
var inDto = new SendImageReuploadEmailInDto
{
EmailNoticeConfig = emailConfig,
Scenario = scenario,
SubjectVisit = subjectVisit,
TrialId = trialId,
ReReadingApplyState= context.Message.ReReadingApplyState,
};
await SendImageReuploadEmail(inDto);
}
}
/// <summary>
/// 发送影像重传相关邮件的通用方法
/// </summary>
private async Task SendImageReuploadEmail(SendImageReuploadEmailInDto inDto)
{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
inDto.SubjectVisit = await _subjectVisitRepository.Where(x => x.Id == inDto.SubjectVisit.Id).Include(x => x.Subject).FirstNotNullAsync();
// 获取项目信息
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == inDto.TrialId);
List<UserTypeEnum> filterUserTypeList = new List<UserTypeEnum>()
{
UserTypeEnum.ClinicalResearchCoordinator,
UserTypeEnum.CRA,
};
// 根据不同场景获取不同角色的用户 先排除CRC和CRA
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == inDto.TrialId && !x.TrialUser.IsDeleted && !filterUserTypeList.Contains(x.UserRole.UserTypeEnum) ).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
// CRC和CRA单独取
var crcAndcraUserList = await _trialSiteRepository.Where(x => x.Id == inDto.SubjectVisit.TrialSiteId).SelectMany(x => x.CRCUserList.Select(y => y.UserRole)).ToListAsync();
trialUserList.AddRange(crcAndcraUserList);
// 根据场景确定收件人
List<UserRole> toUserList = new List<UserRole>();
List<UserRole> ccUserList = new List<UserRole>();
var emailNoticeUserList = await _emailNoticeUserTypeRepository.Where(x => x.EmailNoticeConfigId == inDto.EmailNoticeConfig.Id).ToListAsync();
var userTypeEnumList = emailNoticeUserList.Select(x => x.UserType).ToList();
if (inDto.UserTypes != null)
{
userTypeEnumList = inDto.UserTypes;
}
if (inDto.UserTypes == null)
{
var toList = emailNoticeUserList.Where(x => x.EmailUserType == EmailUserType.To).Select(x => x.UserType).ToList();
toUserList = trialUserList.Where(x => toList.Contains(x.UserTypeEnum)).ToList();
}
else
{
var toList = inDto.UserTypes;
toUserList = trialUserList.Where(x => toList.Contains(x.UserTypeEnum)).ToList();
}
var ccList = emailNoticeUserList.Where(x => x.EmailUserType == EmailUserType.Copy).Select(x => x.UserType).ToList();
ccUserList = trialUserList.Where(x => ccList.Contains(x.UserTypeEnum)).ToList();
// 如果没有收件人,则不发送邮件
if (toUserList.Count == 0)
{
return;
}
List<DictionaryDto> dictionaryDtos = new List<DictionaryDto>() {
new DictionaryDto (){DictionaryCode= "YesOrNo",EnumValue=inDto.SubjectVisit.IsUrgent.ToString().ToLower(), }, //是否加急
};
switch (inDto.Scenario)
{
case EmailBusinessScenario.Re_ReadApproval_SPMCPMApprovalRe_Reading:
dictionaryDtos.Add(new DictionaryDto() { DictionaryCode = "ReReadingApplyState", EnumValue = inDto.ReReadingApplyState.GetEnumInt(), });
break;
case EmailBusinessScenario.DataReconciliation_PMApprovalRe_Uploading:
dictionaryDtos.Add(new DictionaryDto() { DictionaryCode = "RequestBackState", EnumValue = inDto.RequestBackStateEnum.GetEnumInt(), });
break;
default:
dictionaryDtos.Add(new DictionaryDto() { DictionaryCode = "ImageBackStateEnum", EnumValue = inDto.ImageBackStateEnum.GetEnumInt(), });//审批结果
break;
}
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
{
DictionaryRepository = _dictionaryRepository,
IsEn_US = isEn_US,
DictionaryList = dictionaryDtos
});
foreach (var userinfo in toUserList)
{
var messageToSend = new MimeMessage();
// 发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
// 添加抄送
foreach (var ccUser in ccUserList)
{
messageToSend.Cc.Add(new MailboxAddress(String.Empty, ccUser.EMail));
}
// 格式化邮件内容
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var subjectCode = inDto.SubjectVisit.Subject.Code;
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, inDto.SubjectVisit.VisitName);
var htmlBodyStr = string.Format(
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
userinfo.FullName, // 用户名 {0}
trialInfo.ExperimentName, // 项目 {1}
subjectCode, // 受试者 {2}
inDto.SubjectVisit.VisitName, // 访视 {3}
dictionValue[0], // 是否加急 {4}
dictionValue[1], // 审批结果 {5}
_systemEmailConfig.SiteUrl // 链接 {6}
);
return (topicStr, htmlBodyStr);
};
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(inDto.EmailNoticeConfig, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
}
}
/// <summary>
/// 处理PM申请阅片人筛选事件
/// </summary>
public async Task Consume(ConsumeContext<ReviewerPMApplyEvent> context)
{
Console.WriteLine("发送【阅片人筛选-PM申请审批】邮件");
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
// 获取项目信息
var enrollIdList = context.Message.EnrollIdList;
if (enrollIdList == null || !enrollIdList.Any())
{
return;
}
// 获取第一个Enroll的TrialId
var enrollId = enrollIdList.First();
var enroll = await _enrollRepository.Where(x => x.Id == enrollId).FirstNotNullAsync();
var trialId = enroll.TrialId;
// 设置邮件场景
var scenario = EmailBusinessScenario.ReviewerSelection_PMApplyApproving; // 69
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsEnable && t.IsAutoSend).FirstOrDefault();
if (emailConfig != null)
{
await SendReviewerSelectionEmail(emailConfig, trialId, enrollIdList);
}
}
/// <summary>
/// 处理SPM审批阅片人筛选事件
/// </summary>
public async Task Consume(ConsumeContext<ReviewerSPMApprovedEvent> context)
{
Console.WriteLine("发送【阅片人筛选-SPM审批】邮件");
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
// 获取项目信息
var enrollIdList = context.Message.EnrollIdList;
if (enrollIdList == null || !enrollIdList.Any())
{
return;
}
// 获取第一个Enroll的TrialId
var enrollId = enrollIdList.First();
var enroll = await _enrollRepository.Where(x => x.Id == enrollId).FirstNotNullAsync();
var trialId = enroll.TrialId;
// 设置邮件场景
var scenario = EmailBusinessScenario.ReviewerSelection_SPMCPMApproval; // 70
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsEnable && t.IsAutoSend).FirstOrDefault();
if (emailConfig != null)
{
await SendReviewerSelectionEmail(emailConfig, trialId, enrollIdList);
}
}
/// <summary>
/// 发送阅片人筛选相关邮件的通用方法
/// </summary>
private async Task SendReviewerSelectionEmail(EmailNoticeConfig emailNoticeConfig, Guid trialId, List<Guid> enrollIdList)
{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
// 获取项目信息
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
// 根据不同场景获取不同角色的用户
var trialUser = await _trialUseRoleRepository.Where(x => x.TrialId == trialId && !x.TrialUser.IsDeleted).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
// 根据场景确定收件人
List<UserRole> toUserList = new List<UserRole>();
List<UserRole> ccUserList = new List<UserRole>();
var emailNoticeUserList = await _emailNoticeUserTypeRepository.Where(x => x.EmailNoticeConfigId == emailNoticeConfig.Id).ToListAsync();
var toList = emailNoticeUserList.Where(x => x.EmailUserType == EmailUserType.To).Select(x => x.UserType).ToList();
toUserList = trialUser.Where(x => toList.Contains(x.UserTypeEnum)).ToList();
var ccList = emailNoticeUserList.Where(x => x.EmailUserType == EmailUserType.Copy && x.UserType != UserTypeEnum.ClinicalResearchCoordinator).Select(x => x.UserType).ToList();
ccUserList = trialUser.Where(x => ccList.Contains(x.UserTypeEnum)).ToList();
// 如果没有收件人,则不发送邮件
if (toUserList.Count == 0)
{
return;
}
foreach (var userinfo in toUserList)
{
var messageToSend = new MimeMessage();
// 发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
// 添加抄送
foreach (var ccUser in ccUserList)
{
messageToSend.Cc.Add(new MailboxAddress(String.Empty, ccUser.EMail));
}
// 格式化邮件内容
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
userinfo.FullName, // 用户名 {0}
trialInfo.ExperimentName, // 项目 {1}
"", // 受试者 {2} - 阅片人筛选不涉及受试者
"", // 访视 {3} - 阅片人筛选不涉及访视
"", // 是否加急 {4}
"", // 预留 {5}
_systemEmailConfig.SiteUrl // 链接 {6}
);
return (topicStr, htmlBodyStr);
};
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailNoticeConfig, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
}
}
}

View File

@ -22,14 +22,14 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer;
/// 加急的医学反馈任务 通知MIM
/// </summary>
public class UrgentMedicalReviewAddedEventConsumer(
IRepository<User> _userRepository,
IRepository<UserRole> _userRoleRepository,
IRepository<TaskMedicalReview> _taskMedicalReviewRepository,
IRepository<Trial> _trialRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig
) : IConsumer<UrgentMedicalReviewAddedEvent>
{
@ -48,52 +48,62 @@ public class UrgentMedicalReviewAddedEventConsumer(
var medicalReviewId = context.Message.MedicalReviewId;
var medicalReview = await _taskMedicalReviewRepository.Where(x => x.Id == medicalReviewId).Include(x => x.VisitTask).Include(x=>x.MedicalManagerUser).FirstOrDefaultAsync();
var medicalReview = await _taskMedicalReviewRepository.Where(x => x.Id == medicalReviewId).Include(x => x.VisitTask).Include(x => x.MedicalManagerUser).FirstOrDefaultAsync();
if (medicalReview.MedicalManagerUserId == null)
{
Console.WriteLine("MIMId为空 ID"+ medicalReviewId);
Console.WriteLine("MIMId为空 ID" + medicalReviewId);
return;
}
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == medicalReview.VisitTask.TrialReadingCriterionId);
var userinfo = await _userRepository.Where(x => x.Id == medicalReview.MedicalManagerUserId).FirstOrDefaultAsync();
var taskInfo = await _visitTaskRepository.Where(x => x.Id == medicalReview.VisitTaskId).Include(x=>x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
var trialId = medicalReview.TrialId;
var scenario = context.Message.IsPD ? EmailBusinessScenario.PDVerification_MedicalQC : EmailBusinessScenario.EligibilityVerification_MedicalQC;
var visitid = taskInfo.SourceSubjectVisit == null ? taskInfo.ReadModule.SubjectVisitId : taskInfo.SourceSubjectVisitId;
var trialEmailConfig = _trialEmailNoticeConfigrepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == medicalReview.TrialId);
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
if (trialEmailConfig != null)
{
DictionaryRepository = _dictionaryRepository,
IsEn_US = isEn_US,
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == medicalReview.VisitTask.TrialReadingCriterionId);
var userinfo = await _userRoleRepository.Where(x => x.Id == medicalReview.MedicalManagerUserId).FirstOrDefaultAsync();
var taskInfo = await _visitTaskRepository.Where(x => x.Id == medicalReview.VisitTaskId).Include(x => x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
DictionaryList = new List<DictionaryDto>()
{
var visitid = taskInfo.SourceSubjectVisit == null ? taskInfo.ReadModule.SubjectVisitId : taskInfo.SourceSubjectVisitId;
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == medicalReview.TrialId);
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
{
DictionaryRepository = _dictionaryRepository,
IsEn_US = isEn_US,
DictionaryList = new List<DictionaryDto>()
{
new DictionaryDto (){DictionaryCode= "ReadingCategory",EnumValue=taskInfo.ReadingCategory.GetEnumInt(), },
new DictionaryDto (){DictionaryCode= "MedicalReviewDoctorUserIdea",EnumValue=medicalReview.DoctorUserIdeaEnum.GetEnumInt(), },
new DictionaryDto (){DictionaryCode= "MedicalReviewAuditState",EnumValue=medicalReview.AuditState.GetEnumInt(), },
new DictionaryDto (){DictionaryCode= "YesOrNo",EnumValue=taskInfo.IsUrgent.ToString().ToLower(), }
}
}) ;
});
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
@ -107,7 +117,7 @@ public class UrgentMedicalReviewAddedEventConsumer(
subjectName, // 受试者 {3}
taskInfo.TaskBlindName, // 访视 {4}
dictionValue[0], // 任务类型 {5}
//dictionValue[1], // 阅片人是否同意 {6}
//dictionValue[1], // 阅片人是否同意 {6}
dictionValue[2], // 审核状态 {6}
dictionValue[3], // 是否加急 {7}
_systemEmailConfig.SiteUrl // 链接 {8}
@ -116,26 +126,25 @@ public class UrgentMedicalReviewAddedEventConsumer(
return (topicStr, htmlBodyStr);
};
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(_emailNoticeConfigrepository,
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
context.Message.IsPD ? EmailBusinessScenario.PDVerification_MedicalQC : EmailBusinessScenario.EligibilityVerification_MedicalQC,
messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
}
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
}
}
//IR 回复医学反馈通知MIM
public class UrgentIRRepliedMedicalReviewConsumer(
IRepository<User> _userRepository,
IRepository<UserRole> _userRoleRepository,
IRepository<TaskMedicalReview> _taskMedicalReviewRepository,
IRepository<Trial> _trialRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) : IConsumer<UrgentIRRepliedMedicalReview>
{
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
@ -151,79 +160,85 @@ public class UrgentIRRepliedMedicalReviewConsumer(
var medicalReview = await _taskMedicalReviewRepository.Where(x => x.Id == medicalReviewId).Include(x => x.VisitTask).Include(x => x.MedicalManagerUser).FirstOrDefaultAsync();
if (medicalReview.MedicalManagerUserId == null)
{
Console.WriteLine("MIMId为空 ID" + medicalReviewId);
return;
}
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == medicalReview.VisitTask.TrialReadingCriterionId);
var userinfo = await _userRepository.Where(x => x.Id == medicalReview.MedicalManagerUserId).FirstOrDefaultAsync();
var trialId = medicalReview.TrialId;
var taskInfo = await _visitTaskRepository.Where(x => x.Id == medicalReview.VisitTaskId).Include(x => x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
var scenario = context.Message.IsPD ? EmailBusinessScenario.PDVerification_ExpeditedMedicalQCResponse : EmailBusinessScenario.EligibilityVerification_ExpeditedMedicalQCResponse;
var trialEmailConfig = _trialEmailNoticeConfigrepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
var visitid = taskInfo.SourceSubjectVisit == null ? taskInfo.ReadModule.SubjectVisitId : taskInfo.SourceSubjectVisitId;
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == medicalReview.TrialId);
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
if (trialEmailConfig != null)
{
DictionaryRepository = _dictionaryRepository,
IsEn_US = isEn_US,
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == medicalReview.VisitTask.TrialReadingCriterionId);
var userinfo = await _userRoleRepository.Where(x => x.Id == medicalReview.MedicalManagerUserId).FirstOrDefaultAsync();
var taskInfo = await _visitTaskRepository.Where(x => x.Id == medicalReview.VisitTaskId).Include(x => x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
DictionaryList = new List<DictionaryDto>()
var visitid = taskInfo.SourceSubjectVisit == null ? taskInfo.ReadModule.SubjectVisitId : taskInfo.SourceSubjectVisitId;
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == medicalReview.TrialId);
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
{
DictionaryRepository = _dictionaryRepository,
IsEn_US = isEn_US,
DictionaryList = new List<DictionaryDto>()
{
new DictionaryDto (){DictionaryCode= "ReadingCategory",EnumValue=taskInfo.ReadingCategory.GetEnumInt(), },
new DictionaryDto (){DictionaryCode= "MedicalReviewDoctorUserIdea",EnumValue=medicalReview.DoctorUserIdeaEnum.GetEnumInt(), },
new DictionaryDto (){DictionaryCode= "MedicalReviewAuditState",EnumValue=medicalReview.AuditState.GetEnumInt(), },
new DictionaryDto (){DictionaryCode= "YesOrNo",EnumValue=taskInfo.IsUrgent.ToString().ToLower(), }
}
});
});
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var subjectCode = taskInfo.BlindSubjectCode.IsNullOrEmpty() ? taskInfo.Subject.Code : taskInfo.BlindSubjectCode;
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, taskInfo.TaskBlindName);
var htmlBodyStr = string.Format(
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
userinfo.FullName, // 用户名 {0}
trialInfo.ExperimentName, // 项目 {1}
criterion.CriterionName, // 阅片标准 {2}
subjectCode, // 受试者 {3}
taskInfo.TaskBlindName, // 访视 {4}
dictionValue[0], // 任务类型 {5}
dictionValue[1], // 阅片人是否同意 {6}
dictionValue[2], // 审核状态 {7}
dictionValue[3], // 是否加急 {8}
_systemEmailConfig.SiteUrl // 链接 {9}
);
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var subjectCode = taskInfo.BlindSubjectCode.IsNullOrEmpty() ? taskInfo.Subject.Code : taskInfo.BlindSubjectCode;
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, taskInfo.TaskBlindName);
var htmlBodyStr = string.Format(
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
userinfo.FullName, // 用户名 {0}
trialInfo.ExperimentName, // 项目 {1}
criterion.CriterionName, // 阅片标准 {2}
subjectCode, // 受试者 {3}
taskInfo.TaskBlindName, // 访视 {4}
dictionValue[0], // 任务类型 {5}
dictionValue[1], // 阅片人是否同意 {6}
dictionValue[2], // 审核状态 {7}
dictionValue[3], // 是否加急 {8}
_systemEmailConfig.SiteUrl // 链接 {9}
);
return (topicStr, htmlBodyStr);
};
return (topicStr, htmlBodyStr);
};
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(_emailNoticeConfigrepository,
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
}
context.Message.IsPD ? EmailBusinessScenario.PDVerification_ExpeditedMedicalQCResponse : EmailBusinessScenario.EligibilityVerification_ExpeditedMedicalQCResponse,
messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
}
}
@ -231,14 +246,14 @@ public class UrgentIRRepliedMedicalReviewConsumer(
/// MIM 回复医学返回通知IR
/// </summary>
public class UrgentMIMRepliedMedicalReviewConsumer(
IRepository<User> _userRepository,
IRepository<UserRole> _userRoleRepository,
IRepository<TaskMedicalReview> _taskMedicalReviewRepository,
IRepository<Trial> _trialRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) : IConsumer<UrgentMIMRepliedMedicalReview>
{
@ -254,146 +269,48 @@ public class UrgentMIMRepliedMedicalReviewConsumer(
Console.WriteLine("发送(022) 【加急医学反馈】邮件!!!");
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
var medicalReviewId = context.Message.MedicalReviewId;
var medicalReview = await _taskMedicalReviewRepository.Where(x => x.Id == medicalReviewId).Include(x => x.VisitTask).Include(x => x.MedicalManagerUser).FirstOrDefaultAsync();
if (medicalReview.MedicalManagerUserId == null)
{
Console.WriteLine("MIMId为空 ID" + medicalReviewId);
return;
}
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == medicalReview.VisitTask.TrialReadingCriterionId);
var taskInfo = await _visitTaskRepository.Where(x => x.Id == medicalReview.VisitTaskId).Include(x => x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
var userinfo = await _userRepository.Where(x => x.Id == taskInfo.DoctorUserId).FirstOrDefaultAsync();
var trialId = medicalReview.TrialId;
var scenario = EmailBusinessScenario.ExpeditedMedicalQCToIR;
var trialEmailConfig = _trialEmailNoticeConfigrepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
var visitid = taskInfo.SourceSubjectVisit == null ? taskInfo.ReadModule.SubjectVisitId : taskInfo.SourceSubjectVisitId;
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == medicalReview.TrialId);
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
if (trialEmailConfig != null)
{
DictionaryRepository = _dictionaryRepository,
IsEn_US = isEn_US,
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == medicalReview.VisitTask.TrialReadingCriterionId);
var taskInfo = await _visitTaskRepository.Where(x => x.Id == medicalReview.VisitTaskId).Include(x => x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
var userinfo = await _userRoleRepository.Where(x => x.Id == taskInfo.DoctorUserId).FirstOrDefaultAsync();
DictionaryList = new List<DictionaryDto>()
{
new DictionaryDto (){DictionaryCode= "ReadingCategory",EnumValue=taskInfo.ReadingCategory.GetEnumInt(), },
new DictionaryDto (){DictionaryCode= "IsPass",EnumValue=medicalReview.IsHaveQuestion.ToString().ToLower(), },// 审核结论
new DictionaryDto (){DictionaryCode= "AuditAdvice",EnumValue=medicalReview.AuditAdviceEnum.GetEnumInt(), },// 审核建议
new DictionaryDto (){DictionaryCode= "YesOrNo",EnumValue=taskInfo.IsUrgent.ToString().ToLower(), }, //是否加急
}
});
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var subjectCode = taskInfo.BlindSubjectCode.IsNullOrEmpty() ? taskInfo.Subject.Code : taskInfo.BlindSubjectCode;
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, taskInfo.TaskBlindName);
var htmlBodyStr = string.Format(
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
userinfo.FullName, // 用户名 {0}
trialInfo.ExperimentName, // 项目 {1}
subjectCode, // 受试者 {2}
taskInfo.TaskBlindName, // 访视 {3}
criterion.CriterionName, // 阅片标准 {4}
dictionValue[0], // 任务类型 {5}
dictionValue[1], // 审核结论 {6}
dictionValue[2], // 医学审核建议 {7}
dictionValue[3], // 是否加急 {8}
_systemEmailConfig.SiteUrl // 链接 {9}
);
return (topicStr, htmlBodyStr);
};
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(_emailNoticeConfigrepository,
EmailBusinessScenario.ExpeditedMedicalQCToIR,
messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
}
}
/// <summary>
/// 加急阅片 IR 申请重阅 或者PM 申请重阅
/// </summary>
public class UrgentIRApplyedReReadingConsumer(
IRepository<User> _userRepository,
IRepository<TrialUser> _trialUseRepository,
IRepository<TaskMedicalReview> _taskMedicalReviewRepository,
IRepository<Trial> _trialRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) : IConsumer<UrgentApplyedReReading>
{
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
public async Task Consume(ConsumeContext<UrgentApplyedReReading> context)
{
Console.WriteLine("发送(024,025) 【加急医学反馈】邮件!!!");
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
var visitTaskId = context.Message.VisitTaskId;
var taskInfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x => x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == taskInfo.TrialReadingCriterionId);
var doctorInfo = await _userRepository.Where(x => x.Id == taskInfo.DoctorUserId).FirstOrDefaultAsync();
var trialUser = await _trialUseRepository.Where(x => x.TrialId == taskInfo.TrialId).Include(x => x.User).Select(x=>x.User).ToListAsync();
var userinfoList = trialUser.Where(x => x.UserTypeEnum == UserTypeEnum.ProjectManager||x.UserTypeEnum==UserTypeEnum.APM).ToList();
if (context.Message.ReReadingApplyState == ReReadingApplyState.TrialGroupHaveApplyed)
{
userinfoList = trialUser.Where(x => x.UserTypeEnum == UserTypeEnum.CPM || x.UserTypeEnum == UserTypeEnum.SPM).ToList();
}
var visitid = taskInfo.SourceSubjectVisit == null ? taskInfo.ReadModule.SubjectVisitId : taskInfo.SourceSubjectVisitId;
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
var visitid = taskInfo.SourceSubjectVisit == null ? taskInfo.ReadModule.SubjectVisitId : taskInfo.SourceSubjectVisitId;
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
foreach (var userinfo in userinfoList)
{
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == taskInfo.TrialId);
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == medicalReview.TrialId);
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
@ -402,10 +319,14 @@ public class UrgentIRApplyedReReadingConsumer(
DictionaryRepository = _dictionaryRepository,
IsEn_US = isEn_US,
DictionaryList = new List<DictionaryDto>()
{
new DictionaryDto (){DictionaryCode= "ReadingCategory",EnumValue=taskInfo.ReadingCategory.GetEnumInt(), }, //任务类型
new DictionaryDto (){DictionaryCode= "RequestReReadingResult",EnumValue="0", }, //审批结果 都是待审批
new DictionaryDto (){DictionaryCode= "ReadingCategory",EnumValue=taskInfo.ReadingCategory.GetEnumInt(), },
new DictionaryDto (){DictionaryCode= "IsPass",EnumValue=medicalReview.IsHaveQuestion.ToString().ToLower(), },// 审核结论
new DictionaryDto (){DictionaryCode= "AuditAdvice",EnumValue=medicalReview.AuditAdviceEnum.GetEnumInt(), },// 审核建议
new DictionaryDto (){DictionaryCode= "YesOrNo",EnumValue=taskInfo.IsUrgent.ToString().ToLower(), }, //是否加急
}
});
@ -419,30 +340,133 @@ public class UrgentIRApplyedReReadingConsumer(
trialInfo.ExperimentName, // 项目 {1}
subjectCode, // 受试者 {2}
taskInfo.TaskBlindName, // 访视 {3}
dictionValue[0], // 任务类型 {4}
doctorInfo.FullName, // 阅片人 {5}
criterion.CriterionName, // 阅片标准 {6}
dictionValue[1], // 审批结果 {7}
_systemEmailConfig.SiteUrl // 链接 {8}
criterion.CriterionName, // 阅片标准 {4}
dictionValue[0], // 任务类型 {5}
dictionValue[1], // 审核结论 {6}
dictionValue[2], // 医学审核建议 {7}
dictionValue[3], // 是否加急 {8}
_systemEmailConfig.SiteUrl // 链接 {9}
);
return (topicStr, htmlBodyStr);
};
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(_emailNoticeConfigrepository,
context.Message.ReReadingApplyState == ReReadingApplyState.TrialGroupHaveApplyed? EmailBusinessScenario.ReReadFromPMApproval: EmailBusinessScenario.ReReadFromIRApproval,
messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
}
}
}
/// <summary>
/// 加急阅片 IR 申请重阅 或者PM 申请重阅
/// </summary>
public class UrgentIRApplyedReReadingConsumer(
IRepository<UserRole> _userRoleRepository,
IRepository<TrialUserRole> _trialUseRoleRepository,
IRepository<TaskMedicalReview> _taskMedicalReviewRepository,
IRepository<Trial> _trialRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) : IConsumer<UrgentApplyedReReading>
{
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
public async Task Consume(ConsumeContext<UrgentApplyedReReading> context)
{
Console.WriteLine("发送(024,025) 【加急医学反馈】邮件!!!");
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
var visitTaskId = context.Message.VisitTaskId;
var taskInfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x => x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
var trialId=taskInfo.TrialId;
var scenario = context.Message.ReReadingApplyState == ReReadingApplyState.TrialGroupHaveApplyed ? EmailBusinessScenario.ReReadFromPMApproval : EmailBusinessScenario.ReReadFromIRApproval;
var trialEmailConfig = _trialEmailNoticeConfigrepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
if (trialEmailConfig != null)
{
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == taskInfo.TrialReadingCriterionId);
var doctorInfo = await _userRoleRepository.Where(x => x.Id == taskInfo.DoctorUserId).FirstOrDefaultAsync();
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == taskInfo.TrialId && x.TrialUser.IsDeleted==false).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.ProjectManager || x.UserTypeEnum == UserTypeEnum.APM).ToList();
if (context.Message.ReReadingApplyState == ReReadingApplyState.TrialGroupHaveApplyed)
{
userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.CPM || x.UserTypeEnum == UserTypeEnum.SPM).ToList();
}
var visitid = taskInfo.SourceSubjectVisit == null ? taskInfo.ReadModule.SubjectVisitId : taskInfo.SourceSubjectVisitId;
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
foreach (var userinfo in userinfoList)
{
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == taskInfo.TrialId);
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
{
DictionaryRepository = _dictionaryRepository,
IsEn_US = isEn_US,
DictionaryList = new List<DictionaryDto>()
{
new DictionaryDto (){DictionaryCode= "ReadingCategory",EnumValue=taskInfo.ReadingCategory.GetEnumInt(), }, //任务类型
new DictionaryDto (){DictionaryCode= "RequestReReadingResult",EnumValue="0", }, //审批结果 都是待审批
}
});
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var subjectCode = taskInfo.BlindSubjectCode.IsNullOrEmpty() ? taskInfo.Subject.Code : taskInfo.BlindSubjectCode;
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, taskInfo.TaskBlindName);
var htmlBodyStr = string.Format(
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
userinfo.FullName, // 用户名 {0}
trialInfo.ExperimentName, // 项目 {1}
subjectCode, // 受试者 {2}
taskInfo.TaskBlindName, // 访视 {3}
dictionValue[0], // 任务类型 {4}
doctorInfo.FullName, // 阅片人 {5}
criterion.CriterionName, // 阅片标准 {6}
dictionValue[1], // 审批结果 {7}
_systemEmailConfig.SiteUrl // 链接 {8}
);
return (topicStr, htmlBodyStr);
};
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
}
}
}
}

View File

@ -25,12 +25,12 @@ using System.Threading.Tasks;
namespace IRaCIS.Core.Application.MassTransit.Consumer;
/// <summary>
/// 用户提交 发送邮件 通知SPM 或者PM
/// 用户提交 发送邮件 通知SPM 或者PM 项目默认邮件,不用添加到项目中,直接发送的
/// </summary>
public class UserSiteSurveySubmitedEventConsumer(
IRepository<Trial> _trialRepository,
IRepository<TrialSite> _trialSiteRepository,
IRepository<TrialUser> _trialUserRepository,
IRepository<TrialUserRole> _trialUserRoleRepository,
IRepository<TrialSiteSurvey> _trialSiteSurveyRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig
@ -47,75 +47,83 @@ public class UserSiteSurveySubmitedEventConsumer(
var trialId = siteSurveyInfo.TrialId;
var trialUserList = await _trialUserRepository.Where(t => t.TrialId == siteSurveyInfo.TrialId)
.Where(t => t.User.UserTypeEnum == UserTypeEnum.SPM || t.User.UserTypeEnum == UserTypeEnum.CPM || t.User.UserTypeEnum == UserTypeEnum.ProjectManager || t.User.UserTypeEnum == UserTypeEnum.APM)
.Select(t => new { t.User.FullName, t.User.EMail, t.User.UserTypeEnum }).ToListAsync();
var sPMOrCPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.SPM || t.UserTypeEnum == UserTypeEnum.CPM).ToList();
var pmAndAPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserTypeEnum == UserTypeEnum.APM).ToList();
var messageToSend = new MimeMessage();
var toUserName = string.Empty;
//有SPM
if (sPMOrCPMList.Count > 0)
{
foreach (var user in sPMOrCPMList)
{
messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
}
toUserName = string.Join('、', sPMOrCPMList.Select(t => t.FullName));
foreach (var user in pmAndAPMList)
{
messageToSend.Cc.Add(new MailboxAddress(user.FullName, user.EMail));
}
}
else
{
foreach (var user in pmAndAPMList)
{
messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
}
toUserName = string.Join('、', pmAndAPMList.Select(t => t.FullName));
}
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
var siteInfo = await _trialSiteRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.Id == siteSurveyInfo.TrialSiteId, true);
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
toUserName,
siteInfo.TrialSiteCode,
siteInfo.TrialSiteAliasName,
siteSurveyInfo.UserName,
siteSurveyInfo.Email,
siteSurveyInfo.Phone,
_systemEmailConfig.SiteUrl
);
return (topicStr, htmlBodyStr);
};
var scenario = _trialSiteSurveyRepository.Where(t => t.Id != trialSiteSurveyId && t.TrialId == siteSurveyInfo.TrialId && t.TrialSiteId == siteSurveyInfo.TrialSiteId).IgnoreQueryFilters().Any() ?
EmailBusinessScenario.Approval_UpdateSiteSurvey : EmailBusinessScenario.Approval_SubmitSiteSurvey;
EmailBusinessScenario.Approval_UpdateSiteSurvey : EmailBusinessScenario.Approval_SubmitSiteSurvey;
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(_emailNoticeConfigrepository, scenario, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
if (emailConfig != null)
{
var trialUserList = await _trialUserRoleRepository.Where(t => t.TrialId == siteSurveyInfo.TrialId && t.TrialUser.IsDeleted == false)
.Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM || t.UserRole.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserRole.UserTypeEnum == UserTypeEnum.APM)
.Select(t => new { t.UserRole.FullName, t.UserRole.IdentityUser.EMail, t.UserRole.UserTypeEnum }).ToListAsync();
var sPMOrCPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.SPM || t.UserTypeEnum == UserTypeEnum.CPM).ToList();
var pmAndAPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserTypeEnum == UserTypeEnum.APM).ToList();
var messageToSend = new MimeMessage();
var toUserName = string.Empty;
//有SPM
if (sPMOrCPMList.Count > 0)
{
foreach (var user in sPMOrCPMList)
{
messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
}
toUserName = string.Join('、', sPMOrCPMList.Select(t => t.FullName));
foreach (var user in pmAndAPMList)
{
messageToSend.Cc.Add(new MailboxAddress(user.FullName, user.EMail));
}
}
else
{
foreach (var user in pmAndAPMList)
{
messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
}
toUserName = string.Join('、', pmAndAPMList.Select(t => t.FullName));
}
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
var siteInfo = await _trialSiteRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.Id == siteSurveyInfo.TrialSiteId, true);
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
toUserName,
siteInfo.TrialSiteCode,
siteInfo.TrialSiteAliasName,
siteSurveyInfo.UserName,
siteSurveyInfo.Email,
siteSurveyInfo.Phone,
_systemEmailConfig.SiteUrl
);
return (topicStr, htmlBodyStr);
};
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
}
}
}
@ -125,7 +133,7 @@ public class UserSiteSurveySubmitedEventConsumer(
/// </summary>
public class SiteSurveySPMSubmitedEventConsumer(
IRepository<Trial> _trialRepository,
IRepository<TrialUser> _trialUserRepository,
IRepository<TrialUserRole> _trialUserRoleRepository,
IRepository<TrialSite> _trialSiteRepository,
IRepository<TrialSiteSurvey> _trialSiteSurveyRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
@ -143,55 +151,65 @@ public class SiteSurveySPMSubmitedEventConsumer(
var trialId = siteSurveyInfo.TrialId;
var messageToSend = new MimeMessage();
var scenario = EmailBusinessScenario.Approval_SubmitSiteSurvey;
var trialUserList = _trialUserRepository.Where(t => t.TrialId == trialId)
.Where(t => t.User.UserTypeEnum == UserTypeEnum.SPM || t.User.UserTypeEnum == UserTypeEnum.CPM || t.User.UserTypeEnum == UserTypeEnum.ProjectManager || t.User.UserTypeEnum == UserTypeEnum.APM)
.Select(t => new { t.User.EMail, t.User.FullName, t.User.UserTypeEnum }).ToList();
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
var sPMOrCPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.SPM || t.UserTypeEnum == UserTypeEnum.CPM).ToList();
var pmAndAPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserTypeEnum == UserTypeEnum.APM).ToList();
var toUserName = string.Empty;
foreach (var item in pmAndAPMList)
if (emailConfig != null)
{
messageToSend.To.Add(new MailboxAddress(item.FullName, item.EMail));
var messageToSend = new MimeMessage();
toUserName = string.Join('、', pmAndAPMList.Select(t => t.FullName));
var trialUserList = _trialUserRoleRepository.Where(t => t.TrialId == trialId && t.TrialUser.IsDeleted == false)
.Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM || t.UserRole.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserRole.UserTypeEnum == UserTypeEnum.APM)
.Select(t => new { t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum }).ToList();
var sPMOrCPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.SPM || t.UserTypeEnum == UserTypeEnum.CPM).ToList();
var pmAndAPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserTypeEnum == UserTypeEnum.APM).ToList();
var toUserName = string.Empty;
foreach (var item in pmAndAPMList)
{
messageToSend.To.Add(new MailboxAddress(item.FullName, item.EMail));
toUserName = string.Join('、', pmAndAPMList.Select(t => t.FullName));
}
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
var siteInfo = await _trialSiteRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.Id == siteSurveyInfo.TrialSiteId, true);
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
toUserName,
siteInfo.TrialSiteCode, //中心编号
siteInfo.TrialSiteAliasName,//中心名称
siteSurveyInfo.UserName, //联系人
siteSurveyInfo.Email, //联系邮箱
siteSurveyInfo.Phone, //联系电话
_systemEmailConfig.SiteUrl
);
return (topicStr, htmlBodyStr);
};
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
}
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
var siteInfo = await _trialSiteRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.Id == siteSurveyInfo.TrialSiteId, true);
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
toUserName,
siteInfo.TrialSiteCode,
siteInfo.TrialSiteAliasName,
siteSurveyInfo.UserName,
siteSurveyInfo.Email,
siteSurveyInfo.Phone,
_systemEmailConfig.SiteUrl
);
return (topicStr, htmlBodyStr);
};
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(_emailNoticeConfigrepository, EmailBusinessScenario.Approval_SubmitSiteSurvey, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
}
}
@ -200,11 +218,11 @@ public class SiteSurveySPMSubmitedEventConsumer(
/// 调研表驳回发送邮件 之前已有,需要迁移过来
/// </summary>
public class SiteSurverRejectedEventConsumer(
IRepository<TrialUser> _trialUserRepository,
IRepository<TrialUserRole> _trialUserRoleRepository,
IRepository<Trial> _trialRepository,
IRepository<TrialSite> _trialSiteRepository,
IRepository<TrialSiteSurvey> _trialSiteSurveyRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig
) : IConsumer<SiteSurverRejectedEvent>
{
@ -216,83 +234,95 @@ public class SiteSurverRejectedEventConsumer(
var trialSiteSurveyId = context.Message.TrialSiteSurveyId;
var siteSurveyInfo = _trialSiteSurveyRepository.Where(t => t.Id == trialSiteSurveyId).FirstOrDefault().IfNullThrowException();
var siteSurveyInfo = _trialSiteSurveyRepository.Where(t => t.Id == trialSiteSurveyId ,ignoreQueryFilters:true).FirstOrDefault().IfNullThrowException();
var trialId = siteSurveyInfo.TrialId;
var messageToSend = new MimeMessage();
var scenario = EmailBusinessScenario.SiteSurveyReject;
var toUserName = siteSurveyInfo.UserName;
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
if (context.Message.IsHaveSPMOrCPM)
if (emailConfig != null)
{
//PM 驳回到SPM
if (siteSurveyInfo.State == TrialSiteSurveyEnum.CRCSubmitted)
var messageToSend = new MimeMessage();
var toUserName = siteSurveyInfo.UserName;
if (context.Message.IsHaveSPMOrCPM)
{
//var user = await _userRepository.FirstOrDefaultAsync(t => t.Id == siteSurveyInfo.PreliminaryUserId);
//name = user.FullName;
var sPMOrCPMList = _trialUserRepository.Where(t => t.TrialId == trialId)
.Where(t => t.User.UserTypeEnum == UserTypeEnum.SPM || t.User.UserTypeEnum == UserTypeEnum.CPM)
.Select(t => new { t.User.EMail, t.User.FullName, t.User.UserTypeEnum }).ToList();
foreach (var user in sPMOrCPMList)
//PM 驳回到SPM
if (siteSurveyInfo.State == TrialSiteSurveyEnum.CRCSubmitted)
{
messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
//var user = await _userRoleRepository.FirstOrDefaultAsync(t => t.Id == siteSurveyInfo.PreliminaryUserId);
//name = user.FullName;
var sPMOrCPMList = _trialUserRoleRepository.Where(t => t.TrialId == trialId && t.TrialUser.IsDeleted == false)
.Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM)
.Select(t => new { t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum }).ToList();
foreach (var user in sPMOrCPMList)
{
messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
}
toUserName = string.Join('、', sPMOrCPMList.Select(t => t.FullName));
}
//SPM 驳回到CRC
else if (siteSurveyInfo.State == TrialSiteSurveyEnum.ToSubmit)
{
messageToSend.To.Add(new MailboxAddress(toUserName, siteSurveyInfo.Email));
}
toUserName = string.Join('、', sPMOrCPMList.Select(t => t.FullName));
}
//SPM 驳回到CRC
else if (siteSurveyInfo.State == TrialSiteSurveyEnum.ToSubmit)
else
{
messageToSend.To.Add(new MailboxAddress(toUserName, siteSurveyInfo.Email));
//没有SPM PM驳回到CRC
messageToSend.To.Add(new MailboxAddress(String.Empty, siteSurveyInfo.Email));
}
}
else
{
//没有SPM PM驳回到CRC
messageToSend.To.Add(new MailboxAddress(String.Empty, siteSurveyInfo.Email));
}
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
var siteInfo = await _trialSiteRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.Id == siteSurveyInfo.TrialSiteId, true);
var siteInfo = await _trialSiteRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.Id == siteSurveyInfo.TrialSiteId, true);
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
toUserName,
trialInfo.TrialCode,
trialInfo.ResearchProgramNo,
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName,trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
toUserName,
trialInfo.TrialCode,
trialInfo.ResearchProgramNo,
trialInfo.ExperimentName,
siteInfo.TrialSiteCode,
siteInfo.TrialSiteAliasName,
siteSurveyInfo.LatestBackReason,
_systemEmailConfig.SiteUrl,
(siteSurveyInfo.State == TrialSiteSurveyEnum.ToSubmit ? "inline - block" : "none")
);
return (topicStr, htmlBodyStr);
};
siteInfo.TrialSiteCode, //中心编号
siteInfo.TrialSiteAliasName,//中心名称
siteSurveyInfo.LatestBackReason, //驳回原因
_systemEmailConfig.SiteUrl, //链接
(siteSurveyInfo.State == TrialSiteSurveyEnum.ToSubmit ? "inline - block" : "none")
);
return (topicStr, htmlBodyStr);
};
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
}
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(_emailNoticeConfigrepository, EmailBusinessScenario.SiteSurveyReject, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
}

View File

@ -30,13 +30,13 @@ public class MasstransiTestCommand
/// publish 请求流不会先到消费者,发布后,直接执行后续代码
///
/// </summary>
/// <param name="_userRepository"></param>
public class MasstransitTestConsumer(IRepository<User> _userRepository) : IConsumer<MasstransiTestCommand>
/// <param name="_userRoleRepository"></param>
public class MasstransitTestConsumer(IRepository<UserRole> _userRoleRepository) : IConsumer<MasstransiTestCommand>
{
public async Task Consume(ConsumeContext<MasstransiTestCommand> context)
{
Console.WriteLine(_userRepository._dbContext.GetHashCode());
Console.WriteLine(_userRoleRepository._dbContext.GetHashCode());
Console.WriteLine("Now is " + DateTime.Now.ToString());
Console.WriteLine($"MassTransit.Consumer :{context.Message.value}");

View File

@ -1,9 +1,11 @@
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Spreadsheet;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.MassTransit.Consumer;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Domain.Models;
using MassTransit;
using Microsoft.Extensions.Options;
using MimeKit;
@ -25,9 +27,10 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
public class UrgentIRUnReadTaskRecurringEventConsumer(
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<Trial> _trialRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<TrialUser> _trialUserRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IRepository<TrialUserRole> _trialUserRoleRepository,
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) : IConsumer<UrgentIRUnReadTaskRecurringEvent>
{
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
@ -35,144 +38,152 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
public async Task Consume(ConsumeContext<UrgentIRUnReadTaskRecurringEvent> context)
{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
var trialId = context.Message.TrialId;
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
var scenario = EmailBusinessScenario.ExpeditedReading;
var trialEmailConfig = _trialEmailNoticeConfigrepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
if (trialEmailConfig != null)
{
DictionaryRepository = _dictionaryRepository,
IsEn_US = isEn_US,
DictionaryList = new List<DictionaryDto>()
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
{
DictionaryRepository = _dictionaryRepository,
IsEn_US = isEn_US,
DictionaryList = new List<DictionaryDto>()
{
new DictionaryDto (){DictionaryCode= "YesOrNo",EnumValue="true" }
}
});
});
//找到该项目所有的IR 并且有加急 和Pd 未读的任务
//找到该项目所有的IR 并且有加急 和Pd 未读的任务
Expression<Func<VisitTask, bool>> comonTaskFilter = t => t.TrialId == trialId && t.TaskState == TaskState.Effect && t.ReadingTaskState != ReadingTaskState.HaveSigned && t.TaskAllocationState == TaskAllocationState.Allocated;
Expression<Func<VisitTask, bool>> comonTaskFilter = t => t.TrialId == trialId && t.TaskState == TaskState.Effect && t.ReadingTaskState != ReadingTaskState.HaveSigned && t.TaskAllocationState == TaskAllocationState.Allocated;
var trialUserList = _trialUserRepository.Where(t => t.TrialId == trialId).Select(t => new
{
t.UserId,
t.User.FullName,
t.User.EMail,
t.User.UserName,
t.Trial.TrialCode,
t.Trial.ResearchProgramNo
//TrialReadingCriterionList = t.Trial.TrialReadingCriterionList.Select(t => new { t.CriterionName, TrialReadingCriterionId = t.Id }).ToList()
});
foreach (var trialUser in trialUserList)
{
var userId = trialUser.UserId;
var doctorCriterionList = await _trialReadingCriterionRepository.Where(t => t.IsSigned && t.IsConfirm && t.TrialId == trialId && t.Trial.TrialUserList.Any(t => t.UserId == userId))
.Select(c => new
{
TrialReadingCriterionId = c.Id,
CriterionName = c.CriterionName,
UnReadList = c.VisitTaskList.Where(t => t.ExpetidEmailNoticeTime == null) //没有被通知
.Where(t => t.DoctorUserId == userId && t.ReadingTaskState != ReadingTaskState.HaveSigned && t.TaskState == TaskState.Effect)
// 前序 不存在 未一致性核查未通过的
.Where(t => !t.Subject.SubjectVisitList.Any(sv => sv.CheckState != CheckStateEnum.CVPassed && t.VisitTaskNum > sv.VisitNum))
//前序 不存在 未生成任务的访视
.Where(t => c.IsAutoCreate == false ? !t.Subject.SubjectCriteriaEvaluationVisitFilterList.Where(d => d.TrialReadingCriterionId == t.TrialReadingCriterionId).Any(f => f.IsGeneratedTask == false && t.VisitTaskNum > f.SubjectVisit.VisitNum) : true)
.Where(y => y.IsFrontTaskNeedSignButNotSign == false && (y.IsNeedClinicalDataSign == false || y.IsClinicalDataSign == true))
.Where(t => t.SourceSubjectVisit.PDState == PDStateEnum.PDProgress || t.SourceSubjectVisit.IsEnrollmentConfirm ||
t.ReadModule.SubjectVisit.PDState == PDStateEnum.PDProgress || t.ReadModule.SubjectVisit.IsEnrollmentConfirm)
.Select(c => new
{
SubejctCode = c.IsAnalysisCreate ? c.BlindSubjectCode : c.Subject.Code,
c.TaskBlindName,
c.TaskName,
VisitTaskId = c.Id
}).ToList()
}).ToListAsync();
var toTalUnreadCount = doctorCriterionList.SelectMany(t => t.UnReadList).Count();
if (toTalUnreadCount > 0)
var trialUserList = _trialUserRoleRepository.Where(t => t.TrialId == trialId && t.TrialUser.JoinTime != null).Select(t => new
{
var messageToSend = new MimeMessage();
t.UserId,
t.UserRole.FullName,
t.UserRole.IdentityUser.EMail,
t.UserRole.IdentityUser.UserName,
t.Trial.TrialCode,
t.Trial.ResearchProgramNo
//TrialReadingCriterionList = t.Trial.TrialReadingCriterionList.Select(t => new { t.CriterionName, TrialReadingCriterionId = t.Id }).ToList()
});
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(trialUser.FullName, trialUser.EMail));
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
foreach (var trialUser in trialUserList)
{
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
var userId = trialUser.UserId;
var doctorCriterionList = await _trialReadingCriterionRepository.Where(t => t.IsSigned && t.IsConfirm && t.TrialId == trialId && t.Trial.TrialUserRoleList.Any(t => t.UserId == userId))
.Select(c => new
{
TrialReadingCriterionId = c.Id,
CriterionName = c.CriterionName,
UnReadList = c.VisitTaskList.Where(t => t.ExpetidEmailNoticeTime == null) //没有被通知
.Where(t => t.DoctorUserId == userId && t.ReadingTaskState != ReadingTaskState.HaveSigned && t.TaskState == TaskState.Effect)
// 前序 不存在 未一致性核查未通过的
.Where(t => !t.Subject.SubjectVisitList.Any(sv => sv.CheckState != CheckStateEnum.CVPassed && t.VisitTaskNum > sv.VisitNum))
//前序 不存在 未生成任务的访视
.Where(t => c.IsAutoCreate == false ? !t.Subject.SubjectCriteriaEvaluationVisitFilterList.Where(d => d.TrialReadingCriterionId == t.TrialReadingCriterionId).Any(f => f.IsGeneratedTask == false && t.VisitTaskNum > f.SubjectVisit.VisitNum) : true)
.Where(y => y.IsFrontTaskNeedSignButNotSign == false && (y.IsNeedClinicalDataSign == false || y.IsClinicalDataSign == true))
.Where(t => t.SourceSubjectVisit.PDState == PDStateEnum.PDProgress || t.SourceSubjectVisit.IsEnrollmentConfirm ||
t.ReadModule.SubjectVisit.PDState == PDStateEnum.PDProgress || t.ReadModule.SubjectVisit.IsEnrollmentConfirm)
.Select(c => new
{
SubejctCode = c.IsAnalysisCreate ? c.BlindSubjectCode : c.Subject.Code,
c.TaskBlindName,
c.TaskName,
VisitTaskId = c.Id
}).ToList()
}).ToListAsync();
var toTalUnreadCount = doctorCriterionList.SelectMany(t => t.UnReadList).Count();
if (toTalUnreadCount > 0)
{
var topicStr = string.Format(input.topicStr, trialUser.ResearchProgramNo);
var messageToSend = new MimeMessage();
var template = input.htmlBodyStr;
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(trialUser.FullName, trialUser.EMail));
//正则提取循环的部分 {%for%}(.*?){%end for%}
string pattern = @"{%for%}(.*?){%end for%}";
var match = Regex.Match(template, pattern, RegexOptions.Singleline);
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
string criteriaTemplate = match.Groups[1].Value; // 提取循环模板
// 构建循环内容
string criteriaDetails = "";
foreach (var criteria in doctorCriterionList)
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
if (criteria.UnReadList.Count() > 0)
var topicStr = string.Format(input.topicStr, trialUser.ResearchProgramNo);
var template = input.htmlBodyStr;
//正则提取循环的部分 {%for%}(.*?){%end for%}
string pattern = @"{%for%}(.*?){%end for%}";
var match = Regex.Match(template, pattern, RegexOptions.Singleline);
string criteriaTemplate = match.Groups[1].Value; // 提取循环模板
// 构建循环内容
string criteriaDetails = "";
foreach (var criteria in doctorCriterionList)
{
criteriaDetails += string.Format(criteriaTemplate, criteria.CriterionName, criteria.UnReadList.Select(t => t.SubejctCode).Distinct().Count(), criteria.UnReadList.Count());
if (criteria.UnReadList.Count() > 0)
{
criteriaDetails += string.Format(criteriaTemplate, criteria.CriterionName, criteria.UnReadList.Select(t => t.SubejctCode).Distinct().Count(), criteria.UnReadList.Count());
}
}
}
// 用循环内容替换原始模板中的循环部分
string emailContent = template.Replace(criteriaTemplate, criteriaDetails).Replace("{%for%}", "").Replace("{%end for%}", "");
// 用循环内容替换原始模板中的循环部分
string emailContent = template.Replace(criteriaTemplate, criteriaDetails).Replace("{%for%}", "").Replace("{%end for%}", "");
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, emailContent),
trialUser.FullName,
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, emailContent),
trialUser.FullName,
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
toTalUnreadCount,
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
toTalUnreadCount,
trialUser.ResearchProgramNo,
dictionValue[0],
_systemEmailConfig.SiteUrl
);
trialUser.ResearchProgramNo,
dictionValue[0],
_systemEmailConfig.SiteUrl
);
return (topicStr, htmlBodyStr);
};
return (topicStr, htmlBodyStr);
};
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(_emailNoticeConfigrepository, EmailBusinessScenario.ExpeditedReading, messageToSend, emailConfigFunc);
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
//处理标记已通知的任务
//处理标记已通知的任务
var visitTaskIdList = doctorCriterionList.Where(t => t.UnReadList.Count() > 0).SelectMany(t => t.UnReadList.Select(u => u.VisitTaskId)).ToList();
await _visitTaskRepository.BatchUpdateNoTrackingAsync(t => visitTaskIdList.Contains(t.Id), u => new VisitTask() { ExpetidEmailNoticeTime = DateTime.Now });
}
var visitTaskIdList = doctorCriterionList.Where(t => t.UnReadList.Count() > 0).SelectMany(t => t.UnReadList.Select(u => u.VisitTaskId)).ToList();
await _visitTaskRepository.BatchUpdateNoTrackingAsync(t => visitTaskIdList.Contains(t.Id), u => new VisitTask() { ExpetidEmailNoticeTime = DateTime.Now });
}
}
}
}
}

View File

@ -22,18 +22,19 @@ public static class OldRecurringEmailHelper
public static async Task SendTrialEmailAsync(
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
IRepository<Trial> _trialRepository,
IRepository<TrialUser> _trialUserRepository,
IRepository<TrialUserRole> _trialUserRoleRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<TrialSiteUser> _trialSiteUserRepository,
IRepository<TrialSiteUserRole> _trialSiteUserRoleRepository,
Guid trialId, EmailBusinessScenario businessScenario,
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc,
Guid? trialSiteId = null, Guid? trialReadingCriterionId = null)
Guid? trialSiteId = null)
{
//找到配置
var trialEmailConfig = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId && t.TrialReadingCriterionId == trialReadingCriterionId && t.BusinessScenarioEnum == businessScenario, ignoreQueryFilters: true)
var trialEmailConfig = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == businessScenario, ignoreQueryFilters: true)
.Include(t => t.TrialEmailNoticeUserList).Include(t => t.TrialEmailBlackUserList).FirstOrDefaultAsync();
var trialInfo=await _trialRepository.Where(t=>t.Id== trialId).FirstOrDefaultAsync();
if (trialEmailConfig == null || trialEmailConfig.IsAutoSend == false || trialEmailConfig.IsEnable == false)
{
@ -59,7 +60,7 @@ public static class OldRecurringEmailHelper
var allUserTypeEnumList = toUserTypeEnumList.Union(copyUserTypeEnumList).Distinct().ToList();
var allUserList = await _trialUserRepository.Where(t => t.TrialId == trialId && allUserTypeEnumList.Contains(t.User.UserTypeEnum)).Select(t => new { t.UserId, t.User.EMail, t.User.FullName, t.User.UserTypeEnum }).ToListAsync();
var allUserList = await _trialUserRoleRepository.Where(t => t.TrialId == trialId && allUserTypeEnumList.Contains(t.UserRole.UserTypeEnum)).Select(t => new { t.UserId, t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum }).ToListAsync();
var toUserList = allUserList.Where(t => toUserTypeEnumList.Contains(t.UserTypeEnum))
@ -72,7 +73,7 @@ public static class OldRecurringEmailHelper
}
if (trialSiteId != null && toUserTypeEnumList.Any(t => t == UserTypeEnum.ClinicalResearchCoordinator || t == UserTypeEnum.CRA))
{
var curentSiteUserIdList = _trialSiteUserRepository.Where(t => t.TrialId == trialId && t.TrialSiteId == trialSiteId).Select(t => t.UserId).ToList();
var curentSiteUserIdList = _trialSiteUserRoleRepository.Where(t => t.TrialId == trialId && t.TrialSiteId == trialSiteId).Select(t => t.UserId).ToList();
toUserList = toUserList.Where(t => (t.UserTypeEnum != UserTypeEnum.CRA && t.UserTypeEnum != UserTypeEnum.ClinicalResearchCoordinator) || curentSiteUserIdList.Contains(t.UserId)).ToList();
}
@ -86,7 +87,7 @@ public static class OldRecurringEmailHelper
if (trialSiteId != null && copyUserTypeEnumList.Any(t => t == UserTypeEnum.ClinicalResearchCoordinator || t == UserTypeEnum.CRA))
{
var curentSiteUserIdList = _trialSiteUserRepository.Where(t => t.TrialId == trialId && t.TrialSiteId == trialSiteId).Select(t => t.UserId).ToList();
var curentSiteUserIdList = _trialSiteUserRoleRepository.Where(t => t.TrialId == trialId && t.TrialSiteId == trialSiteId).Select(t => t.UserId).ToList();
copyUserList = copyUserList.Where(t => (t.UserTypeEnum != UserTypeEnum.CRA && t.UserTypeEnum != UserTypeEnum.ClinicalResearchCoordinator) || curentSiteUserIdList.Contains(t.UserId)).ToList();
}
@ -162,7 +163,7 @@ public static class OldRecurringEmailHelper
if (sendEmailConfig != null)
{
await SendEmailHelper.SendEmailAsync(sendEmailConfig);
await SendEmailHelper.SendEmailAsync(sendEmailConfig, trialInfo);
}

View File

@ -14,7 +14,7 @@ using System.Threading.Tasks;
namespace IRaCIS.Core.Application.MassTransit.Consumer;
//项目手动选择 周期性邮件
/// <summary>
@ -23,11 +23,13 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer;
public class QCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRepository,
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
IRepository<TrialUser> _trialUserRepository,
IRepository<TrialUserRole> _trialUserRoleRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<TrialSiteUser> _trialSiteUserRepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig,
IRepository<TrialSiteUserRole> _trialSiteUserRoleRepository,
IOptionsMonitor<SystemEmailSendConfig> _SystemEmailSendConfig) : IConsumer<QCImageQuestionRecurringEvent>
{
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
public async Task Consume(ConsumeContext<QCImageQuestionRecurringEvent> context)
{
var trialId = context.Message.TrialId;
@ -37,7 +39,7 @@ public class QCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRepo
var trialInfo = await _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr }).FirstNotNullAsync();
//找到 该项目的CRC 用户Id
var userList = await _trialUserRepository.Where(t => t.TrialId == trialId).Where(t => t.User.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Select(t => new { t.UserId, t.User.FullName }).ToListAsync();
var userList = await _trialUserRoleRepository.Where(t => t.TrialId == trialId).Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Select(t => new { t.UserId, t.UserRole.FullName }).ToListAsync();
//判断是否任务可以领取 ,可以的话 发送邮件
@ -64,8 +66,9 @@ public class QCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRepo
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
user.FullName, DateTime.Now, sendStat.ToBeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
var htmlContent = isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN;
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, htmlContent),
user.FullName, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), sendStat.ToBeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
return (topicStr, htmlBodyStr, isEn_us, userId);
};
@ -73,9 +76,9 @@ public class QCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRepo
await OldRecurringEmailHelper.SendTrialEmailAsync(
_trialEmailNoticeConfigRepository,
_trialRepository,
_trialUserRepository,
_trialUserRoleRepository,
_visitTaskRepository,
_trialSiteUserRepository,
_trialSiteUserRoleRepository,
trialId, EmailBusinessScenario.QCToCRCImageQuestion, topicAndHtmlFunc);
}
}
@ -88,11 +91,13 @@ public class QCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRepo
/// </summary>
public class CRCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRepository,
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
IRepository<TrialUser> _trialUserRepository,
IRepository<TrialUserRole> _trialUserRoleRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<TrialSiteUser> _trialSiteUserRepository,
IRepository<TrialSiteUserRole> _trialSiteUserRoleRepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig,
IOptionsMonitor<SystemEmailSendConfig> _SystemEmailSendConfig) : IConsumer<CRCImageQuestionRecurringEvent>
{
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
public async Task Consume(ConsumeContext<CRCImageQuestionRecurringEvent> context)
{
var trialId = context.Message.TrialId;
@ -101,7 +106,7 @@ public class CRCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRep
var trialInfo = await _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr, t.DeclarationTypeEnumList }).FirstNotNullAsync();
//找到 该项目的IQC 用户Id
var userList = await _trialUserRepository.Where(t => t.TrialId == trialId).Where(t => t.User.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.User.FullName }).ToListAsync();
var userList = await _trialUserRoleRepository.Where(t => t.TrialId == trialId).Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.UserRole.FullName }).ToListAsync();
//判断是否任务可以领取 ,可以的话 发送邮件
@ -131,9 +136,10 @@ public class CRCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRep
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
var htmlContent = isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN;
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, htmlContent),
user.FullName, DateTime.Now, sendStat.ToBeDealedCount - sendStat.ReUploadTobeDealedCount, sendStat.ReUploadTobeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
user.FullName, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), sendStat.ToBeDealedCount - sendStat.ReUploadTobeDealedCount, sendStat.ReUploadTobeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
return (topicStr, htmlBodyStr, false, userId);
@ -141,9 +147,9 @@ public class CRCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRep
await OldRecurringEmailHelper.SendTrialEmailAsync(_trialEmailNoticeConfigRepository,
_trialRepository,
_trialUserRepository,
_trialUserRoleRepository,
_visitTaskRepository,
_trialSiteUserRepository,
_trialSiteUserRoleRepository,
trialId, EmailBusinessScenario.CRCToQCQuestion, topicAndHtmlFunc);
}
}
@ -155,11 +161,14 @@ public class CRCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRep
/// </summary>
public class ImageQCRecurringEventConsumer(IRepository<Trial> _trialRepository,
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
IRepository<TrialUser> _trialUserRepository,
IRepository<TrialUserRole> _trialUserRoleRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<TrialSiteUser> _trialSiteUserRepository,
IRepository<TrialSiteUserRole> _trialSiteUserRoleRepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig,
IOptionsMonitor<SystemEmailSendConfig> _SystemEmailSendConfig) : IConsumer<ImageQCRecurringEvent>
{
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
public async Task Consume(ConsumeContext<ImageQCRecurringEvent> context)
{
var trialId=context.Message.TrialId;
@ -169,7 +178,7 @@ public class ImageQCRecurringEventConsumer(IRepository<Trial> _trialRepository,
var trialInfo = await _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr }).FirstNotNullAsync();
//找到 该项目的IQC 用户Id
var userList = await _trialUserRepository.Where(t => t.TrialId == trialId).Where(t => t.User.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.User.FullName }).ToListAsync();
var userList = await _trialUserRoleRepository.Where(t => t.TrialId == trialId).Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.UserRole.FullName }).ToListAsync();
//判断是否任务可以领取 ,可以的话 发送邮件
var userIdList = userList.Select(t => t.UserId).ToList();
@ -199,9 +208,12 @@ public class ImageQCRecurringEventConsumer(IRepository<Trial> _trialRepository,
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
user.FullName, DateTime.Now, sendStat.ToBeClaimedCount, sendStat.ToBeReviewedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
var htmlContent = isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN;
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, htmlContent),
user.FullName, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), sendStat.ToBeClaimedCount, sendStat.ToBeReviewedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
return (topicStr, htmlBodyStr, false, userId);
};
@ -209,9 +221,9 @@ public class ImageQCRecurringEventConsumer(IRepository<Trial> _trialRepository,
await OldRecurringEmailHelper.SendTrialEmailAsync(
_trialEmailNoticeConfigRepository,
_trialRepository,
_trialUserRepository,
_trialUserRoleRepository,
_visitTaskRepository,
_trialSiteUserRepository,
_trialSiteUserRoleRepository,
trialId, EmailBusinessScenario.QCTask, topicAndHtmlFunc);
}
}

View File

@ -37,4 +37,45 @@ public class UrgentIRUnReadTaskRecurringEvent : DomainEvent
public Guid TrialId { get; set; }
}
/// <summary>
/// 定时提醒
/// </summary>
public class SystemDocumentErverDayEvent : DomainEvent
{
}
public class SystemDocumentPublishEvent : DomainEvent
{
public List<Guid> Ids { get; set; }
/// <summary>
/// 新增的需要发送邮件的用户角色ID列表
/// 如果为null或空则发送给所有相关角色
/// </summary>
public List<Guid> NewUserTypeIds { get; set; }
}
/// <summary>
/// 定时提醒
/// </summary>
public class TrialDocumentErverDayEvent : DomainEvent
{
}
public class TrialDocumentPublishEvent : DomainEvent
{
public List<Guid> Ids { get; set; }
/// <summary>
/// 新增的需要发送邮件的用户角色ID列表
/// 如果为null或空则发送给所有相关角色
/// </summary>
public List<Guid> NewUserTypeIds { get; set; }
}

View File

@ -0,0 +1,277 @@
using DocumentFormat.OpenXml;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.MassTransit.Consumer;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Domain.Models;
using MassTransit;
using Microsoft.Extensions.Options;
using MimeKit;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reactive.Joins;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.MassTransit.Recurring
{
/// <summary>
/// 定时过期提醒
/// </summary>
public class SystemDocumentErverDayEventConsumer(
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<SystemDocument> _systemDocumentRepository,
IRepository<IdentityUser> _identityUserRepository,
IRepository<SystemDocConfirmedIdentityUser> _systemDocConfirmedUserRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<TrialUserRole> _trialUserRoleRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) : IConsumer<SystemDocumentErverDayEvent>
{
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
public async Task Consume(ConsumeContext<SystemDocumentErverDayEvent> context)
{
DateTime now = DateTime.Now;
Console.WriteLine("发送定时过期提醒");
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
var systemDocQuery =
from sysDoc in _systemDocumentRepository.AsQueryable(false)
from identityUser in _identityUserRepository.AsQueryable(false).Where(t => t.UserRoleList.Where(t => t.IsUserRoleDisabled == false).Any(t => sysDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
join confirmc in _systemDocConfirmedUserRepository.Where() on new { ConfirmUserId = identityUser.Id, SystemDocumentId = sysDoc.Id } equals new { confirmc.ConfirmUserId, confirmc.SystemDocumentId } into cc
from confirm in cc.DefaultIfEmpty()
select new UnionDocumentWithConfirmInfoView()
{
IsSystemDoc = true,
Id = sysDoc.Id,
CreateTime = sysDoc.CreateTime,
IsDeleted = sysDoc.IsDeleted,
SignViewMinimumMinutes = sysDoc.SignViewMinimumMinutes,
Name = sysDoc.Name,
Path = sysDoc.Path,
FileTypeId = sysDoc.FileTypeId,
UpdateTime = sysDoc.UpdateTime,
ConfirmUserId = identityUser.Id,
ConfirmTime = confirm.ConfirmTime,
UserCreateTime = identityUser.CreateTime,
CurrentStaffTrainDays = sysDoc.CurrentStaffTrainDays,
NewStaffTrainDays = sysDoc.NewStaffTrainDays,
RealName = identityUser.FullName,
UserName = identityUser.UserName,
IsNeedSendEmial = identityUser.IsZhiZhun || (!identityUser.IsZhiZhun && sysDoc.DocUserSignType == DocUserSignType.InnerAndOuter),
FullFilePath = sysDoc.Path
};
var datalist = await systemDocQuery.IgnoreQueryFilters().Where(t => t.IsDeleted == false && t.ConfirmTime == null)
.ToListAsync();
datalist = datalist.Where(x => x.SuggestFinishTime != null && x.SuggestFinishTime.Value.Date == DateTime.Now.Date)
.Where(x => x.IsNeedSendEmial).ToList();
var confirmUserIdList = datalist.Select(t => t.ConfirmUserId).Distinct().ToList();
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
Console.WriteLine("发送定时过期提醒:人员数量" + userinfoList.Count);
int index = 1;
foreach (var userinfo in userinfoList)
{
try
{
Console.WriteLine($"{index}发送定时过期提醒,邮箱:{userinfo.EMail},姓名{userinfo.UserName}");
index++;
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName);
var htmlBodyStr = string.Format(
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
userinfo.UserName, // 用户名 {0}
_systemEmailConfig.SiteUrl
);
return (topicStr, htmlBodyStr);
};
var scenario = EmailBusinessScenario.GeneralTraining_ExpirationNotification;
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
if (emailConfig != null)
{
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
}
}
catch (Exception)
{
}
}
}
}
/// <summary>
/// 生效通知
/// </summary>
public class SystemDocumentPublishEventConsumer(
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<SystemDocument> _systemDocumentRepository,
IRepository<IdentityUser> _identityUserRepository,
IRepository<SystemDocConfirmedIdentityUser> _systemDocConfirmedUserRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<TrialUserRole> _trialUserRoleRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) : IConsumer<SystemDocumentPublishEvent>
{
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
public async Task Consume(ConsumeContext<SystemDocumentPublishEvent> context)
{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
// 记录是否只发送给新增角色的日志
if (context.Message.NewUserTypeIds != null && context.Message.NewUserTypeIds.Any())
{
Console.WriteLine($"只发送给新增的角色,角色数量: {context.Message.NewUserTypeIds.Count}");
}
// 构建查询
IQueryable<UnionDocumentWithConfirmInfoView> systemDocQuery;
if (context.Message.NewUserTypeIds != null && context.Message.NewUserTypeIds.Any())
{
// 只查询新增角色的用户
systemDocQuery =
from sysDoc in _systemDocumentRepository.AsQueryable(false).Where(x => context.Message.Ids.Contains(x.Id))
from identityUser in _identityUserRepository.AsQueryable(false)
.Where(t => t.Status == UserStateEnum.Enable &&
t.UserRoleList.Where(t => t.IsUserRoleDisabled == false)
.Any(t => context.Message.NewUserTypeIds.Contains(t.UserTypeId) &&
sysDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
select new UnionDocumentWithConfirmInfoView()
{
IsSystemDoc = true,
Id = sysDoc.Id,
CreateTime = sysDoc.CreateTime,
IsDeleted = sysDoc.IsDeleted,
SignViewMinimumMinutes = sysDoc.SignViewMinimumMinutes,
Name = sysDoc.Name,
Path = sysDoc.Path,
FileTypeId = sysDoc.FileTypeId,
UpdateTime = sysDoc.UpdateTime,
ConfirmUserId = identityUser.Id,
RealName = identityUser.FullName,
UserName = identityUser.UserName,
IsNeedSendEmial = identityUser.IsZhiZhun || (!identityUser.IsZhiZhun && sysDoc.DocUserSignType == DocUserSignType.InnerAndOuter),
FullFilePath = sysDoc.Path
};
}
else
{
// 查询所有相关角色的用户
systemDocQuery =
from sysDoc in _systemDocumentRepository.AsQueryable(false).Where(x => context.Message.Ids.Contains(x.Id))
from identityUser in _identityUserRepository.AsQueryable(false)
.Where(t => t.Status == UserStateEnum.Enable &&
t.UserRoleList.Where(t => t.IsUserRoleDisabled == false)
.Any(t => sysDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
select new UnionDocumentWithConfirmInfoView()
{
IsSystemDoc = true,
Id = sysDoc.Id,
CreateTime = sysDoc.CreateTime,
IsDeleted = sysDoc.IsDeleted,
SignViewMinimumMinutes = sysDoc.SignViewMinimumMinutes,
Name = sysDoc.Name,
Path = sysDoc.Path,
FileTypeId = sysDoc.FileTypeId,
UpdateTime = sysDoc.UpdateTime,
ConfirmUserId = identityUser.Id,
RealName = identityUser.FullName,
UserName = identityUser.UserName,
IsNeedSendEmial = identityUser.IsZhiZhun || (!identityUser.IsZhiZhun && sysDoc.DocUserSignType == DocUserSignType.InnerAndOuter),
FullFilePath = sysDoc.Path
};
}
var datalist = await systemDocQuery.IgnoreQueryFilters().Where(x => x.IsNeedSendEmial).ToListAsync();
var confirmUserIdList = datalist.Select(t => t.ConfirmUserId).Distinct().ToList();
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
int index = 1;
foreach (var userinfo in userinfoList)
{
string msg = $"{index}生效通知,邮箱:{userinfo.EMail},姓名{userinfo.UserName},";
index++;
try
{
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName);
var htmlBodyStr = string.Format(
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
userinfo.UserName, // 用户名 {0}
_systemEmailConfig.SiteUrl
);
return (topicStr, htmlBodyStr);
};
var scenario = EmailBusinessScenario.GeneralTraining_EffectiveNotification;
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
if (emailConfig != null)
{
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
msg += "发送成功";
}
}
catch (Exception)
{
msg += "发送失败";
}
Console.WriteLine(msg);
}
}
}
}

View File

@ -0,0 +1,317 @@
using DocumentFormat.OpenXml;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.MassTransit.Consumer;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Domain.Models;
using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using MimeKit;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Reactive.Joins;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.MassTransit.Recurring
{
/// <summary>
/// 定时过期提醒
/// </summary>
public class TrialDocumentErverDayEventConsumer(
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<SystemDocument> _systemDocumentRepository,
IRepository<IdentityUser> _identityUserRepository,
IRepository<SystemDocConfirmedIdentityUser> _systemDocConfirmedUserRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<TrialUserRole> _trialUserRoleRepository, IRepository<TrialDocument> _trialDocumentRepository,
IRepository<Trial> _trialRepository,
ISystemDocumentService _systemDocumentService,
IRepository<SystemDocNeedConfirmedUserType> _systemDocNeedConfirmedUserTypeRepository,
IRepository<TrialDocNeedConfirmedUserType> _trialDocNeedConfirmedUserTypeRepository,
IServiceScopeFactory serviceScopeFactory,
IRepository<TrialIdentityUser> _trialIdentityUserRepository,
IRepository<TrialDocConfirmedIdentityUser> _trialDocConfirmedUserRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) : IConsumer<TrialDocumentErverDayEvent>
{
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
public async Task Consume(ConsumeContext<TrialDocumentErverDayEvent> context)
{
DateTime now = DateTime.Now;
Console.WriteLine("发送定时项目过期提醒");
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
var trialDocQuery =
from trialDoc in _trialDocumentRepository.AsQueryable(true)
join trialIdentityUser in _trialIdentityUserRepository.Where(x => x.IsDeleted == false) on trialDoc.TrialId equals trialIdentityUser.TrialId
join trialUserRole in _trialUserRoleRepository.Where(x => x.IsDeleted == false) on trialIdentityUser.Id equals trialUserRole.TrialUserId
join identityUser in _identityUserRepository.AsQueryable(false).Where(u => u.Status == UserStateEnum.Enable)
on trialIdentityUser.IdentityUserId equals identityUser.Id
join confirm in _trialDocConfirmedUserRepository.Where() on
new { trialIdentityUser.IdentityUserId, TrialDocumentId = trialDoc.Id } equals new { IdentityUserId = confirm.ConfirmUserId, confirm.TrialDocumentId } into cc
from confirm in cc.DefaultIfEmpty()
where trialIdentityUser.TrialUserRoleList.Any(ur => !ur.IsDeleted && trialDoc.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == ur.UserRole.UserTypeId))
select new TrialSignDocView()
{
TrialCode = trialDoc.Trial.TrialCode,
ResearchProgramNo = trialDoc.Trial.ResearchProgramNo,
ExperimentName = trialDoc.Trial.ExperimentName,
CurrentStaffTrainDays = trialDoc.CurrentStaffTrainDays,
NewStaffTrainDays = trialDoc.NewStaffTrainDays,
Id = trialDoc.Id,
IsSystemDoc = false,
CreateTime = trialDoc.CreateTime,
FullFilePath = trialDoc.Path,
IsDeleted = trialDoc.IsDeleted,
Name = trialDoc.Name,
Path = trialDoc.Path,
FileTypeId = trialDoc.FileTypeId,
UpdateTime = trialDoc.UpdateTime,
SignViewMinimumMinutes = trialDoc.SignViewMinimumMinutes,
//IsConfirmed = confirm.ConfirmTime != null,
ConfirmUserId = identityUser.Id,
ConfirmTime = confirm.ConfirmTime,
RealName = trialIdentityUser.IdentityUser.FullName,
UserName = trialIdentityUser.IdentityUser.UserName,
UserCreateTime= trialIdentityUser.CreateTime,
IdentityUserTypeList = trialIdentityUser.TrialUserRoleList.Select(t => t.UserRole.UserTypeRole.UserTypeShortName).ToList(),
DocNeedSignUserTypeList = trialDoc.NeedConfirmedUserTypeList.Select(t => t.UserTypeRole.UserTypeShortName).ToList(),
};
var datalist = await trialDocQuery.IgnoreQueryFilters().Where(t => t.IsDeleted == false && t.ConfirmTime == null&&t.ConfirmTime==null)
.ToListAsync();
datalist = datalist.Where(x => x.SuggestFinishTime != null && x.SuggestFinishTime.Value.Date == DateTime.Now.Date)
.ToList();
var confirmUserIdList = datalist.Select(t => t.ConfirmUserId).Distinct().ToList();
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
Console.WriteLine("发送定时项目过期提醒:人员数量" + userinfoList.Count);
int index = 1;
foreach (var userinfo in userinfoList)
{
try
{
Console.WriteLine($"{index}发送定时过期提醒,邮箱:{userinfo.EMail},姓名{userinfo.UserName}");
index++;
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName);
var htmlBodyStr = string.Format(
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
userinfo.UserName, // 用户名 {0}
_systemEmailConfig.SiteUrl
);
return (topicStr, htmlBodyStr);
};
var scenario = EmailBusinessScenario.TrialTraining_ExpirationNotification;
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
if (emailConfig != null)
{
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
}
}
catch (Exception)
{
}
}
}
}
/// <summary>
/// 生效通知
/// </summary>
public class TrialDocumentPublishEventConsumer(
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<TrialDocument> _trialDocumentRepository,
IRepository<IdentityUser> _identityUserRepository,
IRepository<Trial> _trialRepository,
IRepository<TrialIdentityUser> _trialIdentityUserRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<TrialUserRole> _trialUserRoleRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) : IConsumer<TrialDocumentPublishEvent>
{
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
public async Task Consume(ConsumeContext<TrialDocumentPublishEvent> context)
{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
// 记录是否只发送给新增角色的日志
if (context.Message.NewUserTypeIds != null && context.Message.NewUserTypeIds.Any())
{
Console.WriteLine($"只发送给新增项目的角色,角色数量: {context.Message.NewUserTypeIds.Count}");
}
// 构建查询
IQueryable<UnionDocumentWithConfirmInfoView> systemDocQuery;
if (context.Message.NewUserTypeIds != null && context.Message.NewUserTypeIds.Any())
{
// 只查询新增角色的用户
systemDocQuery =
from trialDoc in _trialDocumentRepository.AsQueryable(false).Where(x => context.Message.Ids.Contains(x.Id))
join trialIdentityUser in _trialIdentityUserRepository.Where(x=>x.IsDeleted==false) on trialDoc.TrialId equals trialIdentityUser.TrialId
join trialUserRole in _trialUserRoleRepository.Where(x => x.IsDeleted == false) on trialIdentityUser.Id equals trialUserRole.TrialUserId
join identityUser in _identityUserRepository.AsQueryable(false).Where(u => u.Status == UserStateEnum.Enable)
on trialIdentityUser.IdentityUserId equals identityUser.Id
where trialIdentityUser.TrialUserRoleList.Any(ur => !ur.IsDeleted && context.Message.NewUserTypeIds.Contains(ur.UserRole.UserTypeId) && trialDoc.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == ur.UserRole.UserTypeId))
select new UnionDocumentWithConfirmInfoView()
{
IsSystemDoc = true,
Id = trialDoc.Id,
TrialId= trialDoc.TrialId,
CreateTime = trialDoc.CreateTime,
IsDeleted = trialDoc.IsDeleted,
SignViewMinimumMinutes = trialDoc.SignViewMinimumMinutes,
Name = trialDoc.Name,
Path = trialDoc.Path,
FileTypeId = trialDoc.FileTypeId,
UpdateTime = trialDoc.UpdateTime,
ConfirmUserId = identityUser.Id,
RealName = identityUser.FullName,
UserName = identityUser.UserName,
IsNeedSendEmial = identityUser.IsZhiZhun,
FullFilePath = trialDoc.Path
};
}
else
{
// 查询所有相关角色的用户
systemDocQuery =
from trialDoc in _trialDocumentRepository.AsQueryable(false).Where(x => context.Message.Ids.Contains(x.Id))
join trialIdentityUser in _trialIdentityUserRepository.Where(x => x.IsDeleted == false) on trialDoc.TrialId equals trialIdentityUser.TrialId
join trialUserRole in _trialUserRoleRepository.Where(x=>x.IsDeleted==false) on trialIdentityUser.Id equals trialUserRole.TrialUserId
join trial in _trialRepository.AsQueryable(false) on trialDoc.TrialId equals trial.Id
join identityUser in _identityUserRepository.AsQueryable(false).Where(u => u.Status == UserStateEnum.Enable)
on trialIdentityUser.IdentityUserId equals identityUser.Id
where trialIdentityUser.TrialUserRoleList.Any(ur => !ur.IsDeleted &&trialDoc.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == ur.UserRole.UserTypeId))
select new UnionDocumentWithConfirmInfoView()
{
IsSystemDoc = false,
Id = trialDoc.Id,
TrialId = trialDoc.TrialId,
EmailFromName =trial.EmailFromName,
CreateTime = trialDoc.CreateTime,
IsDeleted = trialDoc.IsDeleted,
SignViewMinimumMinutes = trialDoc.SignViewMinimumMinutes,
Name = trialDoc.Name,
Path = trialDoc.Path,
FileTypeId = trialDoc.FileTypeId,
UpdateTime = trialDoc.UpdateTime,
ConfirmUserId = identityUser.Id,
RealName = identityUser.FullName,
UserName = identityUser.UserName,
IsNeedSendEmial = identityUser.IsZhiZhun ,
FullFilePath = trialDoc.Path
};
}
var datalist = await systemDocQuery.IgnoreQueryFilters().ToListAsync();
var confirmUserIdList = datalist.Select(t => t.ConfirmUserId).Distinct().ToList();
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
int index = 1;
foreach (var userinfo in userinfoList)
{
string msg = $"{index}项目生效通知,邮箱:{userinfo.EMail},姓名{userinfo.UserName},";
index++;
try
{
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName);
var htmlBodyStr = string.Format(
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
userinfo.UserName, // 用户名 {0}
_systemEmailConfig.SiteUrl
);
return (topicStr, htmlBodyStr);
};
var scenario = EmailBusinessScenario.TrialTraining_EffectiveNotification;
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsEnable).FirstOrDefault();
if (emailConfig != null)
{
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
var trial = datalist.Where(x => x.ConfirmUserId == userinfo.Id).FirstOrDefault();
var trialInfo = await _trialRepository.Where(x=>x.Id==trial.TrialId).FirstNotNullAsync();
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
msg += "发送成功";
}
}
catch (Exception)
{
msg += "发送失败";
}
Console.WriteLine(msg);
}
}
}
}

View File

@ -71,6 +71,8 @@ namespace IRaCIS.Core.Application.ViewModel
public bool IsPMSetBack { get; set; }
public bool IsSubjectQuit { get; set; }
#region 标准配置
public Guid TrialReadingCriterionId { get; set; }
@ -214,6 +216,10 @@ namespace IRaCIS.Core.Application.ViewModel
/// </summary>
public bool IsManualGeneration { get; set; }
//public bool IsAfterConvertedTask { get; set; }
public string PMBackReason { get; set; }
public int? RandomOrder { get; set; }
}
@ -234,6 +240,7 @@ namespace IRaCIS.Core.Application.ViewModel
//public string ReReadingOriginalTaskCode { get; set; }
public string ApplicantName { get; set; }
public Guid Id { get; set; }
@ -339,6 +346,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 +372,11 @@ namespace IRaCIS.Core.Application.ViewModel
/// 是否是一致性分析产生
/// </summary>
public bool IsAnalysisCreate { get; set; }
/// <summary>
/// 是否存在未处理的反馈
/// </summary>
public bool IsExistUnprocessedFeedback { get; set; }
public bool IsUrgent { get; set; }
@ -465,6 +487,11 @@ namespace IRaCIS.Core.Application.ViewModel
public string? RequestReReadingReason { get; set; }
public ExportResult? ReadingExportType { get; set; }
public int? RandomOrder { get; set; }
public bool? IsRandomOrderList { get; set; }
public CriterionType? CriterionType { get; set; }
}
@ -891,6 +918,30 @@ namespace IRaCIS.Core.Application.ViewModel
CancelAssign = 4,
}
public class SetRandomTaskOrderCommand
{
[NotDefault]
public Guid TrialId { get; set; }
[NotDefault]
public Guid TrialReadingCriterionId { get; set; }
[NotDefault]
public Guid DoctorUserId { get; set; }
public bool IsAutoSet { get; set; }
public List<VisitTaskOrderCommand> SetList { get; set; }
}
public class VisitTaskOrderCommand
{
public Guid Id { get; set; }
public int? RandomOrder { get; set; }
}
}

View File

@ -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;
@ -18,7 +20,7 @@ namespace IRaCIS.Core.Application.Service
/// </summary>
[ApiExplorerSettings(GroupName = "Trial")]
public class TaskAllocationRuleService(IRepository<TaskAllocationRule> _taskAllocationRuleRepository,
IRepository<User> _userRepository,
IRepository<UserRole> _userRoleRepository,
IRepository<Enroll> _enrollRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IRepository<SubjectCanceDoctor> _subjectCanceDoctorRepository,
@ -46,7 +48,7 @@ namespace IRaCIS.Core.Application.Service
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> AddOrUpdateTaskAllocationRule(TaskAllocationRuleAddOrEdit addOrEditTaskAllocationRule)
{
@ -77,7 +79,7 @@ namespace IRaCIS.Core.Application.Service
}
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[HttpDelete("{taskAllocationRuleId:guid}")]
public async Task<IResponseOutput> DeleteTaskAllocationRule(Guid taskAllocationRuleId)
@ -123,16 +125,16 @@ namespace IRaCIS.Core.Application.Service
[HttpGet("{trialId:guid}")]
public async Task<List<TrialDoctorUserSelectView>> GetDoctorUserSelectList(Guid trialId, [FromServices] IRepository<Enroll> _enrollRepository)
{
var query = from enroll in _enrollRepository.Where(t => t.TrialId == trialId && t.EnrollStatus >= EnrollStatus.ConfirmIntoGroup)
join user in _userRepository.AsQueryable() on enroll.DoctorId equals user.DoctorId
var query = from enroll in _enrollRepository.Where(t => t.TrialId == trialId /*&& t.TaskAllocationRule.IsEnable*/ && /*(t.EnrollStatus >= EnrollStatus.ConfirmIntoGroup ||*/ t.Trial.SubjectDoctorUserList.Any(v => v.DoctorUserId == t.DoctorUser.Id))
join user in _userRoleRepository.AsQueryable() on enroll.DoctorId equals user.DoctorId
select new TrialDoctorUserSelectView()
{
TrialId = enroll.TrialId,
//ReadingType = enroll.Trial.ReadingType,
DoctorUserId = user.Id,
FullName = user.FullName,
UserCode = user.UserCode,
UserName = user.UserName,
FullName = user.IdentityUser.FullName,
UserCode = user.IdentityUser.UserCode,
UserName = user.IdentityUser.UserName,
UserTypeEnum = user.UserTypeRole.UserTypeEnum,
ReadingCategoryList = enroll.EnrollReadingCategoryList.Select(t => t.ReadingCategory).ToList()
@ -151,14 +153,14 @@ namespace IRaCIS.Core.Application.Service
.WhereIf(selectQuery.TrialReadingCriterionId != null && selectQuery.ReadingCategory == null, t => t.Enroll.EnrollReadingCategoryList.Any(t => t.TrialReadingCriterionId == selectQuery.TrialReadingCriterionId))
.WhereIf(selectQuery.TrialReadingCriterionId != null && selectQuery.ReadingCategory != null,
t => t.Enroll.EnrollReadingCategoryList.Any(t => t.TrialReadingCriterionId == selectQuery.TrialReadingCriterionId && t.ReadingCategory == selectQuery.ReadingCategory))
join user in _userRepository.AsQueryable() on allocationRule.DoctorUserId equals user.Id
join user in _userRoleRepository.AsQueryable() on allocationRule.DoctorUserId equals user.Id
select new TrialDoctorUserSelectView()
{
TrialId = allocationRule.TrialId,
DoctorUserId = user.Id,
FullName = user.FullName,
UserCode = user.UserCode,
UserName = user.UserName,
FullName = user.IdentityUser.FullName,
UserCode = user.IdentityUser.UserCode,
UserName = user.IdentityUser.UserName,
UserTypeEnum = user.UserTypeRole.UserTypeEnum,
ReadingCategoryList = selectQuery.TrialReadingCriterionId == null ?

View File

@ -30,7 +30,7 @@ namespace IRaCIS.Core.Application.Service
IRepository<Trial> _trialRepository,
IRepository<TrialSite> _trialSiteRepository,
IRepository<Enroll> _enrollRepository,
IRepository<User> _userRepository,
IRepository<UserRole> _userRoleRepository,
IRepository<TrialVirtualSiteCodeUpdate> _trialVirtualSiteCodeUpdateRepository,
IVisitTaskHelpeService _visitTaskCommonService, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ITaskConsistentRuleService
{
@ -369,7 +369,7 @@ namespace IRaCIS.Core.Application.Service
var doctorUserIdQuery = from enroll in _enrollRepository.Where(t => t.TrialId == trialId).Where(t => t.EnrollReadingCategoryList.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId).Any(c => c.ReadingCategory == ReadingCategory.Global || c.ReadingCategory == ReadingCategory.Visit))
.Where(t => t.EnrollReadingCriteriaList.Any(t => t.TrialReadingCriterionId == trialReadingCriterionId && t.IsJoinAnalysis == true))
join user in _userRepository.Where() on enroll.DoctorId equals user.DoctorId
join user in _userRoleRepository.Where() on enroll.DoctorId equals user.DoctorId
select user.Id;
var configDoctorUserIdList = await doctorUserIdQuery.ToListAsync();
@ -707,9 +707,9 @@ namespace IRaCIS.Core.Application.Service
DoctorUserList = t.SubjectDoctorList.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId && t.IsConfirmed && t.ArmEnum <= Arm.DoubleReadingArm2).Select(t => new UserSimpleInfo()
{
UserId = t.Id,
FullName = t.DoctorUser.FullName,
UserCode = t.DoctorUser.UserCode,
UserName = t.DoctorUser.UserName
FullName = t.DoctorUser.IdentityUser.FullName,
UserCode = t.DoctorUser.IdentityUser.UserCode,
UserName = t.DoctorUser.IdentityUser.UserName
}).ToList(),
ValidVisitCount = t.SubjectVisitTaskList.AsQueryable().Where(visitTaskFilter).GroupBy(t => new { t.SubjectId, t.VisitTaskNum }).Where(g => g.Count() == 2).Count(),
@ -784,7 +784,7 @@ namespace IRaCIS.Core.Application.Service
var taskConsistentRuleQueryable = from enroll in _enrollRepository.Where(t => t.TrialId == trialId && t.EnrollStatus == EnrollStatus.ConfirmIntoGroup
&& t.EnrollReadingCriteriaList.Any(c => c.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && c.IsJoinAnalysis))
join user in _userRepository.Where() on enroll.DoctorUserId equals user.Id
join user in _userRoleRepository.Where() on enroll.DoctorUserId equals user.Id
join taskConsistentRule in _taskConsistentRuleRepository.Where(t => t.TrialId == trialId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.IsSelfAnalysis) on enroll.TrialId equals taskConsistentRule.TrialId
select new TaskConsistentRuleView()
{
@ -830,9 +830,9 @@ namespace IRaCIS.Core.Application.Service
AnalysisDoctorUser = new UserSimpleInfo()
{
UserId = user.Id,
UserCode = user.UserCode,
FullName = user.FullName,
UserName = user.UserName
UserCode = user.IdentityUser.UserCode,
FullName = user.IdentityUser.FullName,
UserName = user.IdentityUser.UserName
}
};

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