Compare commits

...

181 Commits

Author SHA1 Message Date
hang 7c7ce6632a 获取授权码接口调整
continuous-integration/drone/push Build is passing Details
2025-05-29 14:48:57 +08:00
hang 787bc250c1 X
continuous-integration/drone/push Build is passing Details
2025-05-27 17:07:26 +08:00
hang 3b5ac96a98 导出bug
continuous-integration/drone/push Build is passing Details
2025-05-14 15:59:04 +08:00
hang 3d4dc0c1f4 HIR 导出bug
continuous-integration/drone/push Build is passing Details
2025-05-14 15:50:42 +08:00
hang 2990420361 修改缓存bug
continuous-integration/drone/push Build is passing Details
2025-05-13 14:28:27 +08:00
hang 2521147579 增加医院通用配置
continuous-integration/drone/push Build is passing Details
2025-05-13 10:19:17 +08:00
hang 4f860cca07 恢复老接口
continuous-integration/drone/push Build is passing Details
2025-05-09 09:49:17 +08:00
hang bea324aa56 增加访视名称查询
continuous-integration/drone/push Build is passing Details
2025-04-30 14:01:08 +08:00
hang c78cbbb737 重阅修改测量数据
continuous-integration/drone/push Build is passing Details
2025-04-28 18:00:33 +08:00
he e197f6c2bb 修改
continuous-integration/drone/push Build is passing Details
2025-04-27 17:51:36 +08:00
he c7d8e38cd3 模板修改
continuous-integration/drone/push Build is passing Details
2025-04-27 15:36:30 +08:00
he 8a241754ca Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-04-25 14:47:49 +08:00
he b3e77ec422 模板修改 2025-04-25 14:47:48 +08:00
hang daf593f76a 邮箱修改
continuous-integration/drone/push Build is passing Details
2025-04-24 11:05:21 +08:00
hang 5c4388a2e7 修改初始化逻辑
continuous-integration/drone/push Build is passing Details
2025-04-24 10:40:58 +08:00
hang 0da73ce1db 单独修改单位
continuous-integration/drone/push Build is passing Details
2025-04-24 09:58:53 +08:00
hang 1d2ef4561f 修改账号信息
continuous-integration/drone/push Build is passing Details
2025-04-24 09:42:44 +08:00
hang dbf75535c5 统一修改用户信息
continuous-integration/drone/push Build is passing Details
2025-04-24 09:35:32 +08:00
he aa34c96a39 模板修改
continuous-integration/drone/push Build is passing Details
2025-04-23 11:29:28 +08:00
he e6b6a24b3b 添加英文模板
continuous-integration/drone/push Build is passing Details
2025-04-22 17:49:09 +08:00
hang 0b958f21a5 修改切换角色 统一密码,checkCode 首次登录标志
continuous-integration/drone/push Build is passing Details
2025-04-21 13:37:56 +08:00
hang e6310a4533 过滤OA
continuous-integration/drone/push Build is passing Details
2025-04-18 17:46:51 +08:00
hang 49c3a0d494 修改国际化
continuous-integration/drone/push Build is passing Details
2025-04-18 13:06:59 +08:00
hang 213cb69332 修改切换医院bug
continuous-integration/drone/push Build is passing Details
2025-04-18 10:03:35 +08:00
hang e43dce220c 修改激活逻辑
continuous-integration/drone/push Build is passing Details
2025-04-18 09:54:44 +08:00
hang 52dc6e05d4 修改名字
continuous-integration/drone/push Build is passing Details
2025-04-17 10:10:39 +08:00
hang 31e76a2e97 HIR 修改配置文件
continuous-integration/drone/push Build is running Details
2025-04-17 10:08:01 +08:00
hang 19d9ca44fb 修改映射配置,字段
continuous-integration/drone/push Build is passing Details
2025-04-14 15:33:55 +08:00
hang c8b0681dfa Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-04-03 16:21:01 +08:00
hang eed17feae0 上传自签署https minio 2025-04-03 16:20:59 +08:00
he c0478ef96e 修改
continuous-integration/drone/push Build is running Details
2025-04-03 16:19:32 +08:00
he 4713d2a09b Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-04-03 16:05:01 +08:00
he ea72e6cf65 修改 2025-04-03 16:05:01 +08:00
hang 9f5aee9258 修改hir minio 上传测试
continuous-integration/drone/push Build is passing Details
2025-04-03 15:57:06 +08:00
hang e56d1b9573 换一种方式忽略证书
continuous-integration/drone/push Build is passing Details
2025-04-03 11:14:06 +08:00
hang 6d5a7bd3a2 修改验证https 证书测试
continuous-integration/drone/push Build is passing Details
2025-04-03 11:03:45 +08:00
he a73ef7108b 没用的文件删除
continuous-integration/drone/push Build is passing Details
2025-04-03 10:35:45 +08:00
he 507500f051 先不删除文件
continuous-integration/drone/push Build is passing Details
2025-04-03 10:12:47 +08:00
he 913084cc8d 修改
continuous-integration/drone/push Build is passing Details
2025-04-03 09:57:37 +08:00
he 5874223866 修改
continuous-integration/drone/push Build is passing Details
2025-04-03 09:55:04 +08:00
he d5609560e2 Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-04-03 09:20:23 +08:00
he a5b4ab6531 修改 2025-04-03 09:20:22 +08:00
hang a91705b35d tj cmove 检查
continuous-integration/drone/push Build is passing Details
2025-04-02 10:01:33 +08:00
hang 65369c73bf 测试发布
continuous-integration/drone/push Build is passing Details
2025-04-01 17:32:37 +08:00
hang eb9bb75825 修改创建的临时token
continuous-integration/drone/push Build is passing Details
2025-04-01 17:04:50 +08:00
hang 69216ae75d HIR 同济对接接口完成
continuous-integration/drone/push Build is passing Details
2025-04-01 16:06:53 +08:00
hang 309ea7b1d1 HIR 对接自动生成账号
continuous-integration/drone/push Build is passing Details
2025-04-01 15:01:39 +08:00
hang 5beacacc0f 医院修改,导致配置修改
continuous-integration/drone/push Build is passing Details
2025-03-28 14:38:23 +08:00
hang 008a909f5b 增加统计配置文件
continuous-integration/drone/push Build is passing Details
2025-03-28 14:17:45 +08:00
hang bdfc65c07b 设置请求方式httpget
continuous-integration/drone/push Build is passing Details
2025-03-28 10:08:52 +08:00
hang 5ee7a70c65 修改账号排序
continuous-integration/drone/push Build is passing Details
2025-03-28 10:03:54 +08:00
hang c9590829b2 Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-03-28 09:54:59 +08:00
hang 80805bde06 增加默认字段 2025-03-28 09:54:57 +08:00
he 20718bca5d Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-03-28 09:52:31 +08:00
he 3d58e91644 修改模板 2025-03-28 09:52:31 +08:00
hang ade2a25fc4 获取tj 医院tokenInfo
continuous-integration/drone/push Build is passing Details
2025-03-28 09:38:12 +08:00
hang dcddf88a66 getUser 返回账户信息
continuous-integration/drone/push Build is passing Details
2025-03-27 17:31:01 +08:00
hang 89574e05bc Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-03-27 16:30:50 +08:00
hang 95fe14fece HIR 增加下拉框切换账户 2025-03-27 16:30:43 +08:00
he cfaf14ed65 模板修改
continuous-integration/drone/push Build is passing Details
2025-03-27 16:25:14 +08:00
he a50f82c42a Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-03-27 15:54:51 +08:00
he 1c0e1e01ce 报告修改医院名称 2025-03-27 15:54:50 +08:00
hang 5ec3fc3d13 修改创建账户默认密码
continuous-integration/drone/push Build is passing Details
2025-03-27 14:48:04 +08:00
he 9bd080b566 修改模板
continuous-integration/drone/push Build is passing Details
2025-03-26 15:52:06 +08:00
he f7cdb5b858 修改
continuous-integration/drone/push Build is passing Details
2025-03-26 14:15:46 +08:00
he 00c3ad8f9e 修改模板
continuous-integration/drone/push Build is passing Details
2025-03-25 16:32:54 +08:00
he d4b3038f6d Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-03-25 15:45:16 +08:00
he dde513a976 修改检查类型 2025-03-25 15:45:15 +08:00
hang 8378e8f2d6 多模态过滤
continuous-integration/drone/push Build is passing Details
2025-03-25 15:30:15 +08:00
hang 374f024f85 Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is failing Details
2025-03-25 14:56:22 +08:00
hang 32aadceaac 增加多模态 2025-03-25 14:56:19 +08:00
he 285e742136 Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-03-25 14:34:07 +08:00
he 704a876cf0 修改 2025-03-25 14:34:06 +08:00
hang 7184ea9565 Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-03-25 14:09:07 +08:00
hang 6da50126e1 增加国际化 2025-03-25 14:09:06 +08:00
he 965c8a56c9 Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-03-25 13:11:25 +08:00
he 0611c1d9fe 代码修改 2025-03-25 13:11:22 +08:00
hang 642acc9cba Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-03-25 11:29:39 +08:00
hang b87fb98c6c 修改pacs 查询 2025-03-25 11:29:37 +08:00
he d0d249655b Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-03-25 09:37:00 +08:00
he a847bb1785 模版修改 2025-03-25 09:36:58 +08:00
hang 445ee00840 修改时间查询
continuous-integration/drone/push Build is passing Details
2025-03-25 09:25:28 +08:00
he ecd33d969b 修改
continuous-integration/drone/push Build is passing Details
2025-03-24 17:10:59 +08:00
he 470420410e 代码修改
continuous-integration/drone/push Build is passing Details
2025-03-24 16:39:07 +08:00
he 2952b9e59f 添加字段
continuous-integration/drone/push Build is passing Details
2025-03-24 16:18:19 +08:00
he 7e8995a7b2 生成肿瘤报告
continuous-integration/drone/push Build is passing Details
2025-03-24 16:15:21 +08:00
he e7046173f8 Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2025-03-24 09:45:15 +08:00
he f1a39e3b9d 修改 2025-03-24 09:45:12 +08:00
hang 2838f232f3 修改权限
continuous-integration/drone/push Build is passing Details
2025-03-21 14:54:34 +08:00
hang 9ac4b262f3 增加id
continuous-integration/drone/push Build is passing Details
2025-03-21 14:08:39 +08:00
hang 582b8b3c07 更新数据库
continuous-integration/drone/push Build is passing Details
2025-03-21 10:19:04 +08:00
hang 91b20e07f2 HIR 管理端医院修改
continuous-integration/drone/push Build is passing Details
2025-03-21 10:15:31 +08:00
hang 5a99f476f9 增加拉取查询
continuous-integration/drone/push Build is passing Details
2025-03-20 15:04:45 +08:00
hang e06b47c8b3 查询某个项目下患者最新的检查列表初步修改
continuous-integration/drone/push Build is passing Details
2025-03-18 13:52:57 +08:00
hang 613cf6441b 修改推送监控记录
continuous-integration/drone/push Build is passing Details
2025-03-17 17:51:43 +08:00
hang 57dd964db2 minio 区域配置,导致上传失败问题
continuous-integration/drone/push Build is passing Details
2025-02-17 14:07:28 +08:00
hang 42dd5d384f 测试
continuous-integration/drone/push Build is passing Details
2025-02-07 19:55:42 +08:00
hang f2138623f4 修改日志记录文本名
continuous-integration/drone/push Build is passing Details
2025-02-07 17:56:32 +08:00
hang c69b2569ce 增加日志记录发送Cmove
continuous-integration/drone/push Build is passing Details
2025-02-07 17:21:29 +08:00
hang 6f8b88422b 修改配置文件
continuous-integration/drone/push Build is passing Details
2025-02-07 16:58:26 +08:00
hang 4c4d19b0d6 修改测试
continuous-integration/drone/push Build is passing Details
2025-02-07 16:17:50 +08:00
hang 91e0f0b787 每个检查只取instance的最新的一条
continuous-integration/drone/push Build is passing Details
2025-02-07 13:26:24 +08:00
hang c7f64ea0fe 修改查询位置
continuous-integration/drone/push Build is passing Details
2025-02-07 12:27:53 +08:00
hang fdb0b74296 修改Cmove 推送命令
continuous-integration/drone/push Build is passing Details
2025-02-07 11:25:08 +08:00
hang 0d7a04f1e8 清理状态再次测试
continuous-integration/drone/push Build is passing Details
2025-01-07 14:01:34 +08:00
hang 0a72c15dfd xxx
continuous-integration/drone/push Build is passing Details
2025-01-07 13:46:39 +08:00
hang 282c0b40c2 HIR 申请重阅,如果后续任务已经拷贝了表单,申请当前任务后,后续拷贝的表单删除
continuous-integration/drone/push Build is passing Details
2025-01-07 13:40:24 +08:00
hang 5783f5836a 数据库配置
continuous-integration/drone/push Build is passing Details
2025-01-06 14:35:54 +08:00
hang aff1f5b599 维护数据根据发送端加锁
continuous-integration/drone/push Build is passing Details
2024-12-30 09:01:12 +08:00
hang b12079f8d9 修改数据库连接
continuous-integration/drone/push Build is passing Details
2024-12-27 17:38:11 +08:00
hang 99de20ef76 修改AOA 不能看admin
continuous-integration/drone/push Build is passing Details
2024-12-27 17:19:57 +08:00
hang c187b5fb94 修改参数位置
continuous-integration/drone/push Build is passing Details
2024-12-20 13:55:02 +08:00
hang d852de4a5b 修改稽查报错
continuous-integration/drone/push Build is passing Details
2024-12-20 12:50:41 +08:00
hang d10020d944 修改关联关系
continuous-integration/drone/push Build is passing Details
2024-12-20 11:13:29 +08:00
hang f7c17546da 多模态修改
continuous-integration/drone/push Build is passing Details
2024-12-20 11:05:33 +08:00
hang c267bb34b4 支持多模态查询
continuous-integration/drone/push Build is passing Details
2024-12-20 10:31:59 +08:00
hang 98b0b36e3b 修改AE 测试
continuous-integration/drone/push Build is passing Details
2024-12-19 16:00:50 +08:00
hang 468224cae9 修改c-find 测试pacs在线与否
continuous-integration/drone/push Build is passing Details
2024-12-19 15:00:32 +08:00
hang 6b385b619a 修改国际化
continuous-integration/drone/push Build is passing Details
2024-12-19 14:42:56 +08:00
hang 88669ccbff 修改验证 和测试
continuous-integration/drone/push Build is passing Details
2024-12-19 14:30:14 +08:00
hang 5f338de0cd 修改时间解析
continuous-integration/drone/push Build is passing Details
2024-12-19 12:29:50 +08:00
hang c266c68be8 修改时间查询
continuous-integration/drone/push Build is passing Details
2024-12-19 10:36:21 +08:00
hang 364b84fd1c 修改时间
continuous-integration/drone/push Build is passing Details
2024-12-19 10:03:56 +08:00
hang 982bd80898 修改modality 查询
continuous-integration/drone/push Build is passing Details
2024-12-19 09:48:45 +08:00
hang 0050ae8d0a 增加patientName
continuous-integration/drone/push Build is passing Details
2024-12-18 13:10:43 +08:00
hang 8d11115fab 修改提示
continuous-integration/drone/push Build is passing Details
2024-12-18 12:55:06 +08:00
hang 355ca22134 增加客户端pacs ae 配置
continuous-integration/drone/push Build is passing Details
2024-12-18 11:30:19 +08:00
hang d568964c64 修改 HIR 验证
continuous-integration/drone/push Build is passing Details
2024-12-17 16:37:38 +08:00
hang 81443e5e36 列表展示
continuous-integration/drone/push Build is passing Details
2024-12-17 14:03:28 +08:00
hang 1c4d513f5b 修改查询
continuous-integration/drone/push Build is passing Details
2024-12-17 13:40:00 +08:00
hang d0a3ce9a09 后台任务Cmove 影像
continuous-integration/drone/push Build is passing Details
2024-12-16 13:44:54 +08:00
hang 0a368c0607 修改增加接口
continuous-integration/drone/push Build is passing Details
2024-12-13 16:52:15 +08:00
hang 1104c1481e 修改解析
continuous-integration/drone/push Build is passing Details
2024-12-13 16:00:25 +08:00
hang 7318dd4812 修改搜索条件
continuous-integration/drone/push Build is passing Details
2024-12-13 13:24:18 +08:00
hang 1ee30d047d 修改Patient 请求
continuous-integration/drone/push Build is passing Details
2024-12-12 17:48:33 +08:00
hang 39e7218b52 拉取影像
continuous-integration/drone/push Build is passing Details
2024-12-12 16:28:43 +08:00
hang 959fa1c40c 修改HIR 提示
continuous-integration/drone/push Build is passing Details
2024-12-02 13:33:55 +08:00
hang fb074048df 修改用户过滤
continuous-integration/drone/push Build is passing Details
2024-11-29 17:44:45 +08:00
hang 0b20c42513 修改加密解密
continuous-integration/drone/push Build is passing Details
2024-11-29 15:19:43 +08:00
hang 7c0e53db73 Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2024-11-28 16:19:10 +08:00
hang d77a6ebda0 加密解密的修改 2024-11-28 16:19:07 +08:00
he 42f7bf9c97 修改模板
continuous-integration/drone/push Build is passing Details
2024-11-28 14:55:42 +08:00
hang b9d9552ae8 Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing Details
2024-11-28 13:20:04 +08:00
hang ba81a842b7 修改用户机构名字 2024-11-28 13:20:03 +08:00
hang 28b3f16ef0 修改用户机构名字
continuous-integration/drone/push Build is passing Details
2024-11-28 13:17:31 +08:00
hang 37bf4905bb 修改IR查询条件
continuous-integration/drone/push Build is passing Details
2024-11-28 10:57:48 +08:00
hang 0ab9cebe45 修改IR 阅片查询
continuous-integration/drone/push Build is passing Details
2024-11-28 10:49:45 +08:00
hang a8c9587572 修改环境配置
continuous-integration/drone/push Build is passing Details
2024-11-28 10:30:16 +08:00
hang 48380aa7ea 修改HIR 配置文件
continuous-integration/drone/push Build is passing Details
2024-11-27 14:18:23 +08:00
hang b1831bfba0 修改token获取
continuous-integration/drone/push Build is passing Details
2024-11-27 13:41:35 +08:00
hang b9f866807e 修改模板调整
continuous-integration/drone/push Build is passing Details
2024-11-25 17:12:32 +08:00
hang 8896450fcc 修改导表 判断
continuous-integration/drone/push Build is passing Details
2024-11-25 16:21:20 +08:00
hang 2dc0cc3525 修改导表bug 初步测试
continuous-integration/drone/push Build is passing Details
2024-11-25 15:08:12 +08:00
hang a3f635894b 修改导表,日志记录
continuous-integration/drone/push Build is passing Details
2024-11-25 11:47:52 +08:00
hang 542ead68a7 稽查修改
continuous-integration/drone/push Build is passing Details
2024-11-25 09:30:30 +08:00
hang 7c25809ad5 稽查修改数据
continuous-integration/drone/push Build is passing Details
2024-11-22 17:10:09 +08:00
hang 1f14adec2a 增加邮箱查询
continuous-integration/drone/push Build is passing Details
2024-11-22 16:58:28 +08:00
hang 8173e6a8f2 修改下载返回间隔
continuous-integration/drone/push Build is failing Details
2024-11-22 16:25:00 +08:00
he 0baf4700f1 发布
continuous-integration/drone/push Build is failing Details
2024-11-22 15:22:05 +08:00
he e3f1fe5569 doctorID 匹配修改
continuous-integration/drone/push Build is failing Details
2024-11-22 15:14:43 +08:00
he 9aa5c27f60 Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is failing Details
2024-11-22 14:53:30 +08:00
he a1479420c8 去掉doctorid匹配 2024-11-22 14:53:29 +08:00
hang 0f368f0a5e 修改发布
continuous-integration/drone/push Build is passing Details
2024-11-21 11:22:54 +08:00
hang 5d0c6417a4 修改Patient 返回影响列表
continuous-integration/drone/push Build is passing Details
2024-11-21 09:35:01 +08:00
hang 12d8944ca7 前端用新的方式对接修改
continuous-integration/drone/push Build is passing Details
2024-11-21 09:24:22 +08:00
hang 521a4ad3f0 HIR_UAT 修改
continuous-integration/drone/push Build is passing Details
2024-11-20 16:25:10 +08:00
hang 040777ec87 修改查询参数
continuous-integration/drone/push Build is passing Details
2024-11-14 17:22:51 +08:00
hang b68d3a5d99 移除HIR后端下载字段
continuous-integration/drone/push Build is passing Details
2024-11-14 17:00:11 +08:00
hang 0af3c5ab8b 影响下载修改
continuous-integration/drone/push Build is passing Details
2024-11-14 16:41:30 +08:00
hang 6ca1e81b6a 修改发布脚本
continuous-integration/drone/push Build is passing Details
2024-11-14 16:00:43 +08:00
hang 068b3fa8d7 修改HIR 获取检查报错
continuous-integration/drone/push Build is failing Details
2024-11-14 15:57:44 +08:00
hang 976b89e970 HIR 修改下载代码 2024-11-14 14:48:08 +08:00
he 47e85ebbdf Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8 2024-11-14 10:53:25 +08:00
he 44f33fb7f0 阅片报告功能 2024-11-14 10:53:23 +08:00
hang 2c5ba280e9 调整申请重阅调整 2024-11-14 10:12:32 +08:00
hang 5250cd524a 阅片接口返回之前的参数对接 2024-11-13 18:30:39 +08:00
hang 787dd9aa5f 修改标准默认配置,修改待阅列表数据 2024-11-13 15:39:16 +08:00
hang e059dcb2b2 HIR 稽查 授权,配置测试提交 2024-11-13 11:14:02 +08:00
hang 75bf9b394b 迁移HIR 初步提交 2024-11-12 16:50:28 +08:00
hang c158d53a39 HIR 数据库初始化准备 2024-11-12 09:40:13 +08:00
hang 8e6125796b IRC 迁移HIR 功能初步修改 2024-11-11 23:50:23 +08:00
247 changed files with 240264 additions and 470596 deletions

View File

@ -27,8 +27,7 @@ namespace IRaCIS.Core.SCP
//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.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value);
options.UseLoggerFactory(logFactory);

View File

@ -19,7 +19,7 @@
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Minio" Version="6.0.3" />
<PackageReference Include="Minio" Version="6.0.4" />
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
@ -36,4 +36,12 @@
<ProjectReference Include="..\IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj" />
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.Prod_HIR_SCP.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
</Project>

View File

@ -82,7 +82,6 @@ builder.Services.AddControllers(options =>
.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"));
@ -126,19 +125,25 @@ builder.Services.Configure<ForwardedHeadersOptions>(options =>
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
//Dicom影像渲染图片 跨平台
//builder.Services.AddDicomSetup();
new DicomSetupBuilder()
.RegisterServices(s =>
s.AddFellowOakDicom()
.AddTranscoderManager<NativeTranscoderManager>()
builder.Services.AddFellowOakDicom().AddTranscoderManager<NativeTranscoderManager>()
//.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
.AddImageManager<ImageSharpImageManager>())
.SkipValidation()
.Build();
.AddImageManager<ImageSharpImageManager>();
////Dicom影像渲染图片 跨平台
////builder.Services.AddDicomSetup();
//new DicomSetupBuilder()
// .RegisterServices(s =>
// s.AddFellowOakDicom()
// .AddTranscoderManager<NativeTranscoderManager>()
// //.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
// .AddImageManager<ImageSharpImageManager>())
// .SkipValidation()
// .Build();
#endregion
// Add services to the container.
@ -211,9 +216,14 @@ 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);
app.Run();

View File

@ -1,24 +1,24 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"Test_IRC_SCP": {
"Test_HIR_SCP": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:6200",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Test_IRC_SCP"
"ASPNETCORE_ENVIRONMENT": "Test_HIR_SCP"
}
},
"Uat_IRC_SCP": {
"Uat_HIR_SCP": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:6200",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Uat_IRC_SCP"
"ASPNETCORE_ENVIRONMENT": "Uat_HIR_SCP"
}
}
}

View File

@ -37,17 +37,13 @@ namespace IRaCIS.Core.SCP.Service
public class CStoreSCPService : DicomService, IDicomServiceProvider, IDicomCStoreProvider, IDicomCEchoProvider
{
//private IServiceProvider _injectServiceProvider { get; set; }
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[]
{
@ -58,27 +54,28 @@ namespace IRaCIS.Core.SCP.Service
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
// Lossless
DicomTransferSyntax.JPEGLSLossless,
DicomTransferSyntax.JPEG2000Lossless,
DicomTransferSyntax.JPEGProcess14SV1,
DicomTransferSyntax.JPEGProcess14,
DicomTransferSyntax.RLELossless,
// 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
DicomTransferSyntax.JPEGLSNearLossless,
DicomTransferSyntax.JPEG2000Lossy,
DicomTransferSyntax.JPEGProcess1,
DicomTransferSyntax.JPEGProcess2_4,
// 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
DicomTransferSyntax.ExplicitVRLittleEndian,
DicomTransferSyntax.ExplicitVRBigEndian,
DicomTransferSyntax.ImplicitVRLittleEndian
};
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,50 +89,22 @@ namespace IRaCIS.Core.SCP.Service
Log.Logger.Warning($"接收到来自{association.CallingAE}的连接");
_serviceProvider = (IServiceProvider)this.UserState;
//_serviceProvider = (IServiceProvider)this.UserState;
//var tt = _injectServiceProvider;
var option = _serviceProvider.GetService<IOptionsMonitor<DicomSCPServiceOption>>().CurrentValue;
var _trialDicomAERepository = _serviceProvider.GetService<IRepository<TrialDicomAE>>();
var calledAEList = option.CalledAEList;
if (!calledAEList.Contains(association.CalledAE))
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)
//if (association.CalledAE != "STORESCP")
{
Log.Logger.Warning($"拒绝CallingAE:{association.CallingAE} CalledAE:{association.CalledAE}的连接");
Log.Logger.Warning($"拒绝CalledAE:{association.CalledAE}的连接");
return SendAssociationRejectAsync(
DicomRejectResult.Permanent,
@ -155,33 +124,32 @@ namespace IRaCIS.Core.SCP.Service
}
}
return SendAssociationAcceptAsync(association);
}
public async Task OnReceiveAssociationReleaseRequestAsync()
{
await DataMaintenanceAsaync();
var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();
//记录监控
var @lock = _distributedLockProvider.CreateLock($"{_upload.CallingAE}");
var _SCPImageUploadRepository = _serviceProvider.GetService<IRepository<SCPImageUpload>>();
using (await @lock.AcquireAsync())
{
_upload.EndTime = DateTime.Now;
_upload.StudyCount = _SCPStudyIdList.Count;
_upload.TrialId = _trialId;
_upload.TrialSiteId = _trialSiteId;
await DataMaintenanceAsaync();
await _SCPImageUploadRepository.AddAsync(_upload, true);
//记录监控
var _SCPImageUploadRepository = _serviceProvider.GetService<IRepository<SCPImageUpload>>();
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
//将检查设置为传输结束
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
_upload.EndTime = DateTime.Now;
_upload.StudyCount = _SCPStudyIdList.Count;
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
//可能是测试echo 导致记录了
await _SCPImageUploadRepository.AddAsync(_upload, _upload.FileCount > 0 ? true : false);
}
await SendAssociationReleaseResponseAsync();
}
@ -189,9 +157,11 @@ namespace IRaCIS.Core.SCP.Service
private async Task DataMaintenanceAsaync()
{
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}传输结束开始维护数据处理检查Modality");
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}传输结束开始维护数据处理检查Modality 以及自动创建访视,绑定检查");
var patientStudyService = _serviceProvider.GetService<IPatientStudyService>();
await patientStudyService.AutoBindingPatientStudyVisitAsync(_SCPStudyIdList);
//处理检查Modality
var _dictionaryRepository = _serviceProvider.GetService<IRepository<Dictionary>>();
@ -243,11 +213,11 @@ namespace IRaCIS.Core.SCP.Service
//奇怪的bug 上传的时候用王捷修改的影像会关闭重新连接导致检查id 丢失,然后状态不一致
if (exception == null)
{
//var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
////将检查设置为传输结束
//await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
//将检查设置为传输结束
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
//await _studyRepository.SaveChangesAndClearAllTrackingAsync();
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
}
Log.Logger.Warning($"连接关闭 {exception?.Message} {exception?.InnerException?.Message}");
@ -263,9 +233,8 @@ namespace IRaCIS.Core.SCP.Service
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());
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid);
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid);
var ossService = _serviceProvider.GetService<IOSSService>();
@ -275,7 +244,7 @@ namespace IRaCIS.Core.SCP.Service
var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();
var storeRelativePath = string.Empty;
var ossFolderPath = $"{_trialId}/Image/PACS/{_trialSiteId}{studyInstanceUid}";
var ossFolderPath = $"Dicom/{studyInstanceUid}";
long fileSize = 0;
@ -308,7 +277,7 @@ 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.Dataset, storeRelativePath, Association.CallingAE, Association.CalledAE, fileSize);
if (!_SCPStudyIdList.Contains(scpStudyId))
{
@ -337,10 +306,14 @@ namespace IRaCIS.Core.SCP.Service
series.ImageResizePath = seriesPath;
//await _seriesRepository.BatchUpdateNoTrackingAsync(t => t.Id == seriesId, u => new SCPSeries() { ImageResizePath = seriesPath });
}
}
await _seriesRepository.SaveChangesAsync();
}
catch (Exception ex)

View File

@ -11,7 +11,6 @@ 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
@ -52,18 +51,18 @@ 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(DicomDataset dataset, 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);
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());
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid);
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid);
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid);
var isStudyNeedAdd = false;
var isSeriesNeedAdd = false;
@ -74,15 +73,16 @@ namespace IRaCIS.Core.SCP.Service
//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 findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr);
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)
if (findPatient == null && findStudy == null)
{
isPatientNeedAdd = true;
@ -90,8 +90,6 @@ namespace IRaCIS.Core.SCP.Service
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),
@ -117,20 +115,6 @@ namespace IRaCIS.Core.SCP.Service
{
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
{
@ -163,8 +147,6 @@ namespace IRaCIS.Core.SCP.Service
PatientId = findPatient.Id,
Id = studyId,
TrialId = trialId,
TrialSiteId = trialSiteId,
StudyInstanceUid = studyInstanceUid,
StudyTime = studyTime,
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
@ -273,8 +255,7 @@ namespace IRaCIS.Core.SCP.Service
Path = fileRelativePath,
FileSize= fileSize,
FileSize = fileSize,
};
++findStudy.InstanceCount;
@ -298,13 +279,14 @@ namespace IRaCIS.Core.SCP.Service
{
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 _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath, FileSize = fileSize });
}
await _studyRepository.SaveChangesAsync();

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(DicomDataset dicomDataset,string fileRelativePath,string callingAE,string calledAE,long fileSize);
}
}

View File

@ -12,6 +12,7 @@ using MassTransit;
using Microsoft.Extensions.Options;
using Minio;
using Minio.DataModel.Args;
using System.Net;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
@ -216,9 +217,19 @@ public class OSSService : IOSSService
.WithBucket(minIOConfig.BucketName)
.WithObject(ossRelativePath)
.WithStreamData(memoryStream)
.WithObjectSize(memoryStream.Length);
await minioClient.PutObjectAsync(putObjectArgs);
var putResponse = await minioClient.PutObjectAsync(putObjectArgs);
if (putResponse.ResponseStatusCode == HttpStatusCode.OK)
{
}
else
{
throw new BusinessValidationFailedException($"上传发生异常:{putResponse.ResponseContent}");
}
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
{

View File

@ -0,0 +1,249 @@
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 Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.EntityFrameworkCore;
namespace IRaCIS.Core.SCP.Service
{
public interface IPatientStudyService
{
Task<IResponseOutput> AutoBindingPatientStudyVisitAsync(List<Guid> scpStudyIdList);
}
[ApiExplorerSettings(GroupName = "Trial")]
public class PatientStudyService : BaseService, IPatientStudyService
{
private readonly IRepository<SCPStudySubjectVisit> _studySubjectVisitRepository;
private readonly IRepository<SubjectPatient> _subjectPatientRepository;
private readonly IRepository<Trial> _trialRepository;
private readonly IRepository<SCPPatient> _patientRepository;
private readonly IRepository<SCPStudy> _studyRepository;
private readonly IRepository<Subject> _subjectRepository;
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
private readonly IDistributedLockProvider _distributedLockProvider;
public PatientStudyService(IRepository<SCPStudySubjectVisit> studySubjectVisitRepository, IRepository<SCPStudy> studyRepository, IRepository<SubjectPatient> subjectPatientRepository, IRepository<Trial> trialRepository, IRepository<SCPPatient> patientRepository, IRepository<Subject> subjectRepository, IRepository<SubjectVisit> subjectVisitRepository, IDistributedLockProvider distributedLockProvider)
{
_studySubjectVisitRepository = studySubjectVisitRepository;
_studyRepository = studyRepository;
_subjectPatientRepository = subjectPatientRepository;
_trialRepository = trialRepository;
_patientRepository = patientRepository;
_subjectRepository = subjectRepository;
_subjectVisitRepository = subjectVisitRepository;
_distributedLockProvider = distributedLockProvider;
}
public class AuToBindingStudyInfo
{
public Guid SCPStudyId { get; set; }
public DateTime? StudyTime { get; set; }
}
private async Task DealAutoBindingStudyAsync(Guid trialId, Guid subjectId, List<AuToBindingStudyInfo> studyList, decimal? startBindVisitNum = null)
{
//自动创建访视 和检查绑定
//1. 查询已存在的访视
var subjectAllVisitList = await _subjectVisitRepository.Where(t => t.SubjectId == subjectId)
.Select(t => new
{
t.SubjectId,
SubjectVisitId = t.Id,
t.SubmitState,
VisitNum = t.VisitNum,
MaxStudyTime = t.SCPStudySubjectVisitList.Max(t => t.SCPStudy.StudyTime),
MinStudyTime = t.SCPStudySubjectVisitList.Min(t => t.SCPStudy.StudyTime)
})
.ToListAsync();
//2、获取项目配置
var trialconfig = _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.BlindBaseLineName, t.BlindFollowUpPrefix }).FirstOrDefault();
//3、 未提交的最小的访视号 从这个访视开始绑定
var subjectMaxVisitNum = startBindVisitNum == null ? subjectAllVisitList.Where(t => t.SubmitState != SubmitStateEnum.Submitted).MinOrDefault(t => t.VisitNum) : startBindVisitNum.Value;
List<(int VisitCount, Guid SCPStudyId)> visits = new List<(int, Guid)>();
int visitCount = 0;
DateTime? lastVisitTime = null;
foreach (var study in studyList)
{
if (lastVisitTime == null || (study.StudyTime - lastVisitTime.Value).Value.TotalDays >= 15)
{
// 当前时间点与上一个访视时间点间隔大于等于 15 天,需要建立一个新的访视
visitCount++;
visits.Add((visitCount, study.SCPStudyId));
}
else
{
visits.Add((visitCount, study.SCPStudyId));
}
lastVisitTime = study.StudyTime;
}
//4、生成访视 并且绑定
for (int i = 0; i < visitCount; i++)
{
var bindSubjectVisitId = Guid.Empty;
var bindVisitNum = i + subjectMaxVisitNum;
var existSubjectVisit = subjectAllVisitList.FirstOrDefault(t => t.SubjectId == subjectId && t.VisitNum == bindVisitNum);
if (existSubjectVisit == null)
{
bindSubjectVisitId = NewId.NextGuid();
//基线
if (bindVisitNum == 0)
{
await _subjectVisitRepository.AddAsync(new SubjectVisit() { TrialId = trialId, SubjectId = subjectId, VisitName = trialconfig.BlindBaseLineName, VisitNum = bindVisitNum, Id = bindSubjectVisitId, SubmitState = SubmitStateEnum.ToSubmit, IsBaseLine = true });
}
else
{
await _subjectVisitRepository.AddAsync(new SubjectVisit() { TrialId = trialId, SubjectId = subjectId, VisitName = trialconfig.BlindFollowUpPrefix + $" {(int)bindVisitNum}", VisitNum = bindVisitNum, Id = bindSubjectVisitId, SubmitState = SubmitStateEnum.ToSubmit });
}
}
else
{
bindSubjectVisitId = existSubjectVisit.SubjectVisitId;
}
var currentVisitStudyList = visits.Where(t => t.VisitCount == (i + 1)).ToList();
foreach (var item in currentVisitStudyList)
{
//访视状态为未提交才绑定
if (!subjectAllVisitList.Any(t => t.SubjectId == subjectId && t.SubjectVisitId == bindSubjectVisitId && t.SubmitState == SubmitStateEnum.Submitted))
{
var find = await _subjectVisitRepository.FindAsync(bindSubjectVisitId);
find.SubmitState = SubmitStateEnum.ToSubmit;
await _studySubjectVisitRepository.AddAsync(new SCPStudySubjectVisit() { TrialId = trialId, SubjectVisitId = bindSubjectVisitId, SCPStudyId = item.SCPStudyId, SubjectId = subjectId });
}
}
}
await _subjectPatientRepository.SaveChangesAsync();
}
/// <summary>
/// 传输完成后,自动给检查绑定访视
/// </summary>
/// <param name="inCommand"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> AutoBindingPatientStudyVisitAsync(List<Guid> scpStudyIdList)
{
//一个检查 可能绑定到不同的项目的不同subject 有的该检查已绑定访视,有的该检查绑定了访视
var query = from scpStudy in _studyRepository.Where(t => scpStudyIdList.Contains(t.Id))
join subjectPatient in _subjectPatientRepository.AsQueryable()
on scpStudy.PatientId equals subjectPatient.PatientId
select new
{
subjectPatient.Subject.Status,
subjectPatient.Subject.TrialId,
subjectPatient.SubjectId,
subjectPatient.PatientId,
SCPStudyId = scpStudy.Id,
scpStudy.StudyTime
};
var list = query.ToList();
if (list.Count > 0)
{
var subjectIdList = list.Select(t => t.SubjectId).ToList();
var allSubjectVisitList = await _subjectVisitRepository.Where(t => subjectIdList.Contains(t.SubjectId))
.Select(t => new { t.SubjectId, SubjectVisitId = t.Id, t.SubmitState, VisitNum = t.VisitNum, MaxStudyTime = t.SCPStudySubjectVisitList.Max(t => t.SCPStudy.StudyTime), MinStudyTime = t.SCPStudySubjectVisitList.Min(t => t.SCPStudy.StudyTime) })
.ToListAsync();
foreach (var g in list.GroupBy(t => new { t.SubjectId, t.TrialId, t.Status }))
{
var subjectId = g.Key.SubjectId;
var trialId = g.Key.TrialId;
//访视结束,那么就不处理
if (g.Key.Status == SubjectStatus.EndOfVisit)
{
continue;
}
// 预先处理1 数据库可能有已存在的subject 患者绑定,在这里要一起考虑绑定
var dbPatientIdList = _subjectPatientRepository.Where(t => t.SubjectId == subjectId).Select(t => t.PatientId).ToList();
// 预先处理2 删除未提交的所有绑定的检查记录,所有检查一起考虑绑定
await _studySubjectVisitRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState != SubmitStateEnum.Submitted);
//预处理3 找到该subjecct 已提交的访视的最大检查时间,绑定的检查时间要比这个时间要大
var maxStudyTime = allSubjectVisitList.Where(t => t.SubjectId == subjectId && t.SubmitState == SubmitStateEnum.Submitted).MaxOrDefault(t => t.MaxStudyTime);
// 预处理4 处理需要绑定的检查
//获取 该受试者绑定患者已存在的检查,考虑要生成多少个访视,去除已提交的检查
var studyList = await _studyRepository.Where(t => dbPatientIdList.Contains(t.PatientId)
&& !t.SCPStudySubjectVisitList.Any(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState == SubmitStateEnum.Submitted))
.WhereIf(maxStudyTime != null, t => t.StudyTime > maxStudyTime)
.Select(t => new AuToBindingStudyInfo { SCPStudyId = t.Id, StudyTime = t.StudyTime }).OrderBy(t => t.StudyTime).ToListAsync();
await DealAutoBindingStudyAsync(trialId, subjectId, studyList);
}
await _subjectVisitRepository.SaveChangesAsync();
}
//将检查设置为传输结束
await _studyRepository.BatchUpdateNoTrackingAsync(t => scpStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
return ResponseOutput.Ok();
}
}
}

View File

@ -0,0 +1,35 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "MinIO",
"MinIO": {
"EndPoint": "192.168.3.112",
"Port": "9000",
"UseSSL": false,
"AccessKeyId": "Jnywl9aIw83yewZIJKod",
"SecretAccessKey": "N83bTzoJGkg4OLW8x54IZRwwSvdxcdYi9UZ2BYII",
"BucketName": "hir-images",
"ViewEndpoint": "http://192.168.3.112:9000/hir-images"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=192.168.3.114,1433;Database=Prod_HIR_Images;User ID=sa;Password=xc_123456;TrustServerCertificate=true",
"Hangfire": "Server=192.168.3.114,1433;Database=Prod_HIR_Hangfire;User ID=sa;Password=xc_123456;TrustServerCertificate=true"
},
"DicomSCPServiceConfig": {
"CalledAEList": [
"STORESCP",
"HIRAE",
"Value2",
"Value3"
],
"ServerPort": 11112
}
}

View File

@ -1,37 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "AliyunOSS",
"AliyunOSS": {
"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",
"Region": "oss-cn-shanghai",
"DurationSeconds": 7200
}
},
"ConnectionStrings": {
"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"
},
"DicomSCPServiceConfig": {
"CalledAEList": [
"STORESCP"
],
"ServerPort": 11112
}
}

View File

@ -0,0 +1,35 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "MinIO",
"MinIO": {
"EndPoint": "192.168.40.99",
"Port": "9000",
"UseSSL": false,
"AccessKeyId": "Jnywl9aIw83yewZIJKod",
"SecretAccessKey": "N83bTzoJGkg4OLW8x54IZRwwSvdxcdYi9UZ2BYII",
"BucketName": "tj-hir",
"ViewEndpoint": "http://192.168.40.99:9000/tj-hir"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=192.168.40.98,1433;Database=TJ_Prod_HIR;User ID=sa;Password=xc_123456;TrustServerCertificate=true",
"Hangfire": "Server=192.168.40.98,1433;Database=TJ_Prod_HIR_Hangfire;User ID=sa;Password=xc_123456;TrustServerCertificate=true"
},
"DicomSCPServiceConfig": {
"CalledAEList": [
"STORESCP",
"HIRAE",
"Value2",
"Value3"
],
"ServerPort": 11112
}
}

View File

@ -0,0 +1,35 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "MinIO",
"MinIO": {
"EndPoint": "106.14.89.110",
"Port": "9001",
"UseSSL": false,
"AccessKeyId": "fbStsVYCIPKHQneeqMwD",
"SecretAccessKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
"BucketName": "hir-test",
"ViewEndpoint": "http://106.14.89.110:9001/hir-test/"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_HIR_New;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=106.14.89.110,1435;Database=Test_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"DicomSCPServiceConfig": {
"CalledAEList": [
"STORESCP",
"HIRAE",
"Value2",
"Value3"
],
"ServerPort": 11112
}
}

View File

@ -1,48 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "AliyunOSS",
"AliyunOSS": {
"RegionId": "cn-shanghai",
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
"AccessKeyId": "LTAI5tRRZehUp2V9pyTPtAJm",
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
"BucketName": "zy-irc-test-store",
"ViewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
"Region": "oss-cn-shanghai",
"DurationSeconds": 7200
},
"MinIO": {
"endPoint": "106.14.89.110",
"port": "9001",
"useSSL": false,
"accessKey": "fbStsVYCIPKHQneeqMwD",
"secretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
"bucketName": "hir-test",
"viewEndpoint": "http://106.14.89.110:9001/hir-test/"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"DicomSCPServiceConfig": {
"CalledAEList": [
"STORESCP"
],
"ServerPort": 11112
}
}

View File

@ -0,0 +1,35 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "MinIO",
"MinIO": {
"EndPoint": "3.226.182.187",
"Port": "9001",
"UseSSL": false,
"AccessKeyId": "7rvVIHs7D6pbyscRcJhz",
"SecretAccessKey": "DQsCQldHFL3QRjlnaLWV7oM4E9PtsO21QPC2h9BD",
"BucketName": "hir-us",
"ViewEndpoint": "http://hir-minio.uat.elevateimaging.ai/hir-us"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=3.226.182.187,1435;Database=US_HIR;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=3.226.182.187,1435;Database=US_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"DicomSCPServiceConfig": {
"CalledAEList": [
"STORESCP",
"HIRAE",
"Value2",
"Value3"
],
"ServerPort": 11112
}
}

View File

@ -1,34 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "AWS",
"AWS": {
"Region": "us-east-1",
"EndPoint": "s3.us-east-1.amazonaws.com",
"UseSSL": true,
"RoleArn": "arn:aws:iam::471112624751:role/lili_s3_access",
"AccessKeyId": "AKIAW3MEAFJXZ2TZK7GM",
"SecretAccessKey": "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",
"BucketName": "ei-med-s3-lili-store",
"ViewEndpoint": "https://ei-med-s3-lili-store.s3.amazonaws.com",
"DurationSeconds": 7200
}
},
"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"
},
"DicomSCPServiceConfig": {
"CalledAEList": [
"STORESCP"
],
"ServerPort": 11112
}
}

View File

@ -1,34 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "AWS",
"AWS": {
"Region": "us-east-1",
"EndPoint": "s3.us-east-1.amazonaws.com",
"UseSSL": true,
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
"SecretAccessKey": "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",
"BucketName": "ei-med-s3-lili-uat-store",
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com/",
"DurationSeconds": 7200
}
},
"ConnectionStrings": {
"RemoteNew": "Server=us-mssql-service,1433;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=us-mssql-service,1433;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"DicomSCPServiceConfig": {
"CalledAEList": [
"STORESCP"
],
"ServerPort": 11112
}
}

View File

@ -0,0 +1,37 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "MinIO",
"MinIO": {
"EndPoint": "101.132.253.119",
"Port": "9001",
"UseSSL": false,
"AccessKeyId": "ylWQa99fDdVdTfnj47ll",
"SecretAccessKey": "kVpy2RIYN0GmyFsU2qAWhbKDf4Nskt23tEqd6sob",
"BucketName": "hir-uat",
"ViewEndpoint": "http://101.132.253.119:9001/hir-uat/"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=101.132.253.119,1435;Database=Uat_HIR_New;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=101.132.253.119,1435;Database=Uat_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"DicomSCPServiceConfig": {
"CalledAEList": [
"STORESCP",
"HIRAE",
"Value2",
"Value3"
],
"ServerPort": 11112
}
}

View File

@ -1,35 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "AliyunOSS",
"AliyunOSS": {
"RegionId": "cn-shanghai",
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
"AccessKeyId": "LTAI5tRRZehUp2V9pyTPtAJm",
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
"BucketName": "zy-irc-uat-store",
"ViewEndpoint": "https://zy-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
"Region": "oss-cn-shanghai",
"DurationSeconds": 7200
}
},
"ConnectionStrings": {
"RemoteNew": "Server=47.117.164.182,1434;Database=Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=47.117.164.182,1434;Database=Uat_IRC.Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"DicomSCPServiceConfig": {
"CalledAEList": [
"STORESCP"
],
"ServerPort": 11112
}
}

View File

@ -1,4 +1,5 @@
using Amazon.Auth.AccessControlPolicy;
using AlibabaCloud.SDK.Sts20150401;
using Amazon.Auth.AccessControlPolicy;
using Amazon.SecurityToken;
using Azure.Core;
using IdentityModel.Client;
@ -24,6 +25,7 @@ using RestSharp;
using RestSharp.Authenticators;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
@ -101,6 +103,80 @@ namespace IRaCIS.Api.Controllers
[HttpGet, Route("user/loginSelectUserType")]
public async Task<IResponseOutput<LoginReturnDTO>> LoginSelectUserType(Guid userId, Guid userTypeId,
[FromServices] IUserService _userService,
[FromServices] IFusionCache _fusionCache,
[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 };
var returnModel = await _userService.LoginSelectUserType(userId, userTypeId);
if (returnModel.IsSuccess)
{
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;
}
@ -325,6 +401,7 @@ namespace IRaCIS.Api.Controllers
}
[HttpGet("user/GetObjectStoreToken")]
[AllowAnonymous]
public async Task<IResponseOutput> GetObjectStoreTokenAsync([FromServices] IOptionsMonitor<ObjectStoreServiceOptions> options, [FromServices] IOSSService _oSSService)
{
@ -374,7 +451,53 @@ namespace IRaCIS.Api.Controllers
return tempToken;
}
#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;
// 返回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")]

View File

@ -112,6 +112,48 @@
<Content Update="Resources\zh-CN.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\downLoad\file.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\ReportTemplate_IRECIST_CN_V1.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\ReportTemplate_PCWG3_CN_V1.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\ReportTemplate_RECIST1.1_CN_V1.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\TumorEvaluation_RECIST1.1_CN_V1.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\协和\ReportTemplate_IRECIST_CN_V1.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\协和\ReportTemplate_PCWG3_CN_V1.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\协和\ReportTemplate_RECIST1.1_CN_V1.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\同济\ReportTemplate_IRECIST_CN_V1.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\同济\ReportTemplate_PCWG3_CN_V1.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\同济\ReportTemplate_RECIST1.1_CN_V1.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\复旦大学肿瘤附属医院\ReportTemplate_IRECIST_CN_V1.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\复旦大学肿瘤附属医院\ReportTemplate_PCWG3_CN_V1.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\复旦大学肿瘤附属医院\ReportTemplate_RECIST1.1_CN_V1.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ProjectExtensions>

View File

@ -16,60 +16,31 @@
"ASPNETCORE_ENVIRONMENT": "Test_IRC"
}
},
"IRaCIS.Test_IRC": {
"Uat_HIR": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Test_IRC"
"ASPNETCORE_ENVIRONMENT": "Uat_HIR"
},
"applicationUrl": "http://localhost:6100"
},
"IRaCIS.Test_IRC_PGSQL": {
"Prod_HIR": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Test_IRC_PGSQL"
"ASPNETCORE_ENVIRONMENT": "Prod_HIR"
},
"applicationUrl": "http://localhost:6100"
},
"IRaCIS.Event_IRC": {
"Test_HIR": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Event_IRC"
},
"applicationUrl": "http://localhost:6100"
},
"Docker": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
"publishAllPorts": true
},
"IRaCIS.Uat_IRC": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Uat_IRC"
},
"applicationUrl": "http://localhost:6100"
},
"IRaCIS.Prod_IRC": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Prod_IRC"
},
"applicationUrl": "http://localhost:6100"
},
"IRaCIS.US_Uat_IRC": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "US_Uat_IRC"
"ASPNETCORE_ENVIRONMENT": "Test_HIR"
},
"applicationUrl": "http://localhost:6100"
}
}
}

View File

@ -1,6 +1,7 @@
using FellowOakDicom;
using FellowOakDicom.Imaging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace IRaCIS.Core.API
{
@ -9,12 +10,14 @@ namespace IRaCIS.Core.API
public static void AddDicomSetup(this IServiceCollection services)
{
new DicomSetupBuilder()
.RegisterServices(s => s.AddFellowOakDicom()
.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
.AddImageManager<ImageSharpImageManager>()
.RegisterServices(s => s.AddFellowOakDicom().AddLogging(config => config.AddConsole())
.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
//.AddImageManager<ImageSharpImageManager>()
)
.SkipValidation()
.Build();
}
}
}

View File

@ -80,8 +80,13 @@ namespace IRaCIS.Core.API
triggerOptions.AddTrigger<UserLogTrigger>();
triggerOptions.AddTrigger<UserAddTrigger>();
triggerOptions.AddTrigger<UserModifyTrigger>();
});
});

View File

@ -1,5 +1,6 @@
using IP2Region.Net.Abstractions;
using IP2Region.Net.XDB;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.BackGroundJob;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Service;

View File

@ -1,72 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"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"
},
"ObjectStoreService": {
"ObjectStoreUse": "AliyunOSS",
"AliyunOSS": {
"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",
"Region": "oss-cn-shanghai",
"DurationSeconds": 7200
},
"MinIO": {
"endpoint": "http://192.168.3.68",
"port": "8001",
"useSSL": false,
"accessKey": "IDFkwEpWej0b4DtiuThL",
"secretKey": "Lhuu83yMhVwu7c1SnjvGY6lq74jzpYqifK6Qtj4h",
"bucketName": "test"
}
},
"BasicSystemConfig": {
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": true,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 60,
"ContinuousReadingTimeMin": 120,
"ReadingRestTimeMin": 10,
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "uat@extimaging.com",
"FromName": "UAT_IRC",
"AuthorizationCode": "SHzyyl2021",
"SiteUrl": "http://irc.event.extimaging.com/login",
"CompanyName": "Extensive Imaging",
"CompanyNameCN": "上海展影医疗科技有限公司",
"CompanyShortName": "Extensive Imaging",
"CompanyShortNameCN": "展影医疗",
"IsEnv_US": false
}
}

View File

@ -0,0 +1,48 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "MinIO",
"MinIO": {
"EndPoint": "192.168.3.112",
"Port": "9080",
"UseSSL": true,
"AccessKeyId": "Jnywl9aIw83yewZIJKod",
"SecretAccessKey": "N83bTzoJGkg4OLW8x54IZRwwSvdxcdYi9UZ2BYII",
"BucketName": "hir-images",
"ViewEndpoint": "https://192.168.3.112:9080/hir-images"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=192.168.3.114,1433;Database=Prod_HIR_Images;User ID=sa;Password=xc_123456;TrustServerCertificate=true",
"Hangfire": "Server=192.168.3.114,1433;Database=Prod_HIR_Hangfire;User ID=sa;Password=xc_123456;TrustServerCertificate=true"
},
"BasicSystemConfig": {
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": false,
"OpenTrialRelationDelete": false,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 120,
"AESKey": "HIR_System_AES_Key_Info",
"CmoveIntervalMinutes": 1,
"CmoveInstanceIntervalMinutes": 1
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "test-study@extimaging.com",
"FromName": "Test_HIR",
"AuthorizationCode": "zhanying123",
"SiteUrl": "http://hir.test.extimaging.com/login"
}
}

View File

@ -1,82 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"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"
},
"ObjectStoreService": {
"ObjectStoreUse": "AliyunOSS",
"AliyunOSS": {
"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",
"Region": "oss-cn-shanghai",
"DurationSeconds": 7200
},
"MinIO": {
"endpoint": "http://192.168.3.68",
"port": "8001",
"useSSL": false,
"accessKey": "IDFkwEpWej0b4DtiuThL",
"secretKey": "Lhuu83yMhVwu7c1SnjvGY6lq74jzpYqifK6Qtj4h",
"bucketName": "test"
}
},
"BasicSystemConfig": {
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": true,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 360,
"OpenLoginMFA": false,
"ContinuousReadingTimeMin": 120,
"ReadingRestTimeMin": 10,
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "IRC@extimaging.com",
"FromName": "IRC",
"AuthorizationCode": "ExtImg@2022",
"SiteUrl": "http://irc.extimaging.com/login",
"OrganizationName": "Extlmaging",
"OrganizationNameCN": "Extlmaging",
"CompanyName": "Extensive Imaging",
"CompanyNameCN": "上海展影医疗科技有限公司",
"CompanyShortName": "Extensive Imaging",
"CompanyShortNameCN": "展影医疗",
"IsEnv_US": false,
"IsOpenErrorNoticeEmail": true,
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
},
"SystemPacsConfig": {
"Port": "11113",
"IP": "101.132.193.237"
}
}

View File

@ -0,0 +1,62 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "MinIO",
"MinIO": {
"EndPoint": "192.168.40.99",
"Port": "9000",
"UseSSL": false,
"AccessKeyId": "Jnywl9aIw83yewZIJKod",
"SecretAccessKey": "N83bTzoJGkg4OLW8x54IZRwwSvdxcdYi9UZ2BYII",
"BucketName": "tj-hir",
"ViewEndpoint": "http://192.168.40.99:9000/tj-hir"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=192.168.40.98,1433;Database=TJ_Prod_HIR;User ID=sa;Password=xc_123456;TrustServerCertificate=true",
"Hangfire": "Server=192.168.40.98,1433;Database=TJ_Prod_HIR_Hangfire;User ID=sa;Password=xc_123456;TrustServerCertificate=true"
},
"BasicSystemConfig": {
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": false,
"OpenTrialRelationDelete": false,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 120,
"AESKey": "HIR_System_AES_Key_Info",
"CmoveIntervalMinutes": 1,
"CmoveInstanceIntervalMinutes": 1
},
"SystemHospitalConfig": {
"HospitalCode": "EI",
"HospitalLogoPath": "/System/GeneralDocuments/1716453306898_图片2.png",
"TrialKeepCount": 60,
"HospitalName": "上海展影医疗科技有限公司",
"HospitalAliasName": "展影医疗",
"Country": "中国",
"City": "上海",
"Province": "上海",
"Address": "上海市杨浦区国泰路复旦科技园",
"Phone": "021-60702575",
"IsCanConnectInternet": false
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "test-study@extimaging.com",
"FromName": "Test_HIR",
"AuthorizationCode": "zhanying123",
"SiteUrl": "http://hir.test.extimaging.com/login"
}
}

View File

@ -0,0 +1,51 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "MinIO",
"MinIO": {
"EndPoint": "hir-oss.test.extimaging.com",
"Port": "443",
"UseSSL": true,
//"endPoint": "106.14.89.110",
//"port": "9001",
//"useSSL": false,
"AccessKeyId": "fbStsVYCIPKHQneeqMwD",
"SecretAccessKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
"BucketName": "hir-test",
//"viewEndpoint": "https://hir.test.extimaging.com/oss/hir-test"
"ViewEndpoint": "https://hir-oss.test.extimaging.com/hir-test"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_HIR_New;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=106.14.89.110,1435;Database=Test_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"BasicSystemConfig": {
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": true,
"OpenTrialRelationDelete": true,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 120,
"AESKey": "HIR_System_AES_Key_Info",
"CmoveIntervalMinutes": 1,
"CmoveInstanceIntervalMinutes": 1
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "test-study@extimaging.com",
"FromName": "Test_HIR",
"AuthorizationCode": "zhanying123",
"SiteUrl": "http://hir.test.extimaging.com/login"
}
}

View File

@ -1,95 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
"Db_Type": "pgsql",
"RemoteNew": "Host=106.14.89.110;Port=5432;Username=sa;Password=pgsql_pwd;Database=Test2_PG",
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"ObjectStoreService": {
"ObjectStoreUse": "AliyunOSS",
"AliyunOSS": {
"regionId": "cn-shanghai",
"internalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
"endPoint": "https://oss-cn-shanghai.aliyuncs.com",
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
"bucketName": "zy-irc-test-store",
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
"viewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
"region": "oss-cn-shanghai"
},
"MinIO": {
"endPoint": "hir-oss.test.extimaging.com",
"port": "443",
"useSSL": true,
"accessKey": "fbStsVYCIPKHQneeqMwD",
"secretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
"bucketName": "irc-test",
"viewEndpoint": "https://hir-oss.test.extimaging.com/irc-test"
},
"AWS": {
"endPoint": "s3.us-east-1.amazonaws.com",
"useSSL": true,
"accessKey": "AKIAZQ3DRSOHFPJJ6FEU",
"secretKey": "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",
"bucketName": "ei-irc-test-store",
"viewEndpoint": "https://ei-irc-test-store.s3.amazonaws.com/"
}
},
"BasicSystemConfig": {
"OpenUserComplexPassword": false,
"OpenSignDocumentBeforeWork": false,
"OpenTrialRelationDelete": true,
"OpenLoginLimit": false,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 1,
"AutoLoginOutMinutes": 1,
"OpenLoginMFA": false,
"ContinuousReadingTimeMin": 120,
"ReadingRestTimeMin": 10,
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "test@extimaging.com",
"FromName": "Test_IRC",
"AuthorizationCode": "SHzyyl2021",
"SiteUrl": "http://irc.test.extimaging.com/login",
"OrganizationName": "Extlmaging",
"OrganizationNameCN": "Extlmaging",
"CompanyName": "Extensive Imaging",
"CompanyNameCN": "上海展影医疗科技有限公司",
"CompanyShortName": "Extensive Imaging",
"CompanyShortNameCN": "展影医疗"
},
"SystemPacsConfig": {
"Port": "11113",
"IP": "106.14.89.110"
}
}

View File

@ -0,0 +1,48 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "MinIO",
"MinIO": {
"EndPoint": "hir-minio.uat.elevateimaging.ai",
"Port": "443",
"UseSSL": true,
"AccessKeyId": "7rvVIHs7D6pbyscRcJhz",
"SecretAccessKey": "DQsCQldHFL3QRjlnaLWV7oM4E9PtsO21QPC2h9BD",
"BucketName": "hir-us",
//"viewEndpoint": "https://hir.test.extimaging.com/oss/hir-test"
"ViewEndpoint": "https://hir-minio.uat.elevateimaging.ai/hir-us"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=3.226.182.187,1435;Database=US_HIR;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=3.226.182.187,1435;Database=US_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"BasicSystemConfig": {
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": true,
"OpenTrialRelationDelete": true,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 120,
"AESKey": "HIR_System_AES_Key_Info",
"CmoveIntervalMinutes": 1,
"CmoveInstanceIntervalMinutes": 1
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "uat-study@extimaging.com",
"FromName": "Uat_HIR",
"AuthorizationCode": "zhanying123",
"SiteUrl": "https://hir.uat.elevateimaging.ai/login"
}
}

View File

@ -1,87 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"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=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",
},
"ObjectStoreService": {
"ObjectStoreUse": "AWS",
"MinIO": {
"endPoint": "44.210.231.169",
"port": "9001",
"useSSL": false,
"accessKey": "e9bT1isTOqSAUxb6wd4n",
"secretKey": "b5TaDzNdQCBtCvfm8eZ3dR6yY7tfZu2JYze2Po1i",
"bucketName": "prod-irc-us",
"viewEndpoint": "http://44.210.231.169:9001/prod-irc-us/"
},
"AWS": {
"Region": "us-east-1",
"EndPoint": "s3.us-east-1.amazonaws.com",
"UseSSL": true,
"RoleArn": "arn:aws:iam::471112624751:role/lili_s3_access",
"AccessKeyId": "AKIAW3MEAFJXZ2TZK7GM",
"SecretAccessKey": "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",
"BucketName": "ei-med-s3-lili-store",
"ViewEndpoint": "https://ei-med-s3-lili-store.s3.amazonaws.com",
"DurationSeconds": 7200
}
},
"BasicSystemConfig": {
"OpenUserComplexPassword": false,
"OpenSignDocumentBeforeWork": false,
"OpenTrialRelationDelete": true,
"OpenLoginLimit": false,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 60,
"ContinuousReadingTimeMin": 120,
"ReadingRestTimeMin": 10,
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90
},
"SystemEmailSendConfig": {
"Port": 587,
"Host": "smtp-mail.outlook.com",
"FromEmail": "donotreply@elevateimaging.ai",
"FromName": "LiLi",
"AuthorizationCode": "Q#669869497420ul",
"OrganizationName": "Elevate Imaging",
"OrganizationNameCN": "Elevate Imaging",
"CompanyName": "Elevate Imaging Inc.",
"CompanyNameCN": "上海展影医疗科技有限公司",
"CompanyShortName": "Elevate Imaging",
"CompanyShortNameCN": "展影医疗",
"SiteUrl": "https://lili.elevateimaging.ai/login",
"IsEnv_US": true,
"IsOpenErrorNoticeEmail": true,
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
},
"SystemPacsConfig": {
"Port": "104",
"IP": "44.210.231.169"
}
}

View File

@ -1,95 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"ObjectStoreService": {
"ObjectStoreUse": "AWS",
"MinIO": {
//"endPoint": "hir-oss.uat.extimaging.com",
//"port": "443",
//"useSSL": true,
//"viewEndpoint": "https://hir-oss.uat.extimaging.com/hir-uat",
"endPoint": "47.117.164.182",
"port": "9001",
"useSSL": false,
"viewEndpoint": "http://47.117.164.182:9001/test-irc-us",
"accessKey": "b9Ul0e98xPzt6PwRXA1Q",
"secretKey": "DzMaU2L4OXl90uytwOmDXF2encN0Jf4Nxu2XkYqQ",
"bucketName": "test-irc-us"
},
"AWS": {
"Region": "us-east-1",
"EndPoint": "s3.us-east-1.amazonaws.com",
"UseSSL": true,
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
"SecretAccessKey": "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",
"BucketName": "ei-med-s3-lili-uat-store",
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com",
"DurationSeconds": 7200
}
},
"BasicSystemConfig": {
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": true,
"OpenTrialRelationDelete": true,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 60,
"ContinuousReadingTimeMin": 120,
"ReadingRestTimeMin": 10,
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90,
"OpenLoginMFA": true
},
"SystemEmailSendConfig": {
"Port": 587,
"Host": "smtp-mail.outlook.com",
"FromEmail": "donotreply@elevateimaging.ai",
"FromName": "LiLi",
"AuthorizationCode": "Q#669869497420ul",
"OrganizationName": "Elevate Imaging",
"OrganizationNameCN": "Elevate Imaging",
"CompanyName": "Elevate Imaging Inc.",
"CompanyNameCN": "上海展影医疗科技有限公司",
"CompanyShortName": "Elevate Imaging",
"CompanyShortNameCN": "展影医疗",
"SiteUrl": "https://lili.test.elevateimaging.ai/login",
"IsEnv_US": true,
"IsOpenErrorNoticeEmail": false,
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
},
"SystemPacsConfig": {
"Port": "104",
"IP": "3.226.182.187"
}
}

View File

@ -1,99 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
//"RemoteNew": "Server=us-mssql-service,1433;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
//"Hangfire": "Server=us-mssql-service,1433;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
"RemoteNew": "Server=3.226.182.187,1435;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=3.226.182.187,1435;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"ObjectStoreService": {
"ObjectStoreUse": "AWS",
"MinIO": {
//"endPoint": "hir-minio.uat.elevateimaging.ai",
//"port": "443",
//"useSSL": true,
//"viewEndpoint": "https://hir-minio.uat.elevateimaging.ai/uat-irc-us",
"endPoint": "3.226.182.187",
"port": "9001",
"useSSL": false,
"viewEndpoint": "http://44.218.11.19:9001/uat-irc-us",
"accessKey": "lH8DkKskLuDqPaiubuSQ",
"secretKey": "pdPdicvvLeH7xAC5yFUrI7odMyBfOXxvVWMvKYV4",
"bucketName": "uat-irc-us"
},
"AWS": {
"Region": "us-east-1",
"EndPoint": "s3.us-east-1.amazonaws.com",
"UseSSL": true,
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
"SecretAccessKey": "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",
"BucketName": "ei-med-s3-lili-uat-store",
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com",
"DurationSeconds": 7200
}
},
"BasicSystemConfig": {
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": true,
"OpenTrialRelationDelete": true,
"OpenLoginLimit": false,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 60,
"ContinuousReadingTimeMin": 120,
"ReadingRestTimeMin": 10,
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90,
"OpenLoginMFA": false
},
"SystemEmailSendConfig": {
"Port": 587,
"Host": "smtp-mail.outlook.com",
"FromEmail": "donotreply@elevateimaging.ai",
"FromName": "LiLi",
"AuthorizationCode": "Q#669869497420ul",
"OrganizationName": "Elevate Imaging",
"OrganizationNameCN": "Elevate Imaging",
"CompanyName": "Elevate Imaging Inc.",
"CompanyNameCN": "上海展影医疗科技有限公司",
"CompanyShortName": "Elevate Imaging",
"CompanyShortNameCN": "展影医疗",
"SiteUrl": "https://lili.test.elevateimaging.ai/login",
"IsEnv_US": true,
"IsOpenErrorNoticeEmail": false,
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
},
"SystemPacsConfig": {
"Port": "104",
"IP": "3.226.182.187"
}
}

View File

@ -0,0 +1,62 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ObjectStoreService": {
"ObjectStoreUse": "MinIO",
"MinIO": {
"EndPoint": "hir-oss.uat.extimaging.com",
"Port": "443",
"UseSSL": true,
//"endPoint": "106.14.89.110",
//"port": "9001",
//"useSSL": false,
"AccessKeyId": "L6owzRVeDJJw3PcRmK2c",
"SecretAccessKey": "2XvFDYSH7EyHQNtpDCgk4efgdsdarQmRKgx1LlOI",
"BucketName": "hir-uat",
"ViewEndpoint": "https://hir-oss.uat.extimaging.com/hir-uat"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=101.132.253.119,1435;Database=Uat_HIR_New;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=101.132.253.119,1435;Database=Uat_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"BasicSystemConfig": {
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": false,
"OpenTrialRelationDelete": false,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 120,
"AESKey": "HIR_System_AES_Key_Info",
"CmoveIntervalMinutes": 1,
"CmoveInstanceIntervalMinutes": 1
},
"SystemHospitalConfig": {
"HospitalCode": "EI",
"HospitalLogoPath": "/System/GeneralDocuments/1716453306898_图片2.png",
"TrialKeepCount": 60,
"HospitalName": "上海展影医疗科技有限公司",
"HospitalAliasName": "展影医疗",
"Country": "中国",
"City": "上海",
"Province": "上海",
"Address": "上海市杨浦区国泰路复旦科技园",
"Phone": "021-60702575",
"IsCanConnectInternet": false
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "test-study@extimaging.com",
"FromName": "Test_HIR",
"AuthorizationCode": "zhanying123",
"SiteUrl": "http://hir.test.extimaging.com/login"
}
}

View File

@ -1,100 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
"RemoteNew": "Server=47.117.164.182,1434;Database=Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=47.117.164.182,1434;Database=Uat_IRC.Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"ObjectStoreService": {
"ObjectStoreUse": "AliyunOSS",
"AliyunOSS": {
"RegionId": "cn-shanghai",
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
"AccessKeyId": "LTAI5tRRZehUp2V9pyTPtAJm",
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
"BucketName": "zy-irc-uat-store",
"ViewEndpoint": "https://zy-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
"Region": "oss-cn-shanghai",
"DurationSeconds": 7200
},
"MinIO": {
"endPoint": "hir-oss.uat.extimaging.com",
"port": "80",
"useSSL": false,
"viewEndpoint": "http://hir-oss.uat.extimaging.com/irc-uat",
//"port": "443",
//"useSSL": true,
//"viewEndpoint": "https://hir-oss.uat.extimaging.com/irc-uat",
"accessKey": "b9Ul0e98xPzt6PwRXA1Q",
"secretKey": "DzMaU2L4OXl90uytwOmDXF2encN0Jf4Nxu2XkYqQ",
"bucketName": "irc-uat"
},
"AWS": {
"Region": "us-east-1",
"EndPoint": "s3.us-east-1.amazonaws.com",
"UseSSL": true,
"RoleArn": "arn:aws:iam::471112624751:role/sts_s3_upload",
"AccessKeyId": "AKIAW3MEAFJXWRCGSX5Z",
"SecretAccessKey": "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",
"BucketName": "ei-med-s3-lili-uat-store",
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com/",
"DurationSeconds": 7200
}
},
"BasicSystemConfig": {
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": true,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 60,
"OpenLoginMFA": false,
"ContinuousReadingTimeMin": 120,
"ReadingRestTimeMin": 10,
"IsNeedChangePassWord": true,
"ChangePassWordDays": 90
},
"SystemEmailSendConfig": {
"Port": 465,
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "uat@extimaging.com",
"FromName": "UAT_IRC",
"AuthorizationCode": "SHzyyl2021",
"SiteUrl": "http://irc.uat.extimaging.com/login",
"OrganizationName": "Extlmaging",
"OrganizationNameCN": "Extlmaging",
"CompanyName": "Extensive Imaging",
"CompanyNameCN": "上海展影医疗科技有限公司",
"CompanyShortName": "Extensive Imaging",
"CompanyShortNameCN": "展影医疗",
"IsEnv_US": false,
"IsOpenErrorNoticeEmail": false,
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
},
"SystemPacsConfig": {
"Port": "11113",
"IP": "47.117.164.182"
}
}

View File

@ -50,7 +50,7 @@ public class EncryptionRequestMiddleware
{
try
{
var decryptedSegment = AesEncryption.Decrypt(pathSegments[i], decryptedSymmetricKey);
var decryptedSegment = Infrastructure.Encryption.AesEncryption.Decrypt(pathSegments[i], decryptedSymmetricKey);
pathSegments[i] = decryptedSegment;
}
catch
@ -74,7 +74,7 @@ public class EncryptionRequestMiddleware
foreach (var param in queryParams)
{
var encryptedValue = param.Value;
var decryptedValue = AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
var decryptedValue = Infrastructure.Encryption.AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
decryptedQueryParams[param.Key] = decryptedValue;
}
@ -104,7 +104,7 @@ public class EncryptionRequestMiddleware
foreach (var property in encryptedJson.Properties())
{
var encryptedValue = property.Value.ToString();
var decryptedValue = AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
var decryptedValue = Infrastructure.Encryption.AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
decryptedJson[property.Name] = decryptedValue;
}

View File

@ -1,8 +1,12 @@
using IRaCIS.Core.Application.BusinessFilter;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.BusinessFilter;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Infrastructure.Encryption;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
@ -13,7 +17,10 @@ using static IRaCIS.Core.Domain.Share.StaticData;
namespace IRaCIS.Core.Application.Filter;
public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _userInfo, IRepository<Trial> _trialRepository) : IAsyncActionFilter
public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _userInfo, IRepository<Trial> _trialRepository,
IOptionsMonitor<ServiceVerifyConfigOption> _basicSystemConfigConfig,
IRepository<HIRHospital> _hirHospitalRepository,
IStringLocalizer _localizer) : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
@ -113,9 +120,9 @@ public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _
trialIdStr = matchResult.Value;
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
var trialInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), async _ =>await CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
if (string.IsNullOrWhiteSpace(trialStatusStr))
if (string.IsNullOrWhiteSpace(trialInfo?.TrialStatusStr))
{
//数据库 检查该项目Id不对
@ -145,22 +152,83 @@ public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _
//通过path 或者body 找到trialId 了
if (!string.IsNullOrWhiteSpace(trialIdStr))
{
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
var trialInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), async _ => await CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方比如项目配置有的在多种状态初始化ongoing都可以操作有的仅仅在Initializing还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
if (trialStatusStr == StaticData.TrialState.TrialOngoing || optActions.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
var hospitalInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Hospital, async _ => await CacheHelper.GetHospitalCode(_hirHospitalRepository), TimeSpan.FromDays(7));
var trialStatusStr = string.Empty;
if (trialInfo != null)
{
trialStatusStr = trialInfo.TrialStatusStr;
await next();
var activationCode = trialInfo.AuthorizationEncrypt;
if (string.IsNullOrEmpty(activationCode))
{
//context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["项目未进行授权之前,不能进行操作"]));
}
else
{
var decodedText = string.Empty;
try
{
//解析加密信息
decodedText = AesEncryption.Decrypt(activationCode, _basicSystemConfigConfig.CurrentValue.AESKey, "Trial_AuthorizationEncrypt");
}
catch (Exception)
{
//该授权码与该项目不匹配(无法解密)
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialGlobalLimit_AuthorizationCodeError"]));
return;
}
var hospitalCode = hospitalInfo.HospitalCode;
var authInfo = JsonConvert.DeserializeObject<TrialAuthorizationInfo>(decodedText);
if (authInfo != null)
{
if (authInfo.TrialCode != trialInfo.TrialCode || authInfo.CreateUserId != trialInfo.CreateUserId || authInfo.TrialId != trialInfo.TrialId
|| authInfo.HospitalCode != hospitalCode || trialInfo.CriterionTypeList.Except(authInfo.CriterionTypeList).Count() != 0)
{
// 您的操作被禁止,系统检测到该项目授权码与该项目授权配置信息不一致,请还原项目授权配置信息!
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialGlobalLimit_AuthorizationCodeInfoError"]));
return;
}
if (DateTime.Now > authInfo.AuthorizationDeadLineDate.Value.AddDays(15))
{
//当前时间已经超过项目授权截止时间半个月,请重新获取项目授权后再进行操作!
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialGlobalLimit_AuthorizationCodeAfterDeadLine15Days"]));
return;
}
}
else
{
//context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["该授权码与该项目不匹配"]));
}
}
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方比如项目配置有的在多种状态初始化ongoing都可以操作有的仅仅在Initializing还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
if (trialStatusStr == StaticData.TrialState.TrialOngoing || optActions.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
{
await next();
}
// 项目停止、或者完成 不允许操作
else
{
//---本次请求被配置规则拦截:项目状态处于进行中时,才允许操作,若此处逻辑有误,请联系开发人员修改
context.Result = new JsonResult(ResponseOutput.NotOk(I18n.T("TrialResource_InterceptedProjectStatusRule")));
}
}
// 项目停止、或者完成 不允许操作
else
{
//---本次请求被配置规则拦截:项目状态处于进行中时,才允许操作,若此处逻辑有误,请联系开发人员修改
context.Result = new JsonResult(ResponseOutput.NotOk(I18n.T("TrialResource_InterceptedProjectStatusRule")));
}
}
//添加项目 签名系统文档的时候 不做拦截 但是更新项目 签名项目文档的时候需要拦截

View File

@ -1,196 +0,0 @@
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Localization;
using System.Text.RegularExpressions;
using ZiggyCreatures.Caching.Fusion;
using static IRaCIS.Core.Domain.Share.StaticData;
namespace IRaCIS.Core.Application.Filter;
/// <summary>
/// 主要为了 处理项目结束 锁库,不允许操作
/// </summary>
public class TrialResourceFilter : Attribute, IAsyncResourceFilter
{
private readonly IUserInfo _userInfo;
private readonly IFusionCache _fusionCache;
public IStringLocalizer _localizer;
private readonly IRepository<Trial> _trialRepository;
private readonly List<string> _trialOptList = new List<string>();
public TrialResourceFilter(IFusionCache fusionCache, IRepository<Trial> trialRepository, IStringLocalizer localizer, IUserInfo userInfo, string trialOpt = null, string trialOpt2 = null, string trialOpt3 = null)
{
_fusionCache = fusionCache;
_userInfo = userInfo;
_localizer = localizer;
_trialRepository = trialRepository;
if (!string.IsNullOrWhiteSpace(trialOpt)) _trialOptList.Add(trialOpt.Trim());
if (!string.IsNullOrWhiteSpace(trialOpt2)) _trialOptList.Add(trialOpt2.Trim());
if (!string.IsNullOrWhiteSpace(trialOpt3)) _trialOptList.Add(trialOpt3.Trim());
}
//优先选择异步的方法
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
{
// var typeFilter = context.ActionDescriptor.EndpointMetadata.Where(t => t.GetType() == typeof(TypeFilterAttribute)).Select(t => (TypeFilterAttribute)t).ToList().FirstOrDefault();
//var _trialOptList= typeFilter.Arguments.Select(t => t.ToString()).ToList();
// 获取当前请求的 Host 信息
var requestHost = context.HttpContext.Request.Host;
// 检查请求是否来自 localhost:6100
if (requestHost.Host == "localhost" && (requestHost.Port == 6100|| requestHost.Port==3305))
{
await next.Invoke();
return;
}
#region 处理新的用户类型,不能操作项目相关接口
// 后期列举出具体的类型,其他任何用户类型,都不允许操作
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA && _userInfo.RequestUrl.ToLower() != "TrialDocument/userConfirm".ToLower())
{
//---对不起,您的账户没有操作权限。
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_NoAccessPermission"]));
return;
}
#endregion
//TrialId 传递的途径多种可能在path 可能在body 可能在数组中也可能在对象中可能就在url
var trialIdStr = string.Empty;
if (!string.IsNullOrWhiteSpace(context.HttpContext.Request.Query["trialId"]))
{
trialIdStr = context.HttpContext.Request.Query["trialId"];
}
//先尝试从path中取TrialId
else if (context.RouteData.Values.Keys.Any(t => t.Contains("trialId")))
{
var index = context.RouteData.Values.Keys.ToList().IndexOf("trialId");
trialIdStr = context.RouteData.Values.Values.ToList()[index] as string;
}
else if (context.HttpContext.Request.Headers["Referer"].ToString().Contains("trialId"))
{
var headerStr = context.HttpContext.Request.Headers["Referer"].ToString();
var trialIdIndex = headerStr.IndexOf("trialId");
var matchResult = Regex.Match(headerStr.Substring(trialIdIndex), @"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}");
if (matchResult.Success)
{
trialIdStr = matchResult.Value;
}
else
{
//---正则取请求Refer 中trialId 失败,请联系开发人员核查
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_ReferTrialIdFailed"]));
}
}
else
{
#region body 中取数据
//设置可以多次读
context.HttpContext.Request.EnableBuffering();
var reader = new StreamReader(context.HttpContext.Request.Body);
var contentFromBody = await reader.ReadToEndAsync();
//读取后,流的位置还原
context.HttpContext.Request.Body.Seek(0, SeekOrigin.Begin);
//context.HttpContext.Request.Body.Position = 0;
//找到参数位置在字符串中的索引
var trialIdIndex = contentFromBody.IndexOf("\"TrialId\"", StringComparison.OrdinalIgnoreCase);
if (trialIdIndex > -1)
{
// (?<="trialId" *: *").*?(?=",)
//使用正则 [0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}
var matchResult = Regex.Match(contentFromBody.Substring(trialIdIndex), @"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}");
if (matchResult.Success)
{
//有可能匹配错误 "trialId":"","documentId":"b8180000-3e2c-0016-9fe0-08da33f96236" 从缓存里面验证下
trialIdStr = matchResult.Value;
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
if (string.IsNullOrWhiteSpace(trialStatusStr))
{
//数据库 检查该项目Id不对
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_ReferTrialIdFailed"]));
return;
}
}
else
{
//---正则取请求Refer 中trialId 失败,请联系开发人员核查
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_ReferTrialIdFailed"]));
return;
}
//使用字符串取 如果是swagger 可能有时取的不对 因为空格的原因
//trialIdStr = contentFromBody.Substring(trialIdIndex + "TrialId".Length + 4, 3
}
#endregion
}
//通过path 或者body 找到trialId 了
if (!string.IsNullOrWhiteSpace(trialIdStr))
{
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方比如项目配置有的在多种状态初始化ongoing都可以操作有的仅仅在Initializing还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
if (trialStatusStr == StaticData.TrialState.TrialOngoing || _trialOptList.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
{
await next.Invoke();
}
// 项目停止、或者完成 不允许操作
else
{
//---本次请求被配置规则拦截:项目状态处于进行中时,才允许操作,若此处逻辑有误,请联系开发人员修改
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_InterceptedProjectStatusRule"]));
}
}
//添加项目 签名系统文档的时候 不做拦截 但是更新项目 签名项目文档的时候需要拦截
else if (_trialOptList.Any(t => t == TrialOpt.AddOrUpdateTrial || t == TrialOpt.SignSystemDocNoTrialId))
{
await next.Invoke();
}
else
{
//如果项目相关接口没有传递trialId 会来到这里,提醒,以便修改
//---该接口参数中,没有传递项目编号,请核对。
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_MissingProjectNumber"]));
}
}
}

View File

@ -1,6 +1,10 @@
using IRaCIS.Core.Application.Helper;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Infrastructure.Encryption;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
@ -24,7 +28,10 @@ public class TrialGlobalLimitAttribute : Attribute
public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo _userInfo, IRepository<Trial> _trialRepository) : IEndpointFilter
public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo _userInfo, IRepository<Trial> _trialRepository,
IOptionsMonitor<ServiceVerifyConfigOption> _basicSystemConfigConfig,
IRepository<HIRHospital> _hirHospitalRepository,
IStringLocalizer _localizer) : IEndpointFilter
{
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
@ -121,9 +128,9 @@ public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo
trialIdStr = matchResult.Value;
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
var trialInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), async _ => await CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
if (string.IsNullOrWhiteSpace(trialStatusStr))
if (string.IsNullOrWhiteSpace(trialInfo?.TrialStatusStr))
{
//数据库 检查该项目Id不对
@ -151,22 +158,81 @@ public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo
//通过path 或者body 找到trialId 了
if (!string.IsNullOrWhiteSpace(trialIdStr))
{
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
var trialInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), async _ => await CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方比如项目配置有的在多种状态初始化ongoing都可以操作有的仅仅在Initializing还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
if (trialStatusStr == StaticData.TrialState.TrialOngoing || optActions.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
var hospitalInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Hospital, async _ => await CacheHelper.GetHospitalCode(_hirHospitalRepository), TimeSpan.FromDays(7));
var trialStatusStr = string.Empty;
if (trialInfo != null)
{
trialStatusStr = trialInfo.TrialStatusStr;
return await next(context);
var activationCode = trialInfo.AuthorizationEncrypt;
if (string.IsNullOrEmpty(activationCode))
{
//context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["项目未进行授权之前,不能进行操作"]));
}
else
{
var decodedText = string.Empty;
try
{
//解析加密信息
decodedText = AesEncryption.Decrypt(activationCode, _basicSystemConfigConfig.CurrentValue.AESKey, "Trial_AuthorizationEncrypt");
}
catch (Exception)
{
return Results.Json(ResponseOutput.NotOk(_localizer["该授权码与该项目不匹配"]));
}
var hospitalCode = hospitalInfo.HospitalCode;
var authInfo = JsonConvert.DeserializeObject<TrialAuthorizationInfo>(decodedText);
if (authInfo != null)
{
if (authInfo.TrialCode != trialInfo.TrialCode || authInfo.CreateUserId != trialInfo.CreateUserId || authInfo.TrialId != trialInfo.TrialId
|| authInfo.HospitalCode != hospitalCode || trialInfo.CriterionTypeList.Except(authInfo.CriterionTypeList).Count() != 0)
{
return Results.Json(ResponseOutput.NotOk(_localizer["您的操作被禁止,系统检测到该项目授权码与该项目授权配置信息不一致,请还原项目授权配置信息!"]));
}
if (DateTime.Now > authInfo.AuthorizationDeadLineDate.Value.AddDays(15))
{
return Results.Json(ResponseOutput.NotOk(_localizer["当前时间已经超过项目授权截止时间半个月,请重新获取项目授权后再进行操作!"]));
}
}
else
{
//context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["该授权码与该项目不匹配"]));
}
}
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方比如项目配置有的在多种状态初始化ongoing都可以操作有的仅仅在Initializing还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
if (trialStatusStr == StaticData.TrialState.TrialOngoing || optActions.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
{
return await next(context);
}
// 项目停止、或者完成 不允许操作
else
{
//---本次请求被配置规则拦截:项目状态处于进行中时,才允许操作,若此处逻辑有误,请联系开发人员修改
return Results.Json(ResponseOutput.NotOk(I18n.T("TrialResource_InterceptedProjectStatusRule")));
}
}
// 项目停止、或者完成 不允许操作
else
{
//---本次请求被配置规则拦截:项目状态处于进行中时,才允许操作,若此处逻辑有误,请联系开发人员修改
return Results.Json(ResponseOutput.NotOk(I18n.T("TrialResource_InterceptedProjectStatusRule")));
}
}
//添加项目 签名系统文档的时候 不做拦截 但是更新项目 签名项目文档的时候需要拦截

View File

@ -36,6 +36,13 @@ public class ServiceVerifyConfigOption
public string ThirdPdfUrl { get; set; }
public string AESKey { get; set; }
public int CmoveIntervalMinutes { get; set; }
public int CmoveInstanceIntervalMinutes { get; set; }
}
public class SystemEmailSendConfig
@ -66,7 +73,7 @@ public class SystemEmailSendConfig
public bool IsOpenErrorNoticeEmail { get; set; }
public List<string> ErrorNoticeEmailList { get; set; } =new List<string>();
public List<string> ErrorNoticeEmailList { get; set; } = new List<string>();
}
public class SystemEmailSendConfigView

View File

@ -1,4 +1,7 @@
namespace IRaCIS.Core.Application.Helper;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.ViewModel;
namespace IRaCIS.Core.Application.Helper;
public static class CacheKeys
@ -56,13 +59,19 @@ public static class CacheKeys
/// <returns></returns>
public static string StartRestTime(Guid userId) => $"{userId}StartRestTime";
public static string CmoveStudyId(string studyIdStr) => $"CmoveStudyId:{studyIdStr}";
public static string Hospital => $"Hospital";
}
public static class CacheHelper
{
public static async Task<string?> GetTrialStatusAsync(Guid trialId, IRepository<Trial> _trialRepository)
public static async Task<TrialCacheInfo> GetTrialStatusAsync(Guid trialId, IRepository<Trial> _trialRepository)
{
var statusStr = await _trialRepository.Where(t => t.Id == trialId, ignoreQueryFilters: true).Select(t => t.TrialStatusStr).FirstOrDefaultAsync();
var statusStr = await _trialRepository.Where(t => t.Id == trialId, ignoreQueryFilters: true).Select(t => new TrialCacheInfo { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr, CriterionTypes = t.CriterionTypes, AuthorizationEncrypt = t.AuthorizationEncrypt, AuthorizationDate = t.AuthorizationDate, CreateUserId = t.CreateUserId, TrialCode = t.TrialCode })
.FirstOrDefaultAsync();
return statusStr;
}
@ -73,4 +82,10 @@ public static class CacheHelper
return list;
}
public static async Task<HIRHospital?> GetHospitalCode(IRepository<HIRHospital> _hirHospitalRepository)
{
return await _hirHospitalRepository.Where(t => t.IsDefault == true).FirstOrDefaultAsync();
}
}

View File

@ -64,7 +64,7 @@ public static class ExcelExportHelper
foreach (var key in dic.Keys)
{
//是数组 那么找到对应的属性 进行翻译
if (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>();
@ -165,7 +165,7 @@ public static class ExcelExportHelper
}
//中文替换项目术语
if (isEn_US == false && data.TrialObjectNameList.Count > 0)
if (data.TrialObjectNameList?.Count > 0)
{
var replaceObjectList = data.TrialObjectNameList;
@ -176,24 +176,30 @@ public static class ExcelExportHelper
for (int rowIndex = 0; rowIndex < rowCount; rowIndex++)
{
var row = sheet.GetRow(rowIndex);
var colums = row.LastCellNum;
for (int colIndex = 0; colIndex < colums; colIndex++)
if (row != null)
{
var cell = row.GetCell(colIndex);
// 只处理字符串类型的单元格
if (cell != null)
var colums = row.LastCellNum;
for (int colIndex = 0; colIndex < colums; colIndex++)
{
var cellValue = cell.StringCellValue;
var cell = row.GetCell(colIndex);
var find = replaceObjectList.FirstOrDefault(t => t.Name == cellValue);
if (find != null)
// 只处理字符串类型的单元格
if (cell != null)
{
cell.SetCellValue(find.TrialName);
var cellValue = cell.StringCellValue;
var find = replaceObjectList.FirstOrDefault(t => t.Name == cellValue);
if (find != null)
{
cell.SetCellValue(find.TrialName);
}
}
}
}
}
}
@ -316,7 +322,7 @@ public static class ExcelExportHelper
foreach (var key in dic.Keys)
{
//是数组 那么找到对应的属性 进行翻译
if (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<>)))
//if (dic[key].GetType().IsAssignableFrom(typeof(JArray)))
{
@ -415,7 +421,7 @@ public static class ExcelExportHelper
}
//中文替换项目术语
if (isEn_US == false && data.TrialObjectNameList.Count > 0)
if (data.TrialObjectNameList?.Count > 0)
{
var replaceObjectList = data.TrialObjectNameList;
@ -426,21 +432,25 @@ public static class ExcelExportHelper
for (int rowIndex = 0; rowIndex < rowCount; rowIndex++)
{
var row = sheet.GetRow(rowIndex);
var colums = row.LastCellNum;
for (int colIndex = 0; colIndex < colums; colIndex++)
if (row != null)
{
var cell = row.GetCell(colIndex);
// 只处理字符串类型的单元格
if (cell != null)
var colums = row.LastCellNum;
for (int colIndex = 0; colIndex < colums; colIndex++)
{
var cellValue = cell.StringCellValue;
var cell = row.GetCell(colIndex);
var find = replaceObjectList.FirstOrDefault(t => t.Name == cellValue);
if (find != null)
// 只处理字符串类型的单元格
if (cell != null)
{
cell.SetCellValue(find.TrialName);
var cellValue = cell.StringCellValue;
var find = replaceObjectList.FirstOrDefault(t => t.Name == cellValue);
if (find != null)
{
cell.SetCellValue(find.TrialName);
}
}
}
}

View File

@ -12,6 +12,8 @@ using MassTransit;
using Microsoft.Extensions.Options;
using Minio;
using Minio.DataModel.Args;
using Newtonsoft.Json;
using System.Net;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
@ -20,9 +22,19 @@ namespace IRaCIS.Core.Application.Helper;
#region 绑定和返回模型
[LowerCamelCaseJson]
public class MinIOOptions : AWSOptions
public class MinIOOptions
{
public int Port { get; set; }
public string EndPoint { get; set; }
public bool UseSSL { get; set; }
[JsonProperty("accessKey")]
public string AccessKeyId { get; set; }
[JsonProperty("secretKey")]
public string SecretAccessKey { get; set; }
public string BucketName { get; set; }
public string ViewEndpoint { get; set; }
}
@ -31,13 +43,19 @@ public class AWSOptions
{
public string EndPoint { get; set; }
public bool UseSSL { get; set; }
[JsonProperty("AccessKey")]
public string AccessKeyId { get; set; }
public string RoleArn { get; set; }
[JsonProperty("SecretKey")]
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 string viewEndpoint { get; set; }
}
public class AliyunOSSOptions
@ -205,11 +223,17 @@ public class OSSService : IOSSService
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
{
var httpClientHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};
var minIOConfig = ObjectStoreServiceOptions.MinIO;
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
.WithHttpClient(new HttpClient(httpClientHandler))
.Build();
var putObjectArgs = new PutObjectArgs()
@ -296,11 +320,18 @@ public class OSSService : IOSSService
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
{
var httpClientHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};
var minIOConfig = ObjectStoreServiceOptions.MinIO;
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
.WithHttpClient(new HttpClient(httpClientHandler))
.Build();
var putObjectArgs = new PutObjectArgs()
@ -373,12 +404,20 @@ public class OSSService : IOSSService
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
{
var httpClientHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};
var minIOConfig = ObjectStoreServiceOptions.MinIO;
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
.WithHttpClient(new HttpClient(httpClientHandler))
.Build();
var getObjectArgs = new GetObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(ossRelativePath)

View File

@ -54,7 +54,7 @@
<PackageReference Include="MimeKit" Version="4.7.1" />
<PackageReference Include="MiniExcel" Version="1.34.2" />
<PackageReference Include="Minio" Version="6.0.3" />
<PackageReference Include="MiniWord" Version="0.8.0" />
<PackageReference Include="MiniWord" Version="0.9.2" />
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
// 生成时间 2022-06-07 14:10:54
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Domain.Share;
using Newtonsoft.Json;
using System.ComponentModel.DataAnnotations;
@ -10,8 +11,108 @@ using System.ComponentModel.DataAnnotations;
namespace IRaCIS.Core.Application.ViewModel
{
public class PIReaingTaskView : ReadingTaskView
{
public Guid? FirstAuditUserId { get; set; }
public string FirstAuditUserName { get; set; }
public DateTime? FirstAuditTime { get; set; }
public Guid? LatestReplyUserId { get; set; }
public string LatestReplyUserName { get; set; }
public DateTime? LatestReplyTime { get; set; }
}
public class PIAuditTaskEnrollOrPdCommand
{
[NotDefault]
public Guid VisitTaskId { get; set; }
public bool? IsEnrollment { get; set; }
public bool? IsPDConfirm { get; set; }
}
public class PIAuditTaskCommand
{
[NotDefault]
public Guid VisitTaskId { get; set; }
public string NotAgreeReason { get; set; }
public string PIAuditNote { get; set; } = string.Empty;
public List<string> PIAuditImagePathList { get; set; }
public PIAuditState PIAuditState { get; set; }
}
public class PIAuditTaskReplyCommand
{
[NotDefault]
public Guid VisitTaskId { get; set; }
public string ReplyContent { get; set; } = string.Empty;
}
public class ClinicalDataDialog
{
public Guid Id { get; set; }
public DateTime CreateTime { get; set; }
public string Content { get; set; }
}
public class PIAuditDialogQuery
{
[NotDefault]
public Guid VisitTaskId { get; set; }
}
public class PIAuditDialogListView
{
public Guid VisitTaskId { get; set; }
public string NotAgreeReason { get; set; }
public string PIAuditNote { get; set; } = string.Empty;
public List<string> PIAuditImagePathList { get; set; }
public PIAuditState? PIAuditState { get; set; }
public string ReplyContent { get; set; } = string.Empty;
public bool? IsEnrollment { get; set; }
public bool? IsPDConfirm { get; set; }
public bool IsCurrentUser { get; set; }
public Guid CreateUserId { get; set; }
public string CreateUserName { get; set; }
public DateTime CreateTime { get; set; }
public UserTypeEnum UserTypeEnum { get; set; }
}
public class PIReadingResult
{
public Guid QuestionId { get; set; }
public string Answer { get; set; }
}
public class VisitTaskViewBasic
{
public Guid? SourceSubjectVisitId { get; set; }
public string SubjectShortName { get; set; }
public Guid Id { get; set; }
public Guid TrialId { get; set; }
@ -214,6 +315,12 @@ namespace IRaCIS.Core.Application.ViewModel
/// </summary>
public bool IsManualGeneration { get; set; }
//public bool IsAfterConvertedTask { get; set; }
public List<PIReadingResult> PIReadingResultList { get; set; }
public List<PatientBasicInfo> PatientList { get; set; }
}
@ -284,10 +391,26 @@ namespace IRaCIS.Core.Application.ViewModel
public ReReadingApplyState ReReadingApplyState { get; set; }
public DateTime? SuggesteFinishedTime { get; set; }
#region HIR
public List<PatientBasicInfo> PatientList { get; set; }
#endregion
}
public class IRUnReadSubjectView
{
#region HIR
public Guid? ClaimUserId { get; set; }
public string? ClaimUserName { get; set; }
public string SubjectName { get; set; }
public List<PatientBasicInfo> PatientList { get; set; }
#endregion
public int Index { get; set; } = 0;
public Guid SubjectId { get; set; }
@ -399,10 +522,23 @@ namespace IRaCIS.Core.Application.ViewModel
public string? SubjectCode { get; set; } = null;
public string? SubjectName { get; set; }
public string? PatientName { get; set; }
public string? PatientIdStr { get; set; }
}
public class VisitTaskQuery : PageInput
{
#region HIR
public DateTime? BeginSignDate { get; set; }
public DateTime? EndSignDate { get; set; }
public string? SubjectName { get; set; }
#endregion
[NotDefault]
public Guid TrialId { get; set; }
@ -465,6 +601,33 @@ namespace IRaCIS.Core.Application.ViewModel
public string? RequestReReadingReason { get; set; }
public ExportResult? ReadingExportType { get; set; }
#region HIR
public PIAuditState? PIAuditState { get; set; }
public string? FirstAuditUserName { get; set; }
public bool? IsWaitPIAudit { get; set; }
public string? LatestReplyUserName { get; set; }
public DateTime? FirstAuditTimeBegin { get; set; }
public DateTime? FirstAuditTimeEnd { get; set; }
public DateTime? LatestReplyTimeBegin { get; set; }
public DateTime? LatestReplyTimeEnd { get; set; }
public string? PatientName { get; set; }
public string? PatientIdStr { get; set; }
public string? PatientSex { get; set; }
#endregion
}
@ -486,6 +649,10 @@ namespace IRaCIS.Core.Application.ViewModel
public class IRUnReadSubjectQuery : PageInput
{
public string? PatientName { get; set; }
public string? PatientIdStr { get; set; }
public string? SubjectName { get; set; }
public Guid TrialId { get; set; }
public string SubjectCode { get; set; }
@ -837,6 +1004,8 @@ namespace IRaCIS.Core.Application.ViewModel
[NotDefault]
public Guid TrialReadingCriterionId { get; set; }
public Guid? VisitTaskId { get; set; }
}

View File

@ -336,7 +336,10 @@ namespace IRaCIS.Core.Application.Service
ReadingCategory = ReadingCategory.Visit,
TrialReadingCriterionId = trialReadingCriterionConfig.TrialReadingCriterionId,
IsNeedClinicalDataSign = isNeedClinicalDataSign,
IsClinicalDataSign = isClinicalDataSign
IsClinicalDataSign = isClinicalDataSign,
//HIR
SuggesteFinishedTime = GetSuggessFinishTime(true, UrgentType.NotUrget)
});
}
@ -1065,7 +1068,10 @@ namespace IRaCIS.Core.Application.Service
TrialReadingCriterionId = trialReadingCriterionConfig.TrialReadingCriterionId,
IsNeedClinicalDataSign = isNeedClinicalDataSign,
IsClinicalDataSign = isClinicalDataSign,
IsFrontTaskNeedSignButNotSign = isFrontTaskNeedSignButNotSign
IsFrontTaskNeedSignButNotSign = isFrontTaskNeedSignButNotSign,
//HIR
SuggesteFinishedTime = GetSuggessFinishTime(true, UrgentType.NotUrget)
});

View File

@ -8,14 +8,17 @@ using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Domain.Share.Reading;
using IRaCIS.Core.Infra.EFCore.Common;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using MassTransit;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System.Linq.Dynamic.Core;
using System.Reactive.Subjects;
using Subject = IRaCIS.Core.Domain.Models.Subject;
namespace IRaCIS.Core.Application.Service.Allocation;
@ -48,10 +51,196 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
IRepository<TaskInfluence> _taskInfluenceRepository,
IRepository<TrialQCQuestionAnswer> _trialQCQuestionAnswerRepository,
ILogger<VisitTaskService> _logger,
IRepository<PIAudit> _PIAuditRepository,
IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository,
IRepository<SubjectCriteriaEvaluationVisitStudyFilter> _subjectCriteriaEvaluationVisitStudyFilterRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IVisitTaskService
{
#region HIR PI 相关接口
private IQueryable<VisitTask> GetReadingTaskQueryable(VisitTaskQuery inQuery)
{
var trialConfig = _trialRepository.Where(t => t.Id == inQuery.TrialId).Select(t => new { t.EnrollConfirmDefaultUserType, t.PDProgressDefaultUserType }).FirstOrDefault();
var visitTaskQueryable = _visitTaskRepository.Where(t => t.TrialId == inQuery.TrialId && t.IsAnalysisCreate == false)
.WhereIf(inQuery.TaskState != null, t => t.TaskState == inQuery.TaskState)
.WhereIf(inQuery.TrialSiteId != null, t => t.Subject.TrialSiteId == inQuery.TrialSiteId)
.WhereIf(inQuery.SubjectId != null, t => t.SubjectId == inQuery.SubjectId)
.WhereIf(inQuery.IsUrgent != null, t => t.IsUrgent == inQuery.IsUrgent)
.WhereIf(inQuery.DoctorUserId != null, t => t.DoctorUserId == inQuery.DoctorUserId)
.WhereIf(inQuery.ReadingCategory != null, t => t.ReadingCategory == inQuery.ReadingCategory)
.WhereIf(inQuery.ReadingTaskState != null, t => t.ReadingTaskState == inQuery.ReadingTaskState)
.WhereIf(inQuery.TaskAllocationState != null, t => t.TaskAllocationState == inQuery.TaskAllocationState)
.WhereIf(inQuery.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId)
.WhereIf(inQuery.ReReadingApplyState != null, t => t.ReReadingApplyState == inQuery.ReReadingApplyState)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientIdStr.Contains(inQuery.PatientIdStr)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientName), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientName.Contains(inQuery.PatientName)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientSex), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientSex.Contains(inQuery.PatientSex)))
.WhereIf(inQuery.CompleteClinicalDataEnum == CompleteClinicalDataEnum.Complete, t => t.IsClinicalDataSign && t.IsNeedClinicalDataSign == true)
.WhereIf(inQuery.CompleteClinicalDataEnum == CompleteClinicalDataEnum.NotComplete, t => t.IsClinicalDataSign == false && t.IsNeedClinicalDataSign == true)
.WhereIf(inQuery.CompleteClinicalDataEnum == CompleteClinicalDataEnum.NA, t => t.IsNeedClinicalDataSign == false)
.WhereIf(!string.IsNullOrEmpty(inQuery.TrialSiteCode), t => (t.BlindTrialSiteCode.Contains(inQuery.TrialSiteCode!) && t.IsAnalysisCreate) || (t.Subject.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteCode!) && t.IsAnalysisCreate == false))
.WhereIf(!string.IsNullOrEmpty(inQuery.TaskName), t => t.TaskName.Contains(inQuery.TaskName) || t.TaskBlindName.Contains(inQuery.TaskName))
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => (t.Subject.Code.Contains(inQuery.SubjectCode) && t.IsAnalysisCreate == false) || (t.BlindSubjectCode.Contains(inQuery.SubjectCode) && t.IsAnalysisCreate))
.WhereIf(inQuery.BeginAllocateDate != null, t => t.AllocateTime > inQuery.BeginAllocateDate)
.WhereIf(inQuery.EndAllocateDate != null, t => t.AllocateTime < inQuery.EndAllocateDate!.Value.AddDays(1))
.WhereIf(trialConfig?.EnrollConfirmDefaultUserType == UserTypeEnum.MIM && trialConfig?.PDProgressDefaultUserType != UserTypeEnum.MIM && _userInfo.UserTypeEnumInt == (int)UserTypeEnum.MIM, t => t.SourceSubjectVisit.IsBaseLine == true)
.WhereIf(trialConfig?.EnrollConfirmDefaultUserType != UserTypeEnum.MIM && trialConfig?.PDProgressDefaultUserType == UserTypeEnum.MIM && _userInfo.UserTypeEnumInt == (int)UserTypeEnum.MIM, t => t.SourceSubjectVisit.IsBaseLine == false)
.WhereIf(inQuery.IsWaitPIAudit == true, t => t.FirstAuditUserId == null)
.WhereIf(inQuery.IsWaitPIAudit == false, t => t.FirstAuditUserId != null)
.WhereIf(inQuery.PIAuditState != null, t => t.PIAuditState == inQuery.PIAuditState)
.WhereIf(inQuery.FirstAuditTimeBegin != null, t => t.AllocateTime > inQuery.FirstAuditTimeBegin)
.WhereIf(inQuery.FirstAuditTimeEnd != null, t => t.AllocateTime < inQuery.FirstAuditTimeEnd)
.WhereIf(inQuery.LatestReplyTimeBegin != null, t => t.AllocateTime > inQuery.LatestReplyTimeBegin)
.WhereIf(inQuery.LatestReplyTimeEnd != null, t => t.AllocateTime < inQuery.LatestReplyTimeEnd);
return visitTaskQueryable;
}
[HttpPost]
public async Task<IResponseOutput<PageOutput<PIReaingTaskView>>> GetPIReadingAuditList(VisitTaskQuery queryVisitTask)
{
var visitTaskQueryable = GetReadingTaskQueryable(queryVisitTask)
.ProjectTo<PIReaingTaskView>(_mapper.ConfigurationProvider);
var defalutSortArray = new string[] { nameof(VisitTask.IsUrgent) + " desc", nameof(VisitTask.SubjectId), nameof(VisitTask.VisitTaskNum) };
var pageList = await visitTaskQueryable.ToPagedListAsync(queryVisitTask, defalutSortArray);
var trialTaskConfig = _trialRepository.Where(t => t.Id == queryVisitTask.TrialId).ProjectTo<TrialUrgentConfig>(_mapper.ConfigurationProvider).FirstOrDefault();
var questionList = _readingQuestionTrialRepository.Where(t => t.TrialId == queryVisitTask.TrialId && t.ReadingQuestionCriterionTrialId == queryVisitTask.TrialReadingCriterionId)
.Where(t => t.IsJudgeQuestion == true)
.Select(t => new { QuestionId = t.Id, QuestionName = _userInfo.IsEn_Us ? t.QuestionEnName : t.QuestionName, t.DictionaryCode }).ToList();
trialTaskConfig!.OtherObj = questionList;
return ResponseOutput.Ok(pageList, trialTaskConfig);
}
/// <summary>
///new- 首次审核 后续编辑审核
/// </summary>
/// <param name="incommand"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> PIAuditTask(PIAuditTaskCommand incommand)
{
//需要设置首次审核时间 审核人
var visitTask = await _visitTaskRepository.FirstOrDefaultAsync(t => t.Id == incommand.VisitTaskId);
var isFirstAudit = visitTask.FirstAuditUserId == null;
visitTask.NotAgreeReason = incommand.NotAgreeReason;
visitTask.PIAuditNote = incommand.PIAuditNote;
visitTask.PIAuditImagePath = string.Join('|', incommand.PIAuditImagePathList);
visitTask.PIAuditState = incommand.PIAuditState;
visitTask.LatestReplyUserId = _userInfo.Id;
visitTask.LatestReplyTime = DateTime.Now;
visitTask.IsEnrollment = incommand.PIAuditState == PIAuditState.PINotAgree ? null : visitTask.IsEnrollment;
visitTask.IsPDConfirm = incommand.PIAuditState == PIAuditState.PINotAgree ? null : visitTask.IsPDConfirm;
if (isFirstAudit)
{
visitTask.FirstAuditUserId = _userInfo.Id;
visitTask.FirstAuditTime = DateTime.Now;
}
//发送对话
var addDialig = _mapper.Map<PIAudit>(incommand);
addDialig.PIAuditState = incommand.PIAuditState;
addDialig.PIAuditImagePath = visitTask.PIAuditImagePath;
await _PIAuditRepository.AddAsync(addDialig);
await _visitTaskRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
[HttpPost]
[UnitOfWork]
public async Task<IResponseOutput> PIAuditTaskEnrollOrPD(PIAuditTaskEnrollOrPdCommand incommand, [FromServices] IEmailSendService emailSendService)
{
var visitTask = await _visitTaskRepository.FirstOrDefaultAsync(t => t.Id == incommand.VisitTaskId);
visitTask.IsEnrollment = incommand.IsEnrollment != null ? incommand.IsEnrollment : visitTask.IsEnrollment;
visitTask.IsPDConfirm = incommand.IsPDConfirm != null ? incommand.IsPDConfirm : visitTask.IsPDConfirm;
visitTask.LatestReplyUserId = _userInfo.Id;
visitTask.LatestReplyTime = DateTime.Now;
await _visitTaskRepository.SaveChangesAsync();
//await emailSendService.SendEnrollOrPdEmail(visitTask.Id, incommand.IsEnrollment, incommand.IsPDConfirm);
return ResponseOutput.Ok();
}
/// <summary>
///new- 回复审核内容
/// </summary>
/// <param name="incommand"></param>
/// <returns></returns>
public async Task<IResponseOutput> PIAuditTaskReply(PIAuditTaskReplyCommand incommand)
{
await _PIAuditRepository.AddAsync(new PIAudit() { ReplyContent = incommand.ReplyContent, VisitTaskId = incommand.VisitTaskId });
await _PIAuditRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// new- 获取审核对话列表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<PIAuditDialogListView>> GetPIAuditDialogList(PIAuditDialogQuery inQuery)
{
var list = await _PIAuditRepository.Where(t => t.VisitTaskId == inQuery.VisitTaskId).OrderBy(t => t.CreateTime).ProjectTo<PIAuditDialogListView>(_mapper.ConfigurationProvider).ToListAsync();
foreach (var item in list)
{
item.IsCurrentUser = item.CreateUserId == _userInfo.Id;
}
return list;
}
public async Task<IResponseOutput> AddClinicalDataDialog(Guid visiTaskId, string content,
[FromServices] IRepository<SubjectVisitClinicalDialog> subjectVisitClinicalDialogRepository,
[FromServices] IEmailSendService emailSendService)
{
var taskInfo = await _visitTaskRepository.Where(t => t.Id == visiTaskId).Select(t => new { t.SourceSubjectVisitId, t.Subject.Code, t.SourceSubjectVisit.VisitName, t.Trial.ResearchProgramNo, t.Trial.TrialCode }).FirstOrDefaultAsync();
await subjectVisitClinicalDialogRepository.AddAsync(new SubjectVisitClinicalDialog() { SubjectVisitId = (Guid)taskInfo.SourceSubjectVisitId, Content = content }, true);
await emailSendService.SendClinicalDataQuestionAsync(visiTaskId, content);
return ResponseOutput.Ok();
}
public async Task<List<ClinicalDataDialog>> GetClinicalDataDialog(Guid visiTaskId,
[FromServices] IRepository<SubjectVisitClinicalDialog> _subjectVisitClinicalDialogRepository)
{
var subjectVisitId = await _visitTaskRepository.Where(t => t.Id == visiTaskId).Select(t => t.SourceSubjectVisitId).FirstOrDefaultAsync();
var list = _subjectVisitClinicalDialogRepository.Where(t => t.SubjectVisitId == subjectVisitId).ProjectTo<ClinicalDataDialog>(_mapper.ConfigurationProvider).OrderByDescending(t => t.CreateTime).ToList();
return list;
}
#endregion
/// <summary>
/// 设置任务加急
@ -861,8 +1050,16 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
.WhereIf(!string.IsNullOrEmpty(inQuery.TrialSiteCode), t => (t.OriginalReReadingTask.BlindTrialSiteCode.Contains(inQuery.TrialSiteCode!) && t.OriginalReReadingTask.IsAnalysisCreate) || (t.OriginalReReadingTask.Subject.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteCode!) && t.OriginalReReadingTask.IsAnalysisCreate == false))
.WhereIf(!string.IsNullOrEmpty(inQuery.TaskName), t => t.OriginalReReadingTask.TaskName.Contains(inQuery.TaskName) || t.NewReReadingTask.TaskBlindName.Contains(inQuery.TaskName))
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => (t.OriginalReReadingTask.Subject.Code.Contains(inQuery.SubjectCode) && t.OriginalReReadingTask.IsAnalysisCreate == false) || (t.OriginalReReadingTask.BlindSubjectCode.Contains(inQuery.SubjectCode) && t.OriginalReReadingTask.IsAnalysisCreate))
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectName), t => t.OriginalReReadingTask.Subject.ShortName.Contains(inQuery.SubjectName))
.WhereIf(inQuery.BeginAllocateDate != null, t => t.OriginalReReadingTask.AllocateTime > inQuery.BeginAllocateDate)
.WhereIf(inQuery.EndAllocateDate != null, t => t.OriginalReReadingTask.AllocateTime < inQuery.EndAllocateDate!.Value.AddDays(1))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), t => t.OriginalReReadingTask.Subject.SubjectPatientList.Any(t => t.Patient.PatientIdStr.Contains(inQuery.PatientIdStr)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientName), t => t.OriginalReReadingTask.Subject.SubjectPatientList.Any(t => t.Patient.PatientName.Contains(inQuery.PatientName)))
.ProjectTo<ReReadingTaskView>(_mapper.ConfigurationProvider);
@ -949,12 +1146,39 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
TrialReadingCriterionId = trialReadingCriterionId,
SubjectCode = inQuery.SubjectCode,
SubjectName = inQuery.SubjectName,
PatientIdStr = inQuery.PatientIdStr,
PatientName = inQuery.PatientName,
PageIndex = inQuery.PageIndex,
PageSize = inQuery.PageSize,
Asc = inQuery.Asc,
SortField = inQuery.SortField,
});
//给出患者编号
var currentPageData = result.CurrentPageData;
var subjectIdList = currentPageData.Select(t => t.SubjectId).ToList();
var list = await _subjectRepository.Where(t => subjectIdList.Contains(t.Id)).Select(t => new
{
SubjectId = t.Id,
PatientList = t.SubjectPatientList.Select(c => new PatientBasicInfo()
{
PatientId = c.PatientId,
PatientAge = c.Patient.PatientAge,
PatientBirthDate = c.Patient.PatientBirthDate,
PatientIdStr = c.Patient.PatientIdStr,
PatientSex = c.Patient.PatientSex,
PatientName = c.Patient.PatientName,
}).ToList(),
}).ToListAsync();
foreach (var item in currentPageData)
{
item.PatientList = list.Where(t => t.SubjectId == item.SubjectId).FirstOrDefault()?.PatientList;
}
}
//随机阅片
else
@ -1001,9 +1225,53 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
var critrion = await _trialReadingCriterionRepository.FindAsync(trialReadingCriterionId);
var readingDivisionEnum = critrion.ReadingDivisionEnum;
var piReadingScopenEnum = critrion.PIReadingScopenEnum;
if (critrion.IsReadingTaskViewInOrder == ReadingOrder.InOrder)
{
var visitQuery = _visitTaskRepository.Where(x => x.TrialId == inQuery.TrialId && x.DoctorUserId == _userInfo.Id && x.TaskState == TaskState.Effect)
var visitQuery = _visitTaskRepository.Where(x => x.TrialId == inQuery.TrialId/* && x.DoctorUserId == _userInfo.Id*/ && x.TaskState == TaskState.Effect)
.WhereIf(inQuery.SubjectId != null, t => t.SubjectId == inQuery.SubjectId)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientIdStr.Contains(inQuery.PatientIdStr)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientName), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientName.Contains(inQuery.PatientName)))
//PI 读基线的时候subject 如果PI基线没阅片完SR就不能看
.WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.SR && piReadingScopenEnum == PIReadingScopenEnum.AllBaseline && readingDivisionEnum == ReadingDivisionEnum.PIandSR,
t => t.Subject.SubjectVisitTaskList.Any(c => c.SourceSubjectVisit.IsBaseLine == true && c.ReadingTaskState == ReadingTaskState.HaveSigned && c.TaskState == TaskState.Effect && c.TrialReadingCriterionId == trialReadingCriterionId))
//PI 读随访的时候, subject 如果SR基线没阅片完PI就不能看
.WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.PI && piReadingScopenEnum == PIReadingScopenEnum.AllVisit && readingDivisionEnum == ReadingDivisionEnum.PIandSR,
t => t.Subject.SubjectVisitTaskList.Any(c => c.SourceSubjectVisit.IsBaseLine == true && c.ReadingTaskState == ReadingTaskState.HaveSigned && c.TaskState == TaskState.Effect && c.TrialReadingCriterionId == trialReadingCriterionId))
//没有site概念
//.WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.SR, t => t.Subject.TrialSite.CRCUserList.Any(u => u.UserId == _userInfo.Id))
// 仅仅SR阅片 PI 没有任务列表
.WhereIf(readingDivisionEnum == ReadingDivisionEnum.OnlySR && _userInfo.UserTypeEnumInt == (int)UserTypeEnum.PI, t => t.TrialId == Guid.Empty)
//PI查看 PI阅片所有基线
.WhereIf(readingDivisionEnum == ReadingDivisionEnum.PIandSR && _userInfo.UserTypeEnumInt == (int)UserTypeEnum.PI && piReadingScopenEnum == PIReadingScopenEnum.AllBaseline,
t => t.SourceSubjectVisit.IsBaseLine == true)
// PI查看 PI 阅片所有
.WhereIf(readingDivisionEnum == ReadingDivisionEnum.PIandSR && _userInfo.UserTypeEnumInt == (int)UserTypeEnum.PI && piReadingScopenEnum == PIReadingScopenEnum.AllBaselineandVisit,
t => true)
// PI查看 PI 阅片访视
.WhereIf(readingDivisionEnum == ReadingDivisionEnum.PIandSR && _userInfo.UserTypeEnumInt == (int)UserTypeEnum.PI && piReadingScopenEnum == PIReadingScopenEnum.AllVisit,
t => t.SourceSubjectVisit.IsBaseLine == false)
//SR查看 PI阅片所有基线
.WhereIf(readingDivisionEnum == ReadingDivisionEnum.PIandSR && _userInfo.UserTypeEnumInt == (int)UserTypeEnum.SR && piReadingScopenEnum == PIReadingScopenEnum.AllBaseline,
t => t.SourceSubjectVisit.IsBaseLine == false)
//SR查看 PI 阅片所有
.WhereIf(readingDivisionEnum == ReadingDivisionEnum.PIandSR && _userInfo.UserTypeEnumInt == (int)UserTypeEnum.SR && piReadingScopenEnum == PIReadingScopenEnum.AllBaselineandVisit,
t => t.TrialId == Guid.Empty)
//SR查看 PI 阅片访视
.WhereIf(readingDivisionEnum == ReadingDivisionEnum.PIandSR && _userInfo.UserTypeEnumInt == (int)UserTypeEnum.SR && piReadingScopenEnum == PIReadingScopenEnum.AllVisit,
t => t.SourceSubjectVisit.IsBaseLine == true)
.WhereIf(inQuery.SubjectId != null, x => x.SubjectId == inQuery.SubjectId)
//前序 不存在 未生成任务的访视
@ -1011,21 +1279,20 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
// 前序 不存在 未一致性核查未通过的
.Where(t => !t.Subject.SubjectVisitList.Any(sv => sv.CheckState != CheckStateEnum.CVPassed && t.VisitTaskNum >= sv.VisitNum))
//.WhereIf(critrion.IsAutoCreate == false, t => t.Subject.SubjectCriteriaEvaluationVisitFilterList.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId).Any(t => t.IsGeneratedTask == false) ?
//t.VisitTaskNum <= t.Subject.SubjectCriteriaEvaluationVisitFilterList.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId && t.IsGeneratedTask == false).Min(t => t.SubjectVisit.VisitNum) : true)
//.Where(t => t.Subject.SubjectVisitList.Any(t => t.CheckState != CheckStateEnum.CVPassed) ? t.VisitTaskNum <= t.Subject.SubjectVisitList.Where(t => t.CheckState != CheckStateEnum.CVPassed).Min(t => t.VisitNum) : true)
//满足前序访视不存在 需要签署但是未签署 sql 相当复杂 同时想查询所有未读的统计数字 就无法统计 byzhouhang
//但是加字段 IsFrontTaskNeedSignButNotSign 那么签名临床数据的时候要对该subject 该标准的有效的任务 这个字段需要在签名的时候维护 采取这种方式 统计数字灵活
//.Where(t => t.Subject.SubjectVisitTaskList.AsQueryable().Where(visitTaskLambda).Any(c => c.IsNeedClinicalDataSign == true && c.IsClinicalDataSign == false && c.VisitTaskNum < t.VisitTaskNum))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectName), t => t.Subject.ShortName.Contains(inQuery.SubjectName))
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => (t.Subject.Code.Contains(inQuery.SubjectCode!) && t.IsAnalysisCreate == false) || (t.BlindSubjectCode.Contains(inQuery.SubjectCode!) && t.IsAnalysisCreate));
var visitGroupQuery = visitQuery.GroupBy(x => new { x.SubjectId, x.Subject.Code, x.BlindSubjectCode });
var visitGroupQuery = visitQuery.GroupBy(x => new { x.SubjectId, x.Subject.Code, x.BlindSubjectCode, x.Subject.ShortName, x.SubjectCriterionClaimUserId, x.SubjectCriterionClaimUser.UserName });
var visitTaskQuery = visitGroupQuery.Select(x => new IRUnReadSubjectView()
{
SubjectId = x.Key.SubjectId,
SubjectCode = x.Key.BlindSubjectCode == string.Empty ? x.Key.Code : x.Key.BlindSubjectCode,
SubjectName = x.Key.ShortName,
ClaimUserId = x.Key.SubjectCriterionClaimUserId,
ClaimUserName = x.Key.UserName,
SuggesteFinishedTime = x.Where(y => y.TrialReadingCriterionId == trialReadingCriterionId && y.ReadingTaskState != ReadingTaskState.HaveSigned).Min(x => x.SuggesteFinishedTime),
@ -1219,17 +1486,23 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
var visitTaskQueryable = _visitTaskRepository.Where(t => t.TrialId == inQuery.TrialId)
.Where(t => t.DoctorUserId == _userInfo.Id && t.ReadingTaskState == ReadingTaskState.HaveSigned)//该医生 已经签名的数据
.WhereIf(inQuery.TrialSiteId != null, t => t.Subject.TrialSiteId == inQuery.TrialSiteId)
.Where(t => /*t.DoctorUserId == _userInfo.Id &&*/ t.ReadingTaskState == ReadingTaskState.HaveSigned)//该医生 已经签名的数据
.WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.PI, t => t.DoctorUser.UserTypeEnum == UserTypeEnum.PI)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientIdStr.Contains(inQuery.PatientIdStr)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientName), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientName.Contains(inQuery.PatientName)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientSex), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientSex.Contains(inQuery.PatientSex)))
.WhereIf(inQuery.PIAuditState != null, t => t.PIAuditState == inQuery.PIAuditState)
.WhereIf(inQuery.BeginSignDate != null, t => t.SignTime >= inQuery.BeginSignDate)
.WhereIf(inQuery.EndSignDate != null, t => t.SignTime <= inQuery.EndSignDate)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectName), t => t.Subject.ShortName.Contains(inQuery.SubjectName))
//.WhereIf(inQuery.TrialSiteId != null, t => t.Subject.TrialSiteId == inQuery.TrialSiteId)
.WhereIf(inQuery.SubjectId != null, t => t.SubjectId == inQuery.SubjectId)
.WhereIf(inQuery.IsUrgent != null, t => t.IsUrgent == inQuery.IsUrgent)
.WhereIf(inQuery.ReadingCategory != null, t => t.ReadingCategory == inQuery.ReadingCategory)
.WhereIf(inQuery.TaskAllocationState != null, t => t.TaskAllocationState == inQuery.TaskAllocationState)
.WhereIf(inQuery.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId)
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectName), t => t.Subject.ShortName.Contains(inQuery.SubjectName))
.WhereIf(inQuery.TaskState != null, t => t.TaskState == inQuery.TaskState)
.WhereIf(!string.IsNullOrEmpty(inQuery.TrialSiteCode), t => (t.BlindTrialSiteCode.Contains(inQuery.TrialSiteCode!) && t.IsAnalysisCreate) || (t.Subject.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteCode!) && t.IsAnalysisCreate == false))
.WhereIf(!string.IsNullOrEmpty(inQuery.TaskName), t => t.TaskName.Contains(inQuery.TaskName) || t.TaskBlindName.Contains(inQuery.TaskName))
@ -1249,55 +1522,105 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
[HttpPost]
[UnitOfWork]
public async Task<IResponseOutput> AIRReReading(AIRReReadingCommand command, [FromServices] IVisitTaskHelpeService _visitTaskCommonService)
public async Task<IResponseOutput> AIRReReading(AIRReReadingCommand command,
[FromServices] IVisitTaskHelpeService _visitTaskCommonService,
[FromServices] IRepository<ReadingTableQuestionAnswer> _readingTableQuestionAnswerRepository)
{
var baseLineTaskList = await _visitTaskRepository.Where(t => t.TrialId == command.TrialId && t.TrialReadingCriterionId == command.TrialReadingCriterionId && t.DoctorUserId == _userInfo.Id
&& t.TaskState == TaskState.Effect && t.ReadingCategory == ReadingCategory.Visit && t.ReadingTaskState == ReadingTaskState.HaveSigned && t.SourceSubjectVisit.IsBaseLine == true).ToListAsync();
var judegeList = await _visitTaskRepository.Where(t => t.TrialId == command.TrialId && t.TrialReadingCriterionId == command.TrialReadingCriterionId && t.DoctorUserId == _userInfo.Id
&& t.TaskState == TaskState.Effect && t.ReadingCategory == ReadingCategory.Judge && t.ReadingTaskState == ReadingTaskState.HaveSigned).ToListAsync();
foreach (var item in judegeList)
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.AIR)
{
if (!baseLineTaskList.Any(t => t.SubjectId == item.SubjectId))
var baseLineTaskList = await _visitTaskRepository.Where(t => t.TrialId == command.TrialId && t.TrialReadingCriterionId == command.TrialReadingCriterionId && t.DoctorUserId == _userInfo.Id
&& t.TaskState == TaskState.Effect && t.ReadingCategory == ReadingCategory.Visit && t.ReadingTaskState == ReadingTaskState.HaveSigned && t.SourceSubjectVisit.IsBaseLine == true).ToListAsync();
var judegeList = await _visitTaskRepository.Where(t => t.TrialId == command.TrialId && t.TrialReadingCriterionId == command.TrialReadingCriterionId && t.DoctorUserId == _userInfo.Id
&& t.TaskState == TaskState.Effect && t.ReadingCategory == ReadingCategory.Judge && t.ReadingTaskState == ReadingTaskState.HaveSigned).ToListAsync();
foreach (var item in judegeList)
{
baseLineTaskList.Add(item);
if (!baseLineTaskList.Any(t => t.SubjectId == item.SubjectId))
{
baseLineTaskList.Add(item);
}
}
var baseLineTaskIdList = baseLineTaskList.Select(t => t.Id).ToList();
if (baseLineTaskIdList.Count == 0)
{
return ResponseOutput.Ok();
}
//if (baseLineTaskList == null)
//{
// return ResponseOutput.NotOk("基线任务未阅完,不允许重阅基线任务");
//}
await ApplyReReading(new ApplyReReadingCommand() { IsCopyFollowForms = false, IsCopyOrigenalForms = false, TaskIdList = baseLineTaskIdList, TrialId = command.TrialId, RequestReReadingReason = "AIR自动重阅基线", RequestReReadingType = RequestReReadingType.DocotorApply });
var requestRecordList = await _visitTaskReReadingRepository.Where(t => baseLineTaskIdList.Contains(t.OriginalReReadingTaskId) && t.RequestReReadingUserId == _userInfo.Id && t.RequestReReadingReason == "AIR自动重阅基线").ToListAsync();
if (requestRecordList.Count != baseLineTaskIdList.Count)
{
//---后台数据有错误
return ResponseOutput.NotOk(_localizer["VisitTask_DoctorConfiguration"]);
}
await ConfirmReReading(new ConfirmReReadingCommand()
{
TrialId = command.TrialId,
RequestReReadingResultEnum = RequestReReadingResult.Agree,
//ConfirmReReadingList = new List<ConfirmReReadingDTO>() { new ConfirmReReadingDTO() { Id = requestRecord.Id, OriginalReReadingTaskId = task.Id } }
ConfirmReReadingList = requestRecordList.Select(t => new ConfirmReReadingDTO() { Id = t.Id, OriginalReReadingTaskId = t.OriginalReReadingTaskId }).ToList()
}, _visitTaskCommonService);
}
else
{
if (command.VisitTaskId != null)
{
var visitTaskId = command.VisitTaskId.Value;
var taskIdList = new List<Guid>();
taskIdList.Add(visitTaskId);
await ApplyReReading(new ApplyReReadingCommand() { IsCopyFollowForms = false, IsCopyOrigenalForms = true, TaskIdList = taskIdList, TrialId = command.TrialId, RequestReReadingReason = "阅片人自动重阅阅片任务", RequestReReadingType = RequestReReadingType.DocotorApply });
var requestRecord = await _visitTaskReReadingRepository.Where(t => visitTaskId == t.OriginalReReadingTaskId && t.RequestReReadingUserId == _userInfo.Id && t.RequestReReadingReason == "阅片人自动重阅阅片任务").FirstAsync();
await ConfirmReReading(new ConfirmReReadingCommand()
{
TrialId = command.TrialId,
RequestReReadingResultEnum = RequestReReadingResult.Agree,
ConfirmReReadingList = new List<ConfirmReReadingDTO>() { new ConfirmReReadingDTO() { Id = requestRecord.Id, OriginalReReadingTaskId = visitTaskId } }
}, _visitTaskCommonService);
//有序SR 申请重阅的时候,把后续任务的拷贝表单要清理掉
var taskInfo = _visitTaskRepository.Where(t => t.Id == visitTaskId).Select(t => new { t.TrialReadingCriterion.IsReadingTaskViewInOrder, t.TrialReadingCriterionId, t.SubjectId, t.VisitTaskNum }).FirstOrDefault();
if (taskInfo.IsReadingTaskViewInOrder == ReadingOrder.InOrder)
{
var afterTaskIdList = _visitTaskRepository.Where(t => t.SubjectId == taskInfo.SubjectId && t.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId
&& t.ReadingCategory == ReadingCategory.Visit && t.VisitTaskNum > taskInfo.VisitTaskNum && t.TaskState == TaskState.Effect).Select(t => t.Id).ToList();
await _visitTaskRepository.BatchUpdateNoTrackingAsync(t => afterTaskIdList.Contains(t.Id), u => new VisitTask() { FirstReadingTime = null, ReadingTaskState = ReadingTaskState.WaitReading });
await _readingCustomTagRepository.BatchDeleteNoTrackingAsync(t => afterTaskIdList.Contains(t.VisitTaskId));
await _readingTaskQuestionMarkRepository.BatchDeleteNoTrackingAsync(t => afterTaskIdList.Contains(t.VisitTaskId));
await _readingTaskQuestionAnswerRepository.BatchDeleteNoTrackingAsync(t => afterTaskIdList.Contains(t.VisitTaskId));
await _readingTableAnswerRowInfoRepository.BatchDeleteNoTrackingAsync(t => afterTaskIdList.Contains(t.VisitTaskId));
await _readingTableQuestionAnswerRepository.BatchDeleteNoTrackingAsync(t => afterTaskIdList.Contains(t.VisitTaskId));
}
}
}
var baseLineTaskIdList = baseLineTaskList.Select(t => t.Id).ToList();
if (baseLineTaskIdList.Count == 0)
{
return ResponseOutput.Ok();
}
//if (baseLineTaskList == null)
//{
// return ResponseOutput.NotOk("基线任务未阅完,不允许重阅基线任务");
//}
await ApplyReReading(new ApplyReReadingCommand() { IsCopyFollowForms = false, IsCopyOrigenalForms = false, TaskIdList = baseLineTaskIdList, TrialId = command.TrialId, RequestReReadingReason = "AIR自动重阅基线", RequestReReadingType = RequestReReadingType.DocotorApply });
var requestRecordList = await _visitTaskReReadingRepository.Where(t => baseLineTaskIdList.Contains(t.OriginalReReadingTaskId) && t.RequestReReadingUserId == _userInfo.Id && t.RequestReReadingReason == "AIR自动重阅基线").ToListAsync();
if (requestRecordList.Count != baseLineTaskIdList.Count)
{
//---后台数据有错误
return ResponseOutput.NotOk(_localizer["VisitTask_DoctorConfiguration"]);
}
await ConfirmReReading(new ConfirmReReadingCommand()
{
TrialId = command.TrialId,
RequestReReadingResultEnum = RequestReReadingResult.Agree,
//ConfirmReReadingList = new List<ConfirmReReadingDTO>() { new ConfirmReReadingDTO() { Id = requestRecord.Id, OriginalReReadingTaskId = task.Id } }
ConfirmReReadingList = requestRecordList.Select(t => new ConfirmReReadingDTO() { Id = t.Id, OriginalReReadingTaskId = t.OriginalReReadingTaskId }).ToList()
}, _visitTaskCommonService);
return ResponseOutput.Ok();
}
@ -1334,7 +1657,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
throw new BusinessValidationFailedException(_localizer["VisitTask_BackendData"]);
}
_logger.LogError("重阅申请状态"+ (int)task.ReReadingApplyState);
_logger.LogError("重阅申请状态" + (int)task.ReReadingApplyState);
if (task.ReReadingApplyState == ReReadingApplyState.DocotorHaveApplyed || task.ReReadingApplyState == ReReadingApplyState.TrialGroupHaveApplyed || task.ReReadingApplyState == ReReadingApplyState.Agree)
{
@ -1478,7 +1801,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
}
//AIR 不加验证
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.AIR)
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.AIR || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.PI || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.SR)
{
task.ReReadingApplyState = ReReadingApplyState.DocotorHaveApplyed;
}
@ -1614,7 +1937,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
visitTaskReReadingAppply.RequestReReadingRejectReason = agreeReReadingCommand.RequestReReadingRejectReason;
Expression<Func<VisitTask, bool>> filterExpression = t => t.TrialId == trialId && t.SubjectId == origenalTask.SubjectId && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze) && t.TaskAllocationState == TaskAllocationState.Allocated;
Expression<Func<VisitTask, bool>> filterExpression = t => t.TrialId == trialId && t.SubjectId == origenalTask.SubjectId && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze) /*&& t.TaskAllocationState == TaskAllocationState.Allocated*/;
//是否是一致性分析任务 正常申请 会影响一致性分析任务
filterExpression = filterExpression.And(t => t.IsAnalysisCreate == origenalTask.IsAnalysisCreate);
@ -1780,7 +2103,10 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
}
//IR申请 PM 审批 注意这里有一致性分析的申请同意 不会回退访视,在此要生成影响的访视任务
else if (visitTaskReReadingAppply.RequestReReadingType == RequestReReadingType.DocotorApply && (IsPMOrAPm() || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.AIR))
else if (visitTaskReReadingAppply.RequestReReadingType == RequestReReadingType.DocotorApply && (IsPMOrAPm() ||
_userInfo.UserTypeEnumInt == (int)UserTypeEnum.AIR
|| _userInfo.UserTypeEnumInt == (int)UserTypeEnum.SR
|| _userInfo.UserTypeEnumInt == (int)UserTypeEnum.PI))
{
@ -2161,6 +2487,8 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
{
item.Id = Guid.Empty;
item.VisitTaskId = newTask.Id;
item.MeasureData = item.MeasureData.Replace(origenalTask.Id.ToString(), newTask.Id.ToString());
}
_ = _readingCustomTagRepository.AddRangeAsync(readingCustomTagList).Result;
@ -2172,6 +2500,8 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
{
item.Id = Guid.Empty;
item.VisitTaskId = newTask.Id;
item.MeasureData = item.MeasureData.Replace(origenalTask.Id.ToString(), newTask.Id.ToString());
}
_ = _readingTaskQuestionMarkRepository.AddRangeAsync(readingTaskQuestionMarkList).Result;
@ -2196,6 +2526,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
var originalVisitTaskId = item.VisitTaskId;
var originalFristAddTaskId = item.FristAddTaskId;
item.MeasureData = item.MeasureData.Replace(origenalTask.Id.ToString(), newTask.Id.ToString());
item.Id = NewId.NextSequentialGuid();
item.VisitTaskId = newTask.Id;
@ -2576,7 +2907,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
var criterionConfig = (await _trialReadingCriterionRepository.Where(x => x.Id == filterObj.TrialReadingCriterionId).Select(x => new { x.ReadingTool, x.CriterionType, x.IsAdditionalAssessment, x.IsReadingTaskViewInOrder }).FirstOrDefaultAsync()).IfNullThrowException();
Expression<Func<VisitTask, bool>> filterExpression = t => t.TrialId == trialId && t.SubjectId == filterObj.SubjectId && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze) && t.TaskAllocationState == TaskAllocationState.Allocated;
Expression<Func<VisitTask, bool>> filterExpression = t => t.TrialId == trialId && t.SubjectId == filterObj.SubjectId && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze);
//是否是一致性分析任务 (一致性分析的任务 不会产生裁判 肿瘤学 仅仅有生成的访视和全局)

View File

@ -10,6 +10,21 @@ namespace IRaCIS.Core.Application.Service
public AllocationConfig()
{
#region HIR
CreateMap<VisitTask, PIReaingTaskView>().IncludeBase<VisitTask, ReadingTaskView>()
.ForMember(o => o.FirstAuditUserName, t => t.MapFrom(u => u.FirstAuditUser.UserName))
.ForMember(o => o.LatestReplyUserName, t => t.MapFrom(u => u.LatestReplyUser.UserName))
.ForMember(d => d.PatientList, u => u.MapFrom(s => s.Subject.SubjectPatientList));
CreateMap<PIAuditTaskCommand, PIAudit>();
CreateMap<PIAudit, PIAuditDialogListView>()
.ForMember(o => o.CreateUserName, t => t.MapFrom(u => u.CreateUser.UserName))
.ForMember(o => o.UserTypeEnum, t => t.MapFrom(u => u.CreateUser.UserTypeEnum))
//.ForMember(o => o.PIAuditState, t => t.MapFrom(u => u.VisitTask.PIAuditState))
;
#endregion
CreateMap<ReadingTableAnswerRowInfo, ConvertedRowInfo>()
.ForMember(d => d.OriginalId, u => u.MapFrom(s => s.Id));
@ -117,13 +132,14 @@ namespace IRaCIS.Core.Application.Service
.ForMember(o => o.IsReadingShowPreviousResults, t => t.MapFrom(u => u.TrialReadingCriterion.IsReadingShowPreviousResults))
.ForMember(o => o.DigitPlaces, t => t.MapFrom(u => u.TrialReadingCriterion.DigitPlaces))
.ForMember(o => o.IseCRFShowInDicomReading, t => t.MapFrom(u => u.TrialReadingCriterion.IseCRFShowInDicomReading))
.ForMember(o => o.CriterionType, t => t.MapFrom(u => u.TrialReadingCriterion.CriterionType));
.ForMember(o => o.CriterionType, t => t.MapFrom(u => u.TrialReadingCriterion.CriterionType))
.ForMember(o => o.SubjectShortName, t => t.MapFrom(u => u.Subject.ShortName));
CreateMap<VisitTask, VisitTaskView>().IncludeBase<VisitTask, VisitTaskViewBasic>()
.ForMember(o => o.TrialSiteId, t => t.MapFrom(u => u.Subject.TrialSiteId))
.ForMember(o => o.TrialSiteCode, t => t.MapFrom(u => /*u.IsAnalysisCreate == true ? u.BlindTrialSiteCode :*/ u.Subject.TrialSite.TrialSiteCode))
//.ForMember(o => o.TrialSiteCode, t => t.MapFrom(u => /*u.IsAnalysisCreate == true ? u.BlindTrialSiteCode :*/ u.Subject.TrialSite.TrialSiteCode))
.ForMember(o => o.SubjectCode, t => t.MapFrom(u => /*u.IsAnalysisCreate == true ? u.BlindSubjectCode :*/ u.Subject.Code))
.ForMember(o => o.MedicalNo, t => t.MapFrom(u => u.Subject.MedicalNo))
@ -169,8 +185,9 @@ namespace IRaCIS.Core.Application.Service
CreateMap<VisitTask, IRHaveReadView>().IncludeBase<VisitTask, VisitTaskViewBasic>()
.ForMember(o => o.TrialSiteId, t => t.MapFrom(u => u.Subject.TrialSiteId))
.ForMember(o => o.TrialSiteCode, t => t.MapFrom(u => u.IsAnalysisCreate == true ? u.BlindTrialSiteCode : u.Subject.TrialSite.TrialSiteCode))
.ForMember(o => o.SubjectCode, t => t.MapFrom(u => u.IsAnalysisCreate == true ? u.BlindSubjectCode : u.Subject.Code));
//.ForMember(o => o.TrialSiteCode, t => t.MapFrom(u => u.IsAnalysisCreate == true ? u.BlindTrialSiteCode : u.Subject.TrialSite.TrialSiteCode))
.ForMember(o => o.SubjectCode, t => t.MapFrom(u => u.IsAnalysisCreate == true ? u.BlindSubjectCode : u.Subject.Code))
.ForMember(d => d.PatientList, u => u.MapFrom(s => s.Subject.SubjectPatientList));
@ -321,6 +338,7 @@ namespace IRaCIS.Core.Application.Service
CreateMap<ReadingClinicalDataPDF, ReadingConsistentClinicalDataPDF>().ReverseMap();
}
}

View File

@ -230,7 +230,7 @@ namespace IRaCIS.Core.Application.Service.Common
ExperimentName = t.ExperimentName,
TrialCode = t.TrialCode,
CreateTime = t.CreateTime,
Sponsor = _userInfo.IsEn_Us ? t.Sponsor.SponsorName : t.Sponsor.SponsorNameCN,
Sponsor = _userInfo.IsEn_Us ? t.Sponsor : t.Sponsor,
TrialStatusStr = t.TrialStatusStr,
ExpetiedTaskCount = isPM ? t.VisitTaskList.Where(t => t.IsUrgent).Count() : 0,
@ -1252,40 +1252,8 @@ namespace IRaCIS.Core.Application.Service.Common
}
/// <summary>
/// 影像接收记录表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> GetSCPImageUploadList_Export(SCPImageUploadQuery inQuery,
[FromServices] IRepository<SCPImageUpload> _scpImageUploadRepository,
[FromServices] IDictionaryService _dictionaryService,
[FromServices] IRepository<Trial> _trialRepository)
{
var query = _scpImageUploadRepository.Where(t => t.TrialId == inQuery.TrialId)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CalledAE), t => t.CalledAE.Contains(inQuery.CalledAE))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAEIP), t => t.CallingAEIP.Contains(inQuery.CallingAEIP))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAE), t => t.CallingAE.Contains(inQuery.CallingAE))
.WhereIf(inQuery.StartTime != null, t => t.StartTime >= inQuery.StartTime)
.WhereIf(inQuery.EndTime != null, t => t.EndTime <= inQuery.EndTime)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.TrialSiteKeyInfo), t => t.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteKeyInfo)
|| t.TrialSite.TrialSiteAliasName.Contains(inQuery.TrialSiteKeyInfo) || t.TrialSite.TrialSiteName.Contains(inQuery.TrialSiteKeyInfo))
.ProjectTo<SCPImageUploadExportDTO>(_mapper.ConfigurationProvider);
var list = await query.SortToListAsync(inQuery);
var exportInfo = (await _trialRepository.Where(t => t.Id == inQuery.TrialId).IgnoreQueryFilters().ProjectTo<ExcelExportInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list, _userInfo.TimeZoneId);
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
return await ExcelExportHelper.DataExportAsync(StaticData.Export.TrialSCPImageUploadList_Export, exportInfo, $"{exportInfo.ResearchProgramNo}", _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(SCPImageUploadExportDTO));
}
/// <summary>
/// 国际化导出
/// </summary>
@ -1322,76 +1290,8 @@ namespace IRaCIS.Core.Application.Service.Common
}
/// <summary>
///影像检查列表-患者为维度组织
/// </summary>
/// <param name="inQuery"></param>
/// <param name="_patientRepository"></param>
/// <param name="_dictionaryService"></param>
/// <param name="_trialRepository"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> GetPatientList_Export(PatientTrialQuery inQuery,
[FromServices] IRepository<SCPPatient> _patientRepository,
[FromServices] IDictionaryService _dictionaryService,
[FromServices] IRepository<Trial> _trialRepository)
{
var query = _patientRepository.Where(t => t.TrialId == inQuery.TrialId)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), t => t.PatientIdStr.Contains(inQuery.PatientIdStr))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientName), t => t.PatientName.Contains(inQuery.PatientName))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubejctCode), t => t.Subject.Code.Contains(inQuery.SubejctCode))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.TrialSiteKeyInfo), t => t.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteKeyInfo)
|| t.TrialSite.TrialSiteAliasName.Contains(inQuery.TrialSiteKeyInfo) || t.TrialSite.TrialSiteName.Contains(inQuery.TrialSiteKeyInfo))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAE), t => t.SCPStudyList.Any(t => t.CallingAE == inQuery.CallingAE))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CalledAE), t => t.SCPStudyList.Any(t => t.CalledAE == inQuery.CalledAE))
.WhereIf(inQuery.BeginPushTime != null, t => t.LatestPushTime >= inQuery.BeginPushTime)
.WhereIf(inQuery.EndPushTime != null, t => t.LatestPushTime <= inQuery.EndPushTime);
var resultQuery = from patient in query
select new SCPPatientSubjectExportDTO()
{
//CreateUserId = patient.CreateUserId,
//UpdateTime = patient.UpdateTime,
//UpdateUserId = patient.UpdateUserId,
//TrialId = patient.TrialId,
//SubejctId = patient.SubjectId,
//CreateTime = patient.CreateTime,
//PatientId = patient.Id,
PatientBirthDate = patient.PatientBirthDate,
CalledAEList = patient.SCPStudyList.Select(t => t.CalledAE).Distinct().ToList(),
CallingAEList = patient.SCPStudyList.Select(t => t.CallingAE).Distinct().ToList(),
EarliestStudyTime = patient.EarliestStudyTime,
LatestStudyTime = patient.LatestStudyTime,
LatestPushTime = patient.LatestPushTime,
PatientAge = patient.PatientAge,
PatientName = patient.PatientName,
PatientIdStr = patient.PatientIdStr,
PatientSex = patient.PatientSex,
StudyCount = patient.SCPStudyList.Count(),
SubjectCode = patient.Subject.Code,
TrialSiteAliasName = patient.TrialSite.TrialSiteAliasName,
TrialSiteCode = patient.TrialSite.TrialSiteCode,
TrialSiteName = patient.TrialSite.TrialSiteName
};
var list = await resultQuery.SortToListAsync(inQuery);
var exportInfo = (await _trialRepository.Where(t => t.Id == inQuery.TrialId).IgnoreQueryFilters().ProjectTo<ExcelExportInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list, _userInfo.TimeZoneId);
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
return await ExcelExportHelper.DataExportAsync(StaticData.Export.TrialSCPImageUploadPatientList_Export, exportInfo, $"{exportInfo.ResearchProgramNo}", _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(SCPPatientSubjectExportDTO));
}
/// <summary>
/// 邮件导出
@ -1502,11 +1402,25 @@ namespace IRaCIS.Core.Application.Service.Common
}
else
{
//如果没有产生裁判默认选择R1
if (item.ArmEnum == Arm.DoubleReadingArm1)
//两个人都做了
if (resultExceptJudgeList.Count(t => t.VisitTaskNum == item.VisitTaskNum && t.SubjectCode == item.SubjectCode) == 2)
{
item.IsJudgeSelect = true;
//如果没有产生裁判默认选择R1
if (item.ArmEnum == Arm.DoubleReadingArm1)
{
item.IsJudgeSelect = true;
}
else
{
item.IsJudgeSelect = false;
}
}
else
{
item.IsJudgeSelect = null;
item.IsTrigerJudge = null;
}
}
}
@ -1524,17 +1438,26 @@ namespace IRaCIS.Core.Application.Service.Common
var maxFinishedJudge = judegeList.Where(t => t.ReadingTaskState == ReadingTaskState.HaveSigned).OrderByDescending(t => t.VisitTaskNum).FirstOrDefault();
var maxNotFinishedJudge = judegeList.Where(t => t.ReadingTaskState != ReadingTaskState.HaveSigned).FirstOrDefault();
var maxNotFinishedJudge = judegeList.Where(t => t.ReadingTaskState != ReadingTaskState.HaveSigned).OrderByDescending(t => t.VisitTaskNum).FirstOrDefault();
//仅有一个未完成的全局裁判那么都是null
//n个裁判任务都未完成
if (maxFinishedJudge == null && maxNotFinishedJudge != null)
{
if (visitItem.VisitTaskNum < maxNotFinishedJudge.VisitTaskNum)
{
visitItem.IsJudgeSelect = null;
}
else
{
//大于当前未完成的全局裁判 后续 肯定是未知的
visitItem.IsTrigerJudge = null;
visitItem.IsJudgeSelect = null;
}
}
//全局裁判都完成了,那么以最后一次裁判选择的为准
//n个全局裁判都完成了,那么以最后一次裁判选择的为准
else if (maxFinishedJudge != null && maxNotFinishedJudge == null)
{
if (visitItem.ArmEnum == maxFinishedJudge.JudgeArmEnum && visitItem.VisitTaskNum < maxFinishedJudge.VisitTaskNum)
@ -1547,14 +1470,27 @@ namespace IRaCIS.Core.Application.Service.Common
{
visitItem.IsJudgeSelect = false;
}
else
{
//裁判都完成的后续 没有其他裁判任务 肯定也是未知的
visitItem.IsTrigerJudge = null;
visitItem.IsJudgeSelect = null;
}
}
else
{
//两个都不为null 肯定是不同的裁判
//在完成裁判之后的,和未完成裁判之前的
if (/*visitItem.VisitTaskNum < maxNotFinishedJudge.VisitTaskNum &&*/ visitItem.VisitTaskNum > maxFinishedJudge.VisitTaskNum)
//在完成裁判之后的
if (visitItem.VisitTaskNum > maxNotFinishedJudge.VisitTaskNum)
{
visitItem.IsTrigerJudge = null;
visitItem.IsJudgeSelect = null;
}
//完成裁判之后的 ,和未完成裁判之前的
else if (visitItem.VisitTaskNum < maxNotFinishedJudge.VisitTaskNum && visitItem.VisitTaskNum > maxFinishedJudge.VisitTaskNum)
{
visitItem.IsTrigerJudge = true;
visitItem.IsJudgeSelect = null;
}
else if (visitItem.ArmEnum == maxFinishedJudge.JudgeArmEnum && visitItem.VisitTaskNum < maxFinishedJudge.VisitTaskNum)
@ -1571,11 +1507,27 @@ namespace IRaCIS.Core.Application.Service.Common
}
else
{
//不存在裁判 将R1设置
if (visitItem.ArmEnum == Arm.DoubleReadingArm1)
//没有产生裁判 有可能一个人没做完,也有可能做完了没产生裁判
//两个人都做了
if (resultExceptJudgeList.Count(t => t.VisitTaskNum == visitItem.VisitTaskNum && t.SubjectCode == visitItem.SubjectCode) == 2)
{
visitItem.IsJudgeSelect = true;
//不存在裁判 将R1设置
if (visitItem.ArmEnum == Arm.DoubleReadingArm1)
{
visitItem.IsJudgeSelect = true;
}
else
{
visitItem.IsJudgeSelect = false;
}
}
else
{
visitItem.IsJudgeSelect = null;
visitItem.IsTrigerJudge = null;
}
}
}
}
@ -1842,7 +1794,7 @@ namespace IRaCIS.Core.Application.Service.Common
list.Add(new ExportDocumentDes() { Code = StaticData.Export.CommonJudgeReadingDetail_Export, ExportCatogory = ExportResult.DetailedTableOfAdjudicationResults });
//list.Add(new ExportDocumentDes() { Code = StaticData.Export.CommonJudgeReadingDetail_Export, ExportCatogory = ExportResult.DetailedTableOfAdjudicationResults });
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB
@ -1852,29 +1804,29 @@ namespace IRaCIS.Core.Application.Service.Common
list.Add(new ExportDocumentDes() { Code = StaticData.Export.ReadingLession_Export, ExportCatogory = ExportResult.DetailedTableOfLesions });
}
if (criterion.CriterionType == CriterionType.OCT)
{
list.Add(new ExportDocumentDes() { Code = StaticData.Export.OCT_ReadingLession_Export, ExportCatogory = ExportResult.OCT_ReadingLession_Export });
}
//if (criterion.CriterionType == CriterionType.OCT)
//{
// list.Add(new ExportDocumentDes() { Code = StaticData.Export.OCT_ReadingLession_Export, ExportCatogory = ExportResult.OCT_ReadingLession_Export });
//}
switch (criterion.ArbitrationRule)
{
case ArbitrationRule.None:
break;
//switch (criterion.ArbitrationRule)
//{
// case ArbitrationRule.None:
// break;
case ArbitrationRule.Visit:
list.Add(new ExportDocumentDes() { Code = StaticData.Export.VisitJudgeRatio_Export, ExportCatogory = ExportResult.VisitJudgeRatio_Export });
// case ArbitrationRule.Visit:
// list.Add(new ExportDocumentDes() { Code = StaticData.Export.VisitJudgeRatio_Export, ExportCatogory = ExportResult.VisitJudgeRatio_Export });
break;
case ArbitrationRule.Reading:
list.Add(new ExportDocumentDes() { Code = StaticData.Export.ReadingPeriodJudgeRatio_Export, ExportCatogory = ExportResult.ReadingPeriodJudgeRatio_Export });
// break;
// case ArbitrationRule.Reading:
// list.Add(new ExportDocumentDes() { Code = StaticData.Export.ReadingPeriodJudgeRatio_Export, ExportCatogory = ExportResult.ReadingPeriodJudgeRatio_Export });
break;
case ArbitrationRule.NA:
break;
default:
break;
}
// break;
// case ArbitrationRule.NA:
// break;
// default:
// break;
//}
//if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB)
@ -2184,8 +2136,8 @@ namespace IRaCIS.Core.Application.Service.Common
var dynamicColumnConfig = new DynamicColumnConfig()
{
AutoColumnTitleRowIndex = 2,
AutoColumnStartIndex = 6,
TempalteLastColumnIndex = 8,
AutoColumnStartIndex = 5,
TempalteLastColumnIndex = 4,
DynamicItemDicName = "TranslateDicName",
DynamicItemValueName = "QuestionValue",
DynamicItemTitleName = "QuestionName",

View File

@ -100,7 +100,8 @@ namespace IRaCIS.Core.Application.Service
.ForMember(d => d.UserName, u => u.MapFrom(s => s.CreateUser.UserName))
.ForMember(d => d.TrialSiteCode, u => u.MapFrom(s => s.Subject.TrialSite.TrialSiteCode));
CreateMap<InternationalizationAddOrEdit, IRCGlobalInfoDTO>();
}
}

View File

@ -1,4 +1,5 @@
using IRaCIS.Core.Application.Helper;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using Microsoft.Extensions.Options;
@ -9,7 +10,11 @@ namespace IRaCIS.Core.Application.Service
public interface IEmailSendService
{
Task SendEnrollOrPdEmail(Guid visitTaskId, bool? isEnrollment, bool? isPDConfirm);
Task SendClinicalDataQuestionAsync(Guid visitTaskId, string content);
Task SendPIAuditResultAsync(Guid visitTaskId);
Task<(TrialEmailNoticeConfig?, SMTPEmailConfig?)> BuildEmailConfig(Guid trialId, EmailBusinessScenario businessScenario, Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc, Guid? siteId = null, Guid? trialReadingCriterionId = null);
}
@ -18,6 +23,7 @@ namespace IRaCIS.Core.Application.Service
IRepository<TrialUser> _trialUserRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<TrialSiteUser> _trialSiteUserRepository,
IRepository<Dictionary> _dictionaryRepository,
IOptionsMonitor<SystemEmailSendConfig> _SystemEmailSendConfig, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IEmailSendService
{
@ -53,7 +59,7 @@ namespace IRaCIS.Core.Application.Service
t.Trial.ResearchProgramNo,
t.Subject.TrialSite.TrialSiteCode,
SubjectCode = t.Subject.Code,
t.Trial.Sponsor.SponsorName,
t.Trial.Sponsor,
t.SourceSubjectVisit.VisitName,
t.TrialId,
@ -98,6 +104,71 @@ namespace IRaCIS.Core.Application.Service
}
//临床数据质询
public async Task SendClinicalDataQuestionAsync(Guid visitTaskId, string content)
{
var isEn_us = _userInfo.IsEn_Us;
var info = await _visitTaskRepository.Where(t => t.Id == visitTaskId, ignoreQueryFilters: true).Select(t => new { t.TrialId, t.Trial.ResearchProgramNo, t.Trial.TrialCode, t.SourceSubjectVisit.VisitName, t.Subject.TrialSiteId, t.Subject.Code }).FirstOrDefaultAsync();
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, info.ResearchProgramNo, info.Code, info.VisitName);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
EmailNamePlaceholder, info.ResearchProgramNo, info.Code, info.VisitName, _userInfo.UserName, content, _SystemEmailSendConfig.CurrentValue.SiteUrl);
return (topicStr, htmlBodyStr, isEn_us, null);
};
await SendTrialEmailAsync(info.TrialId, EmailBusinessScenario.ClinicalDataQuestion, topicAndHtmlFunc, info.TrialSiteId);
}
public async Task SendPIAuditResultAsync(Guid visitTaskId)
{
var isEn_us = _userInfo.IsEn_Us;
var info = await _visitTaskRepository.Where(t => t.Id == visitTaskId, ignoreQueryFilters: true).Select(t => new { t.TrialId, t.Trial.ResearchProgramNo, t.Trial.TrialCode, t.SourceSubjectVisit.VisitName, t.Subject.TrialSiteId, t.Subject.Code }).FirstOrDefaultAsync();
var answerList = await _visitTaskRepository.Where(t => t.Id == visitTaskId, ignoreQueryFilters: true).SelectMany(t => t.ReadingTaskQuestionAnswerList).Where(t => t.ReadingQuestionTrial.IsJudgeQuestion == true).Select(t => new { QuestionName = isEn_us ? t.ReadingQuestionTrial.QuestionEnName : t.ReadingQuestionTrial.QuestionName, t.ReadingQuestionTrial.DictionaryCode, t.Answer }).ToListAsync();
var template = " <div style=\"margin-left: 2ch;\"> {0}: {1} </div>";
var needTranslateDicNameList = answerList.Where(t => !string.IsNullOrEmpty(t.DictionaryCode)).Select(t => t.DictionaryCode).ToList();
var searchList = await _dictionaryRepository.Where(t => needTranslateDicNameList.ToArray().Contains(t.Parent.Code) && t.ParentId != null && t.IsEnable).ProjectTo<BasicDicSelectCopy>(_mapper.ConfigurationProvider, new { isEn_Us = _userInfo.IsEn_Us }).ToListAsync();
var translateDataList = searchList.GroupBy(t => t.ParentCode).ToDictionary(g => g.Key, g => g.OrderBy(t => t.ShowOrder).ToList());
Func<bool, string, string, string> transFunc = (bool isNeedTranslate, string dicCode, string answer) =>
{
if (isNeedTranslate && translateDataList.ContainsKey(dicCode))
{
var result = translateDataList[dicCode].Where(t => t.Code.ToLower() == answer.ToLower()).Select(t => isEn_us ? t.Value : t.ValueCN).FirstOrDefault() ?? answer;
return result;
}
else
{
return answer;
}
};
var piResult = string.Join(' ', answerList.Select(t => string.Format(template, t.QuestionName, transFunc(!string.IsNullOrEmpty(t.DictionaryCode), t.DictionaryCode, t.Answer))));
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, info.ResearchProgramNo, info.Code, info.VisitName);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
EmailNamePlaceholder, info.ResearchProgramNo, info.Code, info.VisitName, _userInfo.UserName, piResult, _SystemEmailSendConfig.CurrentValue.SiteUrl);
return (topicStr, htmlBodyStr, isEn_us, null);
};
await SendTrialEmailAsync(info.TrialId, EmailBusinessScenario.PIAuditResutl, topicAndHtmlFunc, info.TrialSiteId);
}

View File

@ -187,7 +187,7 @@ namespace IRaCIS.Core.Application.Service
t.Trial.ResearchProgramNo,
t.Subject.TrialSite.TrialSiteCode,
SubjectCode = t.Subject.Code,
t.Trial.Sponsor.SponsorName,
t.Trial.Sponsor,
t.Trial.IsEnrollementQualificationConfirm,
t.Trial.IsPDProgressView,
@ -617,7 +617,7 @@ namespace IRaCIS.Core.Application.Service
var value = new Dictionary<string, object>()
{
["SponsorName"] = taskInfo.SponsorName,
["SponsorName"] = taskInfo.Sponsor,
["ResearchProgramNo"] = taskInfo.ResearchProgramNo,
["TrialSiteCode"] = taskInfo.TrialSiteCode,
["SubjectCode"] = taskInfo.SubjectCode,

View File

@ -47,7 +47,7 @@ namespace IRaCIS.Core.Application.Service
CreateMap<TrialPaymentPrice, TrialPaymentPriceDTO>()
.ForMember(t => t.TrialCode, u => u.MapFrom(t => t.Trial.Code))
.ForMember(t => t.ReviewMode, u => u.MapFrom(t => t.Trial.ReviewMode.Value))
.ForMember(t => t.Cro, u => u.MapFrom(t => t.Trial.CRO.CROName))
.ForMember(t => t.Cro, u => u.MapFrom(t => t.Trial.CRO))
.ForMember(t => t.Indication, u => u.MapFrom(t => t.Trial.Indication))
.ForMember(t => t.Expedited, u => u.MapFrom(t => t.Trial.Expedited))
.ForMember(t => t.DoctorsNames, u => u.MapFrom(t => string.Join(',', t.Trial.EnrollList.Select(t => t.Doctor.ChineseName))))

View File

@ -42,6 +42,7 @@ namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
public List<InstanceBasicInfo> InstanceInfoList { get; set; } = new List<InstanceBasicInfo>();
public bool IsExistMutiFrames => InstanceInfoList.Any(t => t.NumberOfFrames > 1);

View File

@ -56,7 +56,7 @@ namespace IRaCIS.Core.Application.Services
}
var anonymizeList = await _fusionCache.GetOrSetAsync(CacheKeys.SystemAnonymization, _ => CacheHelper.GetSystemAnonymizationListAsync(_systemAnonymizationRepository), TimeSpan.FromDays(7));
var anonymizeList = await _fusionCache.GetOrSetAsync(CacheKeys.SystemAnonymization, async _ => await CacheHelper.GetSystemAnonymizationListAsync(_systemAnonymizationRepository), TimeSpan.FromDays(7));
var fixedFiledList = anonymizeList.Where(t => t.IsFixed).ToList();
var ircFiledList = anonymizeList.Where(t => t.IsFixed == false).ToList();

View File

@ -782,7 +782,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
// 写入dicom 固定的信息,以及组织路径的信息 以及匿名化的信息
var otherData = GetSaveToDicomInfo(verifyInfo.SubjectVisitId);
var anonymizeList = _fusionCache.GetOrSetAsync(CacheKeys.SystemAnonymization, _ => CacheHelper.GetSystemAnonymizationListAsync(_systemAnonymizationRepository), TimeSpan.FromDays(7)).Result;
var anonymizeList = _fusionCache.GetOrSetAsync(CacheKeys.SystemAnonymization, async _ => await CacheHelper.GetSystemAnonymizationListAsync(_systemAnonymizationRepository), TimeSpan.FromDays(7)).Result;
return ResponseOutput.Ok<List<VerifyStudyUploadResult>>(result, new
{

View File

@ -445,6 +445,9 @@ namespace IRaCIS.Core.Application.Service.Inspection.DTO
/// </summary>
public decimal? VisitPlanInfo { get; set; }
public string? VisitName { get; set; }
/// <summary>
/// 开始时间
/// </summary>

View File

@ -190,6 +190,8 @@ namespace IRaCIS.Core.Application.Service.Inspection
.WhereIf(!inQuery.TaskName.IsNullOrEmpty(), x => x.TaskName.Contains(inQuery.TaskName) || x.BlindName.Contains(inQuery.TaskName))
.WhereIf(!inQuery.SubjectInfo.IsNullOrEmpty(), x => x.SubjectCode.Contains(inQuery.SubjectInfo))
.WhereIf(!inQuery.RoleName.IsNullOrEmpty(), x => x.RoleName.Contains(inQuery.RoleName))
.WhereIf(!inQuery.VisitName.IsNullOrEmpty(), x => x.VisitName.Contains(inQuery.VisitName))
//.WhereIf(dto.VisitPlanInfo != null&& dto.VisitPlanInfo!=(decimal) 1.11, x => x.VisitNum == dto.VisitPlanInfo)
//.WhereIf(dto.VisitPlanInfo != (decimal)1.11,x=>x.InPlan!=null&& x.InPlan==false)
.WhereIf(inQuery.StartTime != null, x => x.CreateTime >= inQuery.StartTime)

View File

@ -0,0 +1,53 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-03-21 01:28:34Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using IRaCIS.Core.Domain.Share;
using System.Collections.Generic;
namespace IRaCIS.Core.Application.ViewModel;
public class HIRHospitalView : HIRHospitalAddOrEdit
{
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
}
public class HIRHospitalAddOrEdit
{
public Guid? Id { get; set; }
public string HospitalName { get; set; }
public string HospitalAliasName { get; set; }
public string Country { get; set; }
public string City { get; set; }
public string Province { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public bool IsCanConnectInternet { get; set; }
public string HospitalCode { get; set; }
public string HospitalLogoPath { get; set; }
public int TrialKeepCount { get; set; }
public bool IsDefault { get; set; }
}
public class HIRHospitalQuery : PageInput
{
public string HospitalName { get; set; }
public string Country { get; set; }
public string City { get; set; }
public string Province { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
}

View File

@ -22,6 +22,32 @@ namespace IRaCIS.Application.Contracts
public Guid? UserId { get; set; }
}
public class TJUserInfoDto
{
public string Code { get; set; }
public string Msg { get; set; }
public bool Success { get; set; }
public TJUserInfoData Data { get; set; }
}
public class TJUserInfoData
{
public string UserCode { get; set; }
public string UserName { get; set; }
public string DeptCode { get; set; }
public string Sex { get; set; }
public string Birthday { get; set; }
public string Title { get; set; }
public string UserType { get; set; }
public List<string> Roles { get; set; }
}
public class LoginReturnDTO
{
public UserBasicInfo BasicInfo { get; set; } = new UserBasicInfo();
@ -31,6 +57,26 @@ namespace IRaCIS.Application.Contracts
public SystemEmailSendConfigView CompanyInfo { get; set; }
public bool IsMutiAccount => AccountList?.Count > 1;
public List<UserAccountInfo> AccountList { get; set; }
}
public class UserAccountInfo
{
public Guid Id { get; set; }
public string UserName { get; set; } = string.Empty;
public string FullName { get; set; } = string.Empty;
public string Phone { get; set; } = string.Empty;
public string EMail { get; set; } = string.Empty;
public Guid UserTypeId { get; set; }
public UserTypeEnum UserTypeEnum { get; set; }
public string UserTypeShortName { get; set; }
public int Status { get; set; }
}
public class UserBasicInfo
@ -120,10 +166,14 @@ namespace IRaCIS.Application.Contracts
public class UserDetailDTO : UserInfo
{
public bool CanEditUserType { get; set; }
public bool IsMutiAccount => AccountList?.Count > 1;
public List<UserAccountInfo> AccountList { get; set; }
}
public class UserInfo
{
public string CheckCode { get; set; } = string.Empty;
public Guid Id { get; set; }
public string UserName { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
@ -194,6 +244,8 @@ namespace IRaCIS.Application.Contracts
public string NewPassWord { get; set; } = string.Empty;
public string OldPassWord { get; set; } = string.Empty;
public string CheckCode { get; set; } = string.Empty;
}

View File

@ -9,6 +9,8 @@ namespace IRaCIS.Core.Application.Service
Task<IResponseOutput> DeleteUser(Guid userId);
Task<UserDetailDTO> GetUser(Guid id);
Task<PageOutput<UserListDTO>> GetUserList(UserListQueryDTO param);
Task<IResponseOutput<LoginReturnDTO>> LoginSelectUserType(Guid userId, Guid userTypeId);
Task<IResponseOutput<LoginReturnDTO>> Login(string userName, string password);
Task<IResponseOutput> VerifyMFACodeAsync(Guid userId, string Code);

View File

@ -1,7 +1,10 @@
using IP2Region.Net.Abstractions;
using DocumentFormat.OpenXml.Spreadsheet;
using IP2Region.Net.Abstractions;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Auth;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Helper.OtherTool;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
@ -9,6 +12,7 @@ using Medallion.Threading;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using NPOI.SS.Formula.Functions;
using Panda.DynamicWebApi.Attributes;
using System.Text.RegularExpressions;
using ZiggyCreatures.Caching.Fusion;
@ -27,12 +31,14 @@ namespace IRaCIS.Core.Application.Service
IRepository<Trial> _trialRepository,
IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig,
IRepository<HIRHospital> _hirHospitalRepository,
ITokenService _tokenService,
ISearcher _searcher, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, IUserService
{
private SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
private async Task VerifyUserNameAsync(Guid? userId, string userName)
{
if (await _userRepository.WhereIf(userId != null, t => t.Id != userId).AnyAsync(t => t.UserName == userName))
@ -237,8 +243,6 @@ namespace IRaCIS.Core.Application.Service
}
[HttpGet]
public async Task<IResponseOutput> InitSetUserNameAndPwd(Guid userId, string newUserName, string newPWd)
{
@ -275,11 +279,17 @@ namespace IRaCIS.Core.Application.Service
[UnitOfWork]
public async Task<IResponseOutput> ResetPassword(Guid userId)
{
var pwd = IRCEmailPasswordHelper.GenerateRandomPassword(10);
var hospitalInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Hospital,async _ => await CacheHelper.GetHospitalCode(_hirHospitalRepository), TimeSpan.FromDays(7));
await _mailVerificationService.AdminResetPwdSendEmailAsync(userId, pwd);
//var pwd = IRCEmailPasswordHelper.GenerateRandomPassword(10);
var pwd = "123456";
if (hospitalInfo.IsCanConnectInternet)
{
await _mailVerificationService.AdminResetPwdSendEmailAsync(userId, pwd);
}
await _userRepository.UpdatePartialFromQueryAsync(userId, u => new User()
{
@ -337,50 +347,6 @@ namespace IRaCIS.Core.Application.Service
}
/// <summary>
/// 验证验证码,没问题就返回用户所有的账户
/// </summary>
/// <param name="email"></param>
/// <param name="verifyCode"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[AllowAnonymous]
[HttpGet("{email}/{verifyCode}")]
public async Task<List<UserAccountDto>> VerifyAnonymousVerifyCode(string email, string verifyCode)
{
var verificationRecord = await _verificationCodeRepository
.Where(t => t.UserId == Guid.Empty && t.Code == verifyCode && t.CodeType == VerifyType.Email && t.EmailOrPhone == email).OrderByDescending(t => t.CreateTime).FirstOrDefaultAsync();
//检查数据库是否存在该验证码
if (verificationRecord == null)
{
//---验证码错误。
throw new BusinessValidationFailedException(_localizer["User_VerificationCodeError"]);
}
else
{
//检查验证码是否失效
if (verificationRecord.ExpirationTime < DateTime.Now)
{
//---验证码已经过期。
throw new BusinessValidationFailedException(_localizer["User_VerificationCodeExpired"]);
}
else //验证码正确 并且 没有超时
{
//删除验证码历史记录
await _verificationCodeRepository.BatchDeleteNoTrackingAsync(t => t.Id == verificationRecord.Id);
}
}
var list = await _userRepository.Where(t => t.EMail == email && t.Status == UserStateEnum.Enable).Select(t => new UserAccountDto() { UserId = t.Id, UserName = t.UserName, UserRealName = t.FullName, UserType = t.UserTypeRole.UserTypeShortName }).ToListAsync();
return list;
}
/// <summary>
@ -397,7 +363,7 @@ namespace IRaCIS.Core.Application.Service
await VerifyUserPwdAsync(userId, newPwd);
var success = await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == userId, u => new User()
await _userRepository.UpdatePartialFromQueryAsync(t => t.Id == userId, u => new User()
{
Password = newPwd,
IsFirstAdd = false
@ -405,47 +371,11 @@ namespace IRaCIS.Core.Application.Service
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = userId, OptUserId = userId, LoginPassword = newPwd, OptType = UserOptType.UnloginModifyPasswoed }, true);
return ResponseOutput.Result(success);
return ResponseOutput.Ok();
}
/// <summary>
/// 修改密码,当前支持旧密码修改密码
/// </summary>
/// <returns></returns>
[HttpPost]
[UnitOfWork]
public async Task<IResponseOutput> ModifyPassword(EditPasswordCommand editPwModel)
{
await VerifyUserPwdAsync(_userInfo.Id, editPwModel.NewPassWord, editPwModel.OldPassWord);
if (!string.IsNullOrEmpty(editPwModel.NewUserName))
{
await VerifyUserNameAsync(_userInfo.Id, editPwModel.NewUserName);
await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == _userInfo.Id, u => new User()
{
UserName = editPwModel.NewUserName,
});
}
var success = await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == _userInfo.Id, u => new User()
{
Password = editPwModel.NewPassWord,
IsFirstAdd = false
});
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = _userInfo.Id, OptType = UserOptType.LoginModifyPassword }, true);
return ResponseOutput.Result(success);
}
@ -471,6 +401,7 @@ namespace IRaCIS.Core.Application.Service
.WhereIf(inQuery.UserState != null, t => t.Status == inQuery.UserState)
.WhereIf(inQuery.IsTestUser != null, t => t.IsTestUser == inQuery.IsTestUser)
.WhereIf(inQuery.IsZhiZhun != null, t => t.IsZhiZhun == inQuery.IsZhiZhun)
.WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.OA, t => t.UserTypeEnum != UserTypeEnum.Admin)
.ProjectTo<UserListDTO>(_mapper.ConfigurationProvider);
return await userQueryable.ToPagedListAsync(inQuery);
@ -486,7 +417,12 @@ namespace IRaCIS.Core.Application.Service
public async Task<UserDetailDTO> GetUser(Guid id)
{
var userQuery = _userRepository.Where(t => t.Id == id).ProjectTo<UserDetailDTO>(_mapper.ConfigurationProvider);
return await (userQuery.FirstOrDefaultAsync()).IfNullThrowException();
var result = await (userQuery.FirstOrDefaultAsync()).IfNullThrowException();
result.AccountList = _userRepository.Where(t => t.EMail == result.EMail && t.UserTypeEnum != UserTypeEnum.SuperAdmin)
.ProjectTo<UserAccountInfo>(_mapper.ConfigurationProvider).OrderBy(t => t.UserTypeShortName).ToList();
return result;
}
/// <summary>
@ -497,6 +433,7 @@ namespace IRaCIS.Core.Application.Service
[UnitOfWork]
public async Task<IResponseOutput<UserAddedReturnDTO>> AddUser(UserCommand userAddModel)
{
var hospitalInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Hospital, async _ => await CacheHelper.GetHospitalCode(_hirHospitalRepository), TimeSpan.FromDays(7));
await VerifyUserNameAsync(null, userAddModel.UserName);
@ -516,23 +453,27 @@ namespace IRaCIS.Core.Application.Service
saveItem.UserCode = AppSettings.GetCodeStr(saveItem.Code, nameof(User));
if (saveItem.IsZhiZhun)
{
var organizationName = _userInfo.IsEn_Us ? _systemEmailConfig.OrganizationName : _systemEmailConfig.OrganizationNameCN;
//if (saveItem.IsZhiZhun)
//{
// var organizationName = _userInfo.IsEn_Us ? _systemEmailConfig.OrganizationName : _systemEmailConfig.OrganizationNameCN;
saveItem.OrganizationName = organizationName;
}
// saveItem.OrganizationName = organizationName;
//}
// IRCEmailPasswordHelper.GenerateRandomPassword(10)
saveItem.Password = MD5Helper.Md5(IRCEmailPasswordHelper.GenerateRandomPassword(10));
saveItem.Password = MD5Helper.Md5("123456");
await _userRepository.AddAsync(saveItem);
var success = await _userRepository.SaveChangesAsync();
}
if (hospitalInfo.IsCanConnectInternet)
{
await _mailVerificationService.AddUserSendEmailAsync(saveItem.Id, userAddModel.BaseUrl, userAddModel.RouteUrl);
await _mailVerificationService.AddUserSendEmailAsync(saveItem.Id, userAddModel.BaseUrl, userAddModel.RouteUrl);
}
return ResponseOutput.Ok(new UserAddedReturnDTO { Id = saveItem.Id, UserCode = saveItem.UserCode });
@ -558,7 +499,7 @@ namespace IRaCIS.Core.Application.Service
if (user == null) return Null404NotFound(user);
if (user.Status!=model.Status)
if (user.Status != model.Status)
{
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = model.Id, OptType = model.Status == UserStateEnum.Enable ? UserOptType.AccountEnable : UserOptType.AccountLocked }, true);
@ -567,14 +508,14 @@ namespace IRaCIS.Core.Application.Service
_mapper.Map(model, user);
if (user.IsZhiZhun)
{
user.OrganizationName = _userInfo.IsEn_Us ? _systemEmailConfig.OrganizationName : _systemEmailConfig.OrganizationNameCN;
}
//if (user.IsZhiZhun)
//{
// user.OrganizationName = _userInfo.IsEn_Us ? _systemEmailConfig.OrganizationName : _systemEmailConfig.OrganizationNameCN;
//}
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = model.Id, OptType = UserOptType.UpdateUser });
var success = await _userRepository.SaveChangesAsync();
@ -695,6 +636,158 @@ namespace IRaCIS.Core.Application.Service
return ResponseOutput.Ok();
}
/// <summary>
/// 同济生成账号
/// </summary>
/// <param name="token"></param>
/// <param name="_userTypeRepository"></param>
/// <param name="_hirHospitalRepository"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpGet]
public async Task<IResponseOutput> TJUserLoginInfo(string token,
[FromServices] IRepository<UserType> _userTypeRepository,
[FromServices] IRepository<HIRHospital> _hirHospitalRepository)
{
#region MyRegion
//同济医院token 地址http://192.168.40.88:8080 appid:third-hirs
//本地测试地址接口
var apiUrl = "http://192.168.40.88:8080/dock/userinfo";
var headers = new Dictionary<string, string>
{
{ "Content-Type", "application/json" } // 根据需要添加其他头部信息
};
var requestData = new
{
token = token,
appId = "third-hirs",
};
var tjUserInfo = await RestClientAPI.PostAsync<TJUserInfoDto>(apiUrl, requestData, headers);
#endregion
#region 测试数据
//var tjUserInfo = new TJUserInfoDto
//{
// Code = "200",
// Msg = "操作成功",
// Success = true,
// Data = new TJUserInfoData
// {
// UserCode = "YS10138",
// UserName = "胡学梅",
// DeptCode = "2121",
// Sex = "未知",
// Birthday = "",
// Title = "",
// UserType = "doctor",
// Roles = new List<string> { "pm", "crc" }
// }
//};
#endregion
var generateRoles = new List<string>() { "PM", "CRC", "SR", "PI", "QA" };
if (tjUserInfo != null && tjUserInfo.Data?.Roles != null &&
tjUserInfo.Data.Roles.Any(role => generateRoles.Any(gRole => string.Equals(gRole, role, StringComparison.OrdinalIgnoreCase))))
{
var sysUserTypeList = _userTypeRepository.Where().Select(t => new { t.UserTypeShortName, t.UserTypeEnum, t.Id }).ToList();
var matchedRoles = generateRoles.Where(role => tjUserInfo.Data.Roles.Any(r => string.Equals(r, role, StringComparison.OrdinalIgnoreCase))).ToList();
var hospital = await _hirHospitalRepository.Where(t => t.IsDefault == true).ProjectTo<HIRHospitalView>(_mapper.ConfigurationProvider).FirstNotNullAsync();
var thirdUId = tjUserInfo.Data.UserCode;
var email = $"{tjUserInfo.Data.UserCode}@tjhir.com";
var @lock = _distributedLockProvider.CreateLock($"UserAccount");
using (await @lock.AcquireAsync())
{
//匹配的角色 都匹配一遍账号,没有便生成
foreach (var roleName in matchedRoles)
{
var userType = sysUserTypeList.Where(t => t.UserTypeShortName == roleName).First();
var userTypeId = userType.Id;
if (!_userRepository.Any(t => t.ThirdUserCode == thirdUId && t.UserTypeId == userTypeId))
{
var newCode = await _userRepository.Select(t => t.Code).DefaultIfEmpty().MaxAsync() + 1;
var newUser = new User()
{
FirstName = $"{tjUserInfo.Data.UserName}",
LastName = "tj",
IsFirstAdd = false,
IsZhiZhun = true,
OrganizationName = hospital.HospitalName,
Code = newCode,
Password = MD5Helper.Md5("123456"),
CheckCode = "123456",
UserCode = AppSettings.GetCodeStr(newCode, nameof(User)),
UserTypeId = userTypeId,
UserTypeEnum = userType.UserTypeEnum,
EMail = email,
UserName = $"{tjUserInfo.Data.UserName}-{roleName}",
ThirdUserCode = thirdUId,
};
await _userRepository.AddAsync(newUser);
}
}
await _userRepository.SaveChangesAsync();
}
//返回该账号的在系统的中的所有角色,如果单个角色,就直接登录,如果是多个角色,那么前端进行选择后进行登录
var accountList = _userRepository.Where(t => t.EMail == email && t.UserTypeEnum != UserTypeEnum.SuperAdmin)
.ProjectTo<UserAccountInfo>(_mapper.ConfigurationProvider).OrderBy(t => t.UserTypeShortName).ToList();
var hirToken = _tokenService.GetToken(IRaCISClaims.Create(new UserBasicInfo() { Id = Guid.NewGuid(), UserName = tjUserInfo.Data.UserName }));
return ResponseOutput.Ok(accountList, hirToken);
}
else
{
return ResponseOutput.NotOk("跳转系统对接的用户未配置当前系统的角色,无法自动生成账号,请联系管理员配置该跳转账户信息");
}
}
[NonDynamicMethod]
public async Task<IResponseOutput<LoginReturnDTO>> LoginSelectUserType(Guid userId, Guid userTypeId)
{
var userNamePwd = await _userRepository.Where(t => t.Id == userId && t.UserTypeId == userTypeId).Select(t => new { t.UserName, t.Password }).FirstNotNullAsync();
return await Login(userNamePwd.UserName, userNamePwd.Password);
}
/// <summary>
/// 用户登陆
/// </summary>
@ -801,6 +894,9 @@ namespace IRaCIS.Core.Application.Service
});
userLoginReturnModel.AccountList = _userRepository.Where(t => t.EMail == userLoginReturnModel.BasicInfo.EMail && t.UserTypeEnum != UserTypeEnum.SuperAdmin)
.ProjectTo<UserAccountInfo>(_mapper.ConfigurationProvider).ToList();
return ResponseOutput.Ok(userLoginReturnModel);
}
@ -841,5 +937,124 @@ namespace IRaCIS.Core.Application.Service
return ResponseOutput.Ok();
}
#region HIR 修改
/// <summary>
/// 验证验证码,没问题就返回用户所有的账户
/// </summary>
/// <param name="email"></param>
/// <param name="verifyCode"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[AllowAnonymous]
[HttpGet("{email}/{verifyCode}")]
public async Task<List<UserAccountDto>> VerifyAnonymousVerifyCode(string email, string verifyCode)
{
var hospitalInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Hospital, async _ => await CacheHelper.GetHospitalCode(_hirHospitalRepository), TimeSpan.FromDays(7));
if (hospitalInfo.IsCanConnectInternet)
{
var verificationRecord = await _verificationCodeRepository
.Where(t => t.UserId == Guid.Empty && t.Code == verifyCode && t.CodeType == VerifyType.Email && t.EmailOrPhone == email).OrderByDescending(t => t.CreateTime).FirstOrDefaultAsync();
//检查数据库是否存在该验证码
if (verificationRecord == null)
{
//---验证码错误。
throw new BusinessValidationFailedException(_localizer["User_VerificationCodeError"]);
}
else
{
//检查验证码是否失效
if (verificationRecord.ExpirationTime < DateTime.Now)
{
//---验证码已经过期。
throw new BusinessValidationFailedException(_localizer["User_VerificationCodeExpired"]);
}
else //验证码正确 并且 没有超时
{
//删除验证码历史记录
await _verificationCodeRepository.BatchDeleteNoTrackingAsync(t => t.Id == verificationRecord.Id);
}
}
}
else
{
var isPass = _userRepository.Where(t => t.EMail == email).Any(t => t.CheckCode == verifyCode);
if (!isPass)
{
throw new BusinessValidationFailedException(_localizer["User_VerificationCodeError"]);
}
}
var list = await _userRepository.Where(t => t.EMail == email).Select(t => new UserAccountDto() { UserId = t.Id, UserName = t.UserName, UserRealName = t.FullName, UserType = t.UserTypeRole.UserTypeShortName }).ToListAsync();
return list;
}
[HttpPut("{newCheckCode}")]
public async Task<IResponseOutput> SetNewCheckCode(string newCheckCode)
{
var user = await _userRepository.FirstOrDefaultNoTrackingAsync(t => t.Id == _userInfo.Id);
await _userRepository.UpdatePartialFromQueryAsync(t => t.EMail == user.EMail, u => new User()
{
CheckCode = newCheckCode
});
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = _userInfo.Id, OptType = UserOptType.ModifyCheckCode }, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 修改密码,当前支持旧密码修改密码
/// </summary>
/// <returns></returns>
[HttpPost]
[UnitOfWork]
public async Task<IResponseOutput> ModifyPassword(EditPasswordCommand editPwModel)
{
await VerifyUserPwdAsync(_userInfo.Id, editPwModel.NewPassWord, editPwModel.OldPassWord);
if (!string.IsNullOrEmpty(editPwModel.NewUserName))
{
await VerifyUserNameAsync(_userInfo.Id, editPwModel.NewUserName);
await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == _userInfo.Id, u => new User()
{
UserName = editPwModel.NewUserName,
});
}
await _userRepository.UpdatePartialFromQueryAsync(t => t.Id == _userInfo.Id, u => new User()
{
Password = editPwModel.NewPassWord,
CheckCode = editPwModel.CheckCode,
IsFirstAdd = false
});
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = _userInfo.Id, OptType = UserOptType.LoginModifyPassword }, true);
return ResponseOutput.Ok();
}
#endregion
}
}

View File

@ -91,7 +91,7 @@ namespace IRaCIS.Core.Application.Contracts
}
#region HIR 修改
/// <summary>
/// 通过传递场景枚举 返回对应的下拉框数据 1是外部 2是内部 3是Site调研 4: 邮件接收人5邮件抄送人
@ -105,49 +105,53 @@ namespace IRaCIS.Core.Application.Contracts
if (userTypeSelectEnum == UserTypeSelectEnum.ExternalUser)
{
userTypeEnums = new List<UserTypeEnum>() { UserTypeEnum.CPM, UserTypeEnum.SPM, UserTypeEnum.CPM, UserTypeEnum.SMM, UserTypeEnum.CMM, UserTypeEnum.EA, UserTypeEnum.MC };
}
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.TA)
{
userTypeEnums = new List<UserTypeEnum>() { UserTypeEnum.ProjectManager };
}
else
{
userTypeEnums = new List<UserTypeEnum>() { UserTypeEnum.PI, UserTypeEnum.MIM, UserTypeEnum.IQC };
}
if (userTypeSelectEnum == UserTypeSelectEnum.InnerUser)
{
userTypeEnums = new List<UserTypeEnum>() { UserTypeEnum.ClinicalResearchCoordinator, UserTypeEnum.ProjectManager, UserTypeEnum.CRA, UserTypeEnum.IQC, UserTypeEnum.APM, UserTypeEnum.MIM, UserTypeEnum.QA, UserTypeEnum.MW, UserTypeEnum.MC };
//if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.SuperAdmin)
//{
// userTypeEnums.Add(UserTypeEnum.ProjectManager);
//}
}
if (userTypeSelectEnum == UserTypeSelectEnum.SiteSurvey)
{
userTypeEnums = new List<UserTypeEnum>() { UserTypeEnum.CRA, UserTypeEnum.ClinicalResearchCoordinator };
userTypeEnums = new List<UserTypeEnum>() { UserTypeEnum.SR, UserTypeEnum.ClinicalResearchCoordinator, UserTypeEnum.CRA };
}
if (userTypeSelectEnum == UserTypeSelectEnum.EnrollOrPD_EMailCopy)
{
userTypeEnums = new List<UserTypeEnum>() { UserTypeEnum.ProjectManager, UserTypeEnum.APM, UserTypeEnum.CPM, UserTypeEnum.SPM, UserTypeEnum.SMM, UserTypeEnum.CMM };
userTypeEnums = new List<UserTypeEnum>() { UserTypeEnum.ProjectManager, UserTypeEnum.APM, UserTypeEnum.CPM, UserTypeEnum.SPM };
}
if (userTypeSelectEnum == UserTypeSelectEnum.EnrollOrPD_EmailReceive)
{
userTypeEnums = new List<UserTypeEnum>() { UserTypeEnum.CRA, UserTypeEnum.ClinicalResearchCoordinator };
}
if (userTypeSelectEnum == UserTypeSelectEnum.TrialDoc)
{
userTypeEnums = new List<UserTypeEnum>() { UserTypeEnum.PI, UserTypeEnum.SR, UserTypeEnum.ProjectManager, UserTypeEnum.TA, UserTypeEnum.IQC, UserTypeEnum.IM, UserTypeEnum.MIM };
}
var query = _userTypeRepository.Where(x => x.UserTypeEnum != UserTypeEnum.SuperAdmin)
.WhereIf(userTypeSelectEnum != UserTypeSelectEnum.None, t => userTypeEnums.Contains(t.UserTypeEnum))
.OrderBy(t => t.UserTypeShortName).ProjectTo<TrialUserType>(_mapper.ConfigurationProvider);
var query = _userTypeRepository/*.Where(x => x.UserTypeEnum != UserTypeEnum.SuperAdmin)*/
.WhereIf(userTypeSelectEnum != UserTypeSelectEnum.None && userTypeEnums.Count > 0, t => userTypeEnums.Contains(t.UserTypeEnum))
.OrderBy(t => t.Order).ProjectTo<TrialUserType>(_mapper.ConfigurationProvider);
return await query.ToListAsync();
}
#endregion

View File

@ -136,6 +136,11 @@ namespace IRaCIS.Core.Application.Service
;
CreateMap<UserFeedBackAddOrEdit, UserFeedBack>().ReverseMap();
CreateMap<User, UserAccountInfo>()
.ForMember(d => d.UserTypeShortName, c => c.MapFrom(t => t.UserTypeRole.UserTypeShortName));
}
}

View File

@ -356,6 +356,8 @@ namespace IRaCIS.Core.Application.Contracts.DTO
}
public class QAStudyInfoDTO
{
public string PatientIdStr { get; set; }
public string PatientName { get; set; }
public bool IsDeleted { get; set; }
public string StudyInstanceUid { get; set; } = string.Empty;

View File

@ -1184,8 +1184,8 @@ namespace IRaCIS.Core.Application.Contracts
//在当前访视触发裁判,或者在截止日期小于等于当前访视的阅片期触发裁判
[DictionaryTranslateAttribute("YesOrNo")]
public bool IsTrigerJudge { get; set; }
[DictionaryTranslateAttribute("YesOrNoAudit")]
public bool? IsTrigerJudge { get; set; }
//(如果是访视点裁判,则仅在所选阅片人对应访视 显示;如果是阅片期裁判,则在所选阅片人 阅片期内的所有访视 显示此原因)
public string JudgeNote { get; set; } = string.Empty;

View File

@ -771,7 +771,7 @@ namespace IRaCIS.Core.Application.Image.QA
var succeess2 = await _dicomInstanceRepository.BatchDeleteNoTrackingAsync(t => t.StudyId == id);
var success3 = await _dicomSeriesrepository.BatchDeleteNoTrackingAsync(t => t.StudyId == id);
await _scpStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == id, u => new SCPStudy() { SubjectVisitId = null });
//await _scpStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == id, u => new SCPStudy() { SubjectVisitId = null });
@ -797,17 +797,17 @@ namespace IRaCIS.Core.Application.Image.QA
}
var subjectId = waitDeleteStudyList.Select(t => t.SubjectId).FirstOrDefault();
//var subjectId = waitDeleteStudyList.Select(t => t.SubjectId).FirstOrDefault();
var patientList = _scpPatientRepository.Where(t => t.SubjectId == subjectId).Select(t => t.Id).ToList();
//var patientList = _scpPatientRepository.Where(t => t.SubjectId == subjectId).Select(t => t.Id).ToList();
foreach (var patientId in patientList)
{
if (_scpPatientRepository.Where(t => t.Id == patientId).Any(t => t.SCPStudyList.Count() == t.SCPStudyList.Where(t => t.SubjectVisitId == null).Count()))
{
await _scpPatientRepository.BatchUpdateNoTrackingAsync(t => t.Id == patientId, u => new SCPPatient() { SubjectId = null });
}
}
//foreach (var patientId in patientList)
//{
// if (_scpPatientRepository.Where(t => t.Id == patientId).Any(t => t.SCPStudyList.Count() == t.SCPStudyList.Where(t => t.SubjectVisitId == null).Count()))
// {
// await _scpPatientRepository.BatchUpdateNoTrackingAsync(t => t.Id == patientId, u => new SCPPatient() { SubjectId = null });
// }
//}

View File

@ -255,7 +255,7 @@ namespace IRaCIS.Core.Application.Service
false)))
.ForMember(o => o.JudgeNote, t => t.MapFrom(u => u.JudgeVisitTask.JudgeResultRemark))
.ForMember(o => o.VisitNote, t => t.MapFrom(u => u.ReadingTaskQuestionAnswerList.Where(c => c.ReadingQuestionTrial.QuestionType == QuestionType.AdjustReason).FirstOrDefault()!.Answer))
.ForMember(o => o.TrialSiteCode, t => t.MapFrom(u => u.Subject.TrialSite.TrialSiteCode))
//.ForMember(o => o.TrialSiteCode, t => t.MapFrom(u => u.Subject.TrialSite.TrialSiteCode))
.ForMember(o => o.SubjectCode, t => t.MapFrom(u => u.Subject.Code))
.ForMember(o => o.UserName, t => t.MapFrom(u => u.DoctorUser.UserName))
.ForMember(o => o.QuestionAnswerList, t => t.MapFrom(u => u.ReadingTaskQuestionAnswerList

View File

@ -0,0 +1,404 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Service.Reading.Dto
{
public class TumorEvaluationInfo
{
public List<ExportTumorEvaluationInfo> VisitList { get; set; }
}
public class ExportTumorEvaluationInfo
{
/// <summary>
/// 所有访视的靶病灶列表
/// </summary>
public List<ExportVisitData> VisitList { get; set; }
public bool IsLastPage { get; set; } = false;
/// <summary>
/// 受试者Code
/// </summary>
public string SubjectCode { get; set; } =string.Empty;
public string SubjectName { get; set; } = string.Empty;
public string ResearchProgramNo { get; set; } = string.Empty;
public ExportData Lesion { get; set; }=new ExportData();
/// <summary>
/// 访视一
/// </summary>
public ExportVisitData VisitOne
{
get
{
return VisitList[0];
}
}
/// <summary>
/// 访视二
/// </summary>
public ExportVisitData VisitTwo
{
get
{
if (VisitList.Count >= 2)
{
return VisitList[1];
}
else
{
return new ExportVisitData();
}
}
}
/// <summary>
/// 访视三
/// </summary>
public ExportVisitData VisitThree
{
get
{
if (VisitList.Count >= 3)
{
return VisitList[2];
}
else
{
return new ExportVisitData();
}
}
}
/// <summary>
/// 靶病灶信息
/// </summary>
public List<TargetInfo> TargetInfoList
{
get
{
List<TargetInfo> targets=new List<TargetInfo>();
var index = 0;
foreach (var item in VisitOne.VisitTargetInfoList)
{
TargetInfo targetInfo = new TargetInfo()
{
Title = item.Title,
VisitOneImgNum = item.VisitImgNum,
VisitOneLength = item.VisitLength.ToString(),
VisitTwoImgNum = VisitList.Count >= 2 ? VisitTwo.VisitTargetInfoList[index].VisitImgNum : string.Empty,
VisitTwoLength = VisitList.Count >= 2 ? VisitTwo.VisitTargetInfoList[index].VisitLength.ToString() : string.Empty,
VisitThreeImgNum = VisitList.Count >= 3 ? VisitThree.VisitTargetInfoList[index].VisitImgNum : string.Empty,
VisitThreeLength = VisitList.Count >= 3 ? VisitThree.VisitTargetInfoList[index].VisitLength.ToString() : string.Empty
};
targets.Add(targetInfo);
index++;
}
return targets;
}
}
/// <summary>
/// 非靶病灶信息
/// </summary>
public List<TargetInfo> NoTargetInfoList
{
get
{
List<TargetInfo> targets = new List<TargetInfo>();
var index = 0;
foreach (var item in VisitOne.VisitNoTargetInfoList)
{
TargetInfo targetInfo = new TargetInfo()
{
Title = item.Title,
VisitOneImgNum = item.VisitImgNum,
VisitOneLength = item.VisitLength!=null? item.VisitLength.Value.ToString():string.Empty,
VisitTwoImgNum = VisitList.Count >= 2 ? VisitTwo.VisitNoTargetInfoList[index].VisitImgNum : string.Empty,
VisitTwoLength = VisitList.Count >= 2&& VisitTwo.VisitNoTargetInfoList[index].VisitLength!=null ? VisitTwo.VisitNoTargetInfoList[index].VisitLength.Value.ToString() : string.Empty,
VisitThreeImgNum = VisitList.Count >= 3 ? VisitThree.VisitNoTargetInfoList[index].VisitImgNum : string.Empty,
VisitThreeLength = VisitList.Count >= 3&& VisitThree.VisitNoTargetInfoList[index].VisitLength!=null ? VisitThree.VisitNoTargetInfoList[index].VisitLength.Value.ToString() : string.Empty
};
targets.Add(targetInfo);
index++;
}
return targets;
}
}
}
public class TargetInfo
{
public string Title { get; set; } = string.Empty;
public string VisitOneImgNum { get; set; } = string.Empty;
public string VisitOneLength { get; set; } = string.Empty;
public string VisitTwoImgNum { get; set; } = string.Empty;
public string VisitTwoLength { get; set; } = string.Empty;
public string VisitThreeImgNum { get; set; } = string.Empty;
public string VisitThreeLength { get; set; } = string.Empty;
}
public class ExportData
{
public string OneVisitName { get; set; } = string.Empty;
public string OneCheckDate { get; set; } = string.Empty;
public string OneCheckInfoStr { get; set; } = string.Empty;
public string OneTargetSum { get; set; } = string.Empty;
public string OneHaveNewLesion { get; set; } = string.Empty;
public string OneTargetResult { get; set; } = string.Empty;
public string OneNoTargetResult { get; set; } = string.Empty;
public string OneOverallResult { get; set; } = string.Empty;
public string OneDoctorSignTime { get; set; } = string.Empty;
public string TwoVisitName { get; set; } = string.Empty;
public string TwoCheckDate { get; set; } = string.Empty;
public string TwoCheckInfoStr { get; set; } = string.Empty;
public string TwoTargetSum { get; set; } = string.Empty;
public string TwoHaveNewLesion { get; set; } = string.Empty;
public string TwoTargetResult { get; set; } = string.Empty;
public string TwoNoTargetResult { get; set; } = string.Empty;
public string TwoOverallResult { get; set; } = string.Empty;
public string TwoDoctorSignTime { get; set; } = string.Empty;
public string ThreeVisitName { get; set; } = string.Empty;
public string ThreeCheckDate { get; set; } = string.Empty;
public string ThreeCheckInfoStr { get; set; } = string.Empty;
public string ThreeTargetSum { get; set; } = string.Empty;
public string ThreeHaveNewLesion { get; set; } = string.Empty;
public string ThreeTargetResult { get; set; } = string.Empty;
public string ThreeNoTargetResult { get; set; } = string.Empty;
public string ThreeOverallResult { get; set; } = string.Empty;
public string ThreeDoctorSignTime { get; set; } = string.Empty;
}
public class ExportVisitData
{
/// <summary>
/// 访视名称
/// </summary>
public string VisitName { get; set; } = string.Empty;
/// <summary>
/// 访视序号
/// </summary>
public decimal VisitNum { get; set; }
/// <summary>
/// 检查日期
/// </summary>
public string CheckDate { get; set; } = string.Empty;
/// <summary>
/// 检查信息
/// </summary>
public List<DicomStudyInfo> CheckInfoList { get; set; } = new List<DicomStudyInfo>();
/// <summary>
/// 检查信息字符串
/// </summary>
public string CheckInfoStr => string.Join("", CheckInfoList.Select(x => $"{x.Modalities}/{x.BodyPartExamined}"));
/// <summary>
/// 是否有新病灶
/// </summary>
public string HaveNewLesion { get; set; } = string.Empty;
/// <summary>
/// 靶病灶结果
/// </summary>
public string TargetResult { get; set; } = string.Empty;
/// <summary>
/// 非靶病灶结果
/// </summary>
public string NoTargetResult { get; set; } = string.Empty;
/// <summary>
/// 总体结果
/// </summary>
public string OverallResult { get; set; } = string.Empty;
/// <summary>
/// 医生名称
/// </summary>
public string DoctorName { get; set; } = string.Empty;
/// <summary>
/// 签名时间
/// </summary>
public string SignTime { get; set; } = string.Empty;
/// <summary>
/// 医生签名时间
/// </summary>
public string DoctorSignTime
{
get
{
return DoctorName==string.Empty?string.Empty: $"{DoctorName}/{SignTime}";
}
}
/// <summary>
/// 靶病灶信息
/// </summary>
public List<VisitLesionInfo> VisitTargetInfoList { get; set; } = new List<VisitLesionInfo>();
/// <summary>
/// 靶病灶总长度
/// </summary>
public decimal? TargetSum
{
get
{
return VisitTargetInfoList.Sum(x => x.VisitLength);
}
}
/// <summary>
/// 非靶病灶信息
/// </summary>
public List<VisitLesionInfo> VisitNoTargetInfoList { get; set; } = new List<VisitLesionInfo>();
}
public class VisitLesionInfo
{
/// <summary>
/// 序号
/// </summary>
public string RowMark { get; set; } = string.Empty;
/// <summary>
/// 器官
/// </summary>
public string Organ { get; set; } = string.Empty;
/// <summary>
/// 部位
/// </summary>
public string Part { get; set; } = string.Empty;
public int Number { get; set; }
public string Title {
get
{
if (RowMark != string.Empty)
{
return $"{Number}{RowMark}{Organ}{Part}";
}
else
{
return $"{Number}";
}
}
}
/// <summary>
/// 检查号
/// </summary>
public int StudyCode { get; set; }
public Guid? RowId { get; set; }
/// <summary>
/// 序列号
/// </summary>
public int SeriesNumber { get; set; }
/// <summary>
/// 图像号
/// </summary>
public int InstanceNumber { get; set; }
/// <summary>
/// 图像号
/// </summary>
public string VisitImgNum
{
get
{
if (RowId == null)
{
return string.Empty;
}
else
{
return $"{StudyCode}/{SeriesNumber}/{InstanceNumber}";
}
}
}
/// <summary>
/// 长度
/// </summary>
public decimal? VisitLength { get; set; }
}
public class DicomStudyInfo
{
/// <summary>
/// 检查类型
/// </summary>
public string Modalities { get; set; } = string.Empty;
/// <summary>
/// 标记
/// </summary>
public string BodyPartExamined { get; set; }
}
}

View File

@ -291,6 +291,32 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public List<string> SheetNames { get; set; }
}
public class ExportReportQuestion
{
public string QuestionName { get; set; }
public QuestionType QuestionType { get; set; }
}
public class DownLoadReadReportInDto
{
/// <summary>
/// 任务Id
/// </summary>
public Guid VisitTaskId { get; set; }
public Guid DownLoadGuid { get; set; }
}
/// <summary>
/// 阅片计算Dto
/// </summary>

View File

@ -446,6 +446,24 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
}
public class CaGetVisitReadReportUrl
{
/// <summary>
/// 任务Id
/// </summary>
public Guid VisitTaskId { get; set; }
}
public class GenerateReadingReportInDto
{
/// <summary>
/// 任务Id
/// </summary>
public Guid VisitTaskId { get; set; }
}
public class GetPreviousOtherPicturePathInDto
{

View File

@ -41,5 +41,7 @@ namespace IRaCIS.Core.Application.Contracts
Task<List<GetReadingPastResultListOutDto>> GetReadingPastResultList(GetReadingPastResultListInDto inDto);
Task<(List<GetRelatedVisitTaskOutDto>, object)> GetRelatedVisitTask(GetRelatedVisitTaskInDto inDto);
}
}

View File

@ -127,7 +127,8 @@ namespace IRaCIS.Core.Application.Service
&& x.ReadingCategory == ReadingCategory.Visit
&& x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId
&& x.DoctorUserId == taskInfo.DoctorUserId &&
&&
//x.DoctorUserId == taskInfo.DoctorUserId &&
x.ReadingTaskState == ReadingTaskState.HaveSigned &&
x.ReReadingApplyState != ReReadingApplyState.Agree
).OrderBy(x => x.VisitTaskNum).Select(x => new TaskInfo()
@ -155,7 +156,7 @@ namespace IRaCIS.Core.Application.Service
&& x.ReadingCategory == ReadingCategory.Visit
&& x.IsAnalysisCreate == taskInfo.IsAnalysisCreate
&& x.IsSelfAnalysis == taskInfo.IsSelfAnalysis
&& x.DoctorUserId != taskInfo.DoctorUserId
&& x.ArmEnum != taskInfo.ArmEnum
&& x.ReadingTaskState == ReadingTaskState.HaveSigned
&& x.ReReadingApplyState != ReReadingApplyState.Agree)
.OrderBy(x => x.VisitTaskNum).Select(x => new TaskInfo()
@ -204,7 +205,7 @@ namespace IRaCIS.Core.Application.Service
List<TaskInfo> otherTask = await _visitTaskRepository.Where(x =>
x.SouceReadModuleId == taskInfo.SouceReadModuleId
&& x.SourceSubjectVisitId == taskInfo.SourceSubjectVisitId
&& x.DoctorUserId != taskInfo.DoctorUserId
&& x.ArmEnum != taskInfo.ArmEnum
&& x.IsAnalysisCreate == taskInfo.IsAnalysisCreate
&& x.IsSelfAnalysis == taskInfo.IsSelfAnalysis
&& x.ReadingTaskState == ReadingTaskState.HaveSigned
@ -259,7 +260,7 @@ namespace IRaCIS.Core.Application.Service
&& (x.ReadingCategory == ReadingCategory.Global || x.ReadingCategory == ReadingCategory.Judge)
&& x.IsAnalysisCreate == taskInfo.IsAnalysisCreate
&& x.IsSelfAnalysis == taskInfo.IsSelfAnalysis
&& x.DoctorUserId == taskInfo.DoctorUserId
&& x.ArmEnum == taskInfo.ArmEnum
&& x.ReadingTaskState == ReadingTaskState.HaveSigned
&& x.ReReadingApplyState != ReReadingApplyState.Agree)
.Select(x => new

View File

@ -244,7 +244,7 @@ namespace IRaCIS.Core.Application.Service
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
[TypeFilter(typeof(TrialResourceFilter))]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> AddOrUpdateReadingMedicineTrialQuestion(ReadingMedicineTrialQuestionAddOrEdit inDto)
{
var existsQuery = _readingMedicineTrialQuestionRepository

View File

@ -170,7 +170,7 @@ namespace IRaCIS.Core.Application.Service
var otherGlobalTask = await _visitTaskRepository.Where(x => x.SouceReadModuleId == taskInfo.SouceReadModuleId && x.IsAnalysisCreate == taskInfo.IsAnalysisCreate
&& x.IsSelfAnalysis == taskInfo.IsSelfAnalysis && x.TaskState == TaskState.Effect && x.DoctorUserId != taskInfo.DoctorUserId
&& x.IsSelfAnalysis == taskInfo.IsSelfAnalysis && x.TaskState == TaskState.Effect && x.ArmEnum != taskInfo.ArmEnum
).FirstOrDefaultAsync();
if (otherGlobalTask != null)
{
@ -196,7 +196,7 @@ namespace IRaCIS.Core.Application.Service
&& x.ReadingCategory == ReadingCategory.Judge
&& x.IsAnalysisCreate == taskInfo.IsAnalysisCreate
&& x.IsSelfAnalysis == taskInfo.IsSelfAnalysis
&& x.DoctorUserId == taskInfo.DoctorUserId
//&& x.DoctorUserId == taskInfo.DoctorUserId
&& x.ReadingTaskState == ReadingTaskState.HaveSigned
&& x.VisitTaskNum == taskInfo.VisitTaskNum + ReadingCommon.TaskNumDic[ReadingCategory.Judge]
&& x.ReReadingApplyState != ReReadingApplyState.Agree).FirstOrDefaultAsync();
@ -219,7 +219,7 @@ namespace IRaCIS.Core.Application.Service
x.IsAnalysisCreate == taskInfo.IsAnalysisCreate &&
x.ArmEnum == taskInfo.ArmEnum &&
x.IsSelfAnalysis == taskInfo.IsSelfAnalysis &&
x.DoctorUserId == taskInfo.DoctorUserId &&
x.ArmEnum == taskInfo.ArmEnum &&
x.TaskState == TaskState.Effect &&
x.VisitTaskNum < taskInfo.VisitTaskNum);
@ -334,7 +334,7 @@ namespace IRaCIS.Core.Application.Service
var lastGlobalTask = await _visitTaskRepository.Where(x => x.ReadingCategory == ReadingCategory.Global &&
x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId &&
x.SubjectId == taskInfo.SubjectId && x.IsAnalysisCreate == taskInfo.IsAnalysisCreate && x.TaskState == TaskState.Effect && x.VisitTaskNum < taskInfo.VisitTaskNum)
.Where(x => x.DoctorUserId == taskInfo.DoctorUserId)
.Where(x => x.ArmEnum == taskInfo.ArmEnum)
.OrderByDescending(x => x.VisitTaskNum)
.FirstOrDefaultAsync();

View File

@ -68,6 +68,58 @@ namespace IRaCIS.Core.Application.Service
/// <summary>
/// 下载阅片报告
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<FileResult> DownLoadReadReport(DownLoadReadReportInDto inDto)
{
return await _readingCalculateService.DownLoadReadReport(inDto);
}
/// <summary>
/// 获取阅片报告
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<string> GetVisitReadReportUrl(GenerateReadingReportInDto inDto)
{
return await _readingCalculateService.GetVisitReadReportUrl(new CaGetVisitReadReportUrl()
{
VisitTaskId = inDto.VisitTaskId,
});
}
/// <summary>
/// 下载瘤评估
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<FileResult> DownTumorEvaluation(DownLoadReadReportInDto inDto)
{
return await _readingCalculateService.DownLoadTumorEvaluation(inDto);
}
/// <summary>
/// 获取肿瘤评估
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<string> GetTumorEvaluationUrl(GenerateReadingReportInDto inDto)
{
return await _readingCalculateService.GetTumorEvaluationReportUrl(new CaGetVisitReadReportUrl()
{
VisitTaskId = inDto.VisitTaskId,
});
}
#region 计算
/// <summary>
@ -490,7 +542,7 @@ namespace IRaCIS.Core.Application.Service
(x.TrialId == taskInfo.TrialId &&
x.SubjectId == taskInfo.SubjectId &&
x.ArmEnum == taskInfo.ArmEnum &&
x.DoctorUserId == taskInfo.DoctorUserId &&
//x.DoctorUserId == taskInfo.DoctorUserId &&
x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId &&
x.TaskState == TaskState.Effect &&
@ -605,7 +657,7 @@ namespace IRaCIS.Core.Application.Service
x.VisitTaskNum < taskInfo.VisitTaskNum &&
x.ArmEnum == taskInfo.ArmEnum &&
x.Id != inDto.VisitTaskId &&
x.DoctorUserId == taskInfo.DoctorUserId &&
//x.DoctorUserId == taskInfo.DoctorUserId &&
x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId &&
x.ReadingTaskState == ReadingTaskState.HaveSigned &&
x.TaskState == TaskState.Effect &&
@ -729,7 +781,7 @@ namespace IRaCIS.Core.Application.Service
if (await _visitTaskRepository.AnyAsync(x => x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId
&& x.IsAnalysisCreate && taskInfo.IsAnalysisCreate
&& x.SubjectId == taskInfo.SubjectId && x.TaskState == TaskState.Effect &&
((x.ReReadingApplyState == ReReadingApplyState.DocotorHaveApplyed && x.DoctorUserId == taskInfo.DoctorUserId) || x.ReReadingApplyState == ReReadingApplyState.TrialGroupHaveApplyed)
((x.ReReadingApplyState == ReReadingApplyState.DocotorHaveApplyed && x.ArmEnum == taskInfo.ArmEnum) || x.ReReadingApplyState == ReReadingApplyState.TrialGroupHaveApplyed)
))
{
@ -818,7 +870,7 @@ namespace IRaCIS.Core.Application.Service
var laskTaskId = await _visitTaskRepository.Where(x =>
(x.SubjectId == taskInfo.SubjectId && x.TaskState == TaskState.Effect
&& x.IsAnalysisCreate == taskInfo.IsAnalysisCreate
&& x.DoctorUserId == taskInfo.DoctorUserId
&& x.ArmEnum == taskInfo.ArmEnum
&& x.IsSelfAnalysis == taskInfo.IsSelfAnalysis
&& x.VisitTaskNum < taskInfo.VisitTaskNum
&& x.ArmEnum == taskInfo.ArmEnum
@ -1208,7 +1260,7 @@ namespace IRaCIS.Core.Application.Service
var baselineTaskId = await _visitTaskRepository.Where(x => x.SourceSubjectVisitId == baseLineVisitId
&& x.ArmEnum == taskInfo.ArmEnum
&& x.DoctorUserId == taskInfo.DoctorUserId
&& x.ArmEnum == taskInfo.ArmEnum
&& x.IsAnalysisCreate == taskInfo.IsAnalysisCreate
&& x.TaskState == TaskState.Effect
&& x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId
@ -1219,7 +1271,7 @@ namespace IRaCIS.Core.Application.Service
var laskTaskId = await _visitTaskRepository.Where(x =>
(x.SubjectId == taskInfo.SubjectId && x.TaskState == TaskState.Effect
&& x.IsAnalysisCreate == taskInfo.IsAnalysisCreate
&& x.DoctorUserId == taskInfo.DoctorUserId
&& x.ArmEnum == taskInfo.ArmEnum
&& x.IsSelfAnalysis == taskInfo.IsSelfAnalysis
&& x.VisitTaskNum < taskInfo.VisitTaskNum
&& x.ArmEnum == taskInfo.ArmEnum
@ -2105,7 +2157,7 @@ namespace IRaCIS.Core.Application.Service
.Where(x => x.IsAnalysisCreate == taskinfo.IsAnalysisCreate &&
x.SubjectId == taskinfo.SubjectId &&
x.ReadingCategory == taskinfo.ReadingCategory &&
x.DoctorUserId == taskinfo.DoctorUserId &&
x.ArmEnum == taskinfo.ArmEnum &&
x.ArmEnum == taskinfo.ArmEnum &&
x.TrialReadingCriterionId == taskinfo.TrialReadingCriterionId &&
x.ReadingTaskState == ReadingTaskState.HaveSigned &&
@ -3163,6 +3215,7 @@ namespace IRaCIS.Core.Application.Service
await VerifyTaskIsSign(visitTaskId);
await _visitTaskRepository.UpdatePartialFromQueryAsync(visitTaskId, x => new VisitTask()
{
DoctorUserId = _userInfo.Id,
ReadingTaskState = ReadingTaskState.HaveSigned,
SignTime = DateTime.Now,
});
@ -3213,7 +3266,7 @@ namespace IRaCIS.Core.Application.Service
await _visitTaskRepository.SaveChangesAsync();
await _trialEmailNoticeConfigService.BaseBusinessScenarioSendEmailAsync(visitTaskId);
//await _trialEmailNoticeConfigService.BaseBusinessScenarioSendEmailAsync(visitTaskId);
}
@ -3255,7 +3308,7 @@ namespace IRaCIS.Core.Application.Service
x.SubjectId == taskInfo.SubjectId &&
x.VisitTaskNum < taskInfo.VisitTaskNum &&
x.ArmEnum == taskInfo.ArmEnum &&
x.DoctorUserId == taskInfo.DoctorUserId &&
//x.DoctorUserId == taskInfo.DoctorUserId &&
x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId &&
x.ReadingTaskState == ReadingTaskState.HaveSigned &&
x.TaskState == TaskState.Effect &&
@ -3273,7 +3326,7 @@ namespace IRaCIS.Core.Application.Service
x.SubjectId == taskInfo.SubjectId &&
x.VisitTaskNum <= taskInfo.VisitTaskNum &&
x.ArmEnum == taskInfo.ArmEnum &&
x.DoctorUserId == taskInfo.DoctorUserId &&
//x.DoctorUserId == taskInfo.DoctorUserId &&
x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId &&
x.ReadingTaskState == ReadingTaskState.HaveSigned &&
(x.TaskState == TaskState.Effect || x.TaskState == TaskState.Freeze) &&
@ -3296,7 +3349,7 @@ namespace IRaCIS.Core.Application.Service
x.IsAnalysisCreate == taskInfo.IsAnalysisCreate &&
x.ArmEnum == taskInfo.ArmEnum &&
x.IsSelfAnalysis == taskInfo.IsSelfAnalysis &&
x.DoctorUserId == taskInfo.DoctorUserId &&
//x.DoctorUserId == taskInfo.DoctorUserId &&
x.TaskState == TaskState.Effect && x.VisitTaskNum <= taskInfo.VisitTaskNum).Select(x => x.Id).ToListAsync();
break;
case ReadingCategory.Oncology:
@ -3324,7 +3377,7 @@ namespace IRaCIS.Core.Application.Service
x.ArmEnum == taskInfo.ArmEnum &&
x.IsSelfAnalysis == taskInfo.IsSelfAnalysis &&
x.BlindSubjectCode == taskInfo.BlindSubjectCode &&
x.DoctorUserId == taskInfo.DoctorUserId &&
//x.DoctorUserId == taskInfo.DoctorUserId &&
x.TaskState == TaskState.Effect && x.Id != taskInfo.Id).Select(x => x.Id).ToListAsync();
break;

View File

@ -160,7 +160,7 @@ namespace IRaCIS.Core.Application.Service
x.IsAnalysisCreate == globalOrVisitTaskInfo.IsAnalysisCreate &&
x.ArmEnum == globalOrVisitTaskInfo.ArmEnum &&
x.IsSelfAnalysis == globalOrVisitTaskInfo.IsSelfAnalysis &&
x.DoctorUserId == globalOrVisitTaskInfo.DoctorUserId &&
x.ArmEnum == globalOrVisitTaskInfo.ArmEnum &&
x.TaskState == TaskState.Effect &&
x.VisitTaskNum <= globalOrVisitTaskInfo.VisitTaskNum)
.OrderBy(x => x.VisitTaskNum).Select(x => new GlobalVisitInfo()

View File

@ -3,12 +3,18 @@ using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore.Common;
using IRaCIS.Core.Infrastructure;
using MassTransit;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MiniExcelLibs;
using MiniSoftware;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using System.Data;
using System.IO;
using System.Reflection;
using System.Text;
namespace IRaCIS.Core.Application.Service.ReadingCalculate
@ -17,14 +23,16 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
IRepository<VisitTask> _visitTaskRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
ILogger<GeneralCalculateService> _logger,
IRepository<ReadingTableQuestionTrial> _readingTableQuestionTrialRepository,
IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository,
IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IOptionsMonitor<ObjectStoreServiceOptions> _options,
IRepository<TumorAssessment_RECIST1Point1> _tumorAssessmentRepository,
IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository,
IRepository<InspectionFile> _inspectionFileRepository,
IOSSService oSSService, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IGeneralCalculateService
IOSSService _oSSService, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IGeneralCalculateService
{
@ -71,7 +79,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
try
{
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/"+ pathCode, file.FileName);
var ossRelativePath = await _oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/"+ pathCode, file.FileName);
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = file.FileName, RelativePath = ossRelativePath, TrialId = trialId });
}
catch (Exception)
@ -432,7 +440,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
.Where(x => (x.SubjectId == visitTaskInfo.SubjectId
&& (x.TaskState == TaskState.Effect || x.TaskState == TaskState.Freeze)
&& x.IsAnalysisCreate == visitTaskInfo.IsAnalysisCreate
&& x.DoctorUserId == visitTaskInfo.DoctorUserId
&& x.ArmEnum == visitTaskInfo.ArmEnum
&& x.IsSelfAnalysis == visitTaskInfo.IsSelfAnalysis
&& x.VisitTaskNum <= visitTaskInfo.VisitTaskNum
&& x.ArmEnum == visitTaskInfo.ArmEnum
@ -482,5 +490,442 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
});
return taskInfoList;
}
/// <summary>
/// 空转为横线
/// </summary>
/// <param name="myDictionary"></param>
/// <returns></returns>
public Dictionary<string, object> StringEmptyTurnedLine(Dictionary<string, object> myDictionary)
{
foreach (var item in myDictionary)
{
if (item.Value == null)
{
myDictionary[item.Key] = "-";
}
else if (item.Value.GetType() == typeof(string))
{
if (item.Value.ToString() == string.Empty || item.Value == null)
{
myDictionary[item.Key] = "-";
};
}
else if (item.Value.GetType() == typeof(List<Dictionary<string, object>>))
{
var value = item.Value;
foreach (var column in value as List<Dictionary<string, object>>)
{
foreach (var item2 in column)
{
if (item2.Value.ToString() == string.Empty || item.Value == null)
{
column[item2.Key] = "-";
};
}
}
myDictionary[item.Key] = value;
}
}
return myDictionary;
}
/// <summary>
/// 获取word图片
/// </summary>
/// <param name="url"></param>
/// <param name="savePath"></param>
/// <param name="width"></param>
/// <returns></returns>
public async Task<MiniWordPicture> GetWordPicture(string url, string savePath, int width)
{
var resultUrl = await this.FileDownSave(url, savePath);
int picWidth = 0;
int picHeight = 0;
using (var bitmap = Image<Rgba32>.Load(resultUrl))
{
// 获取图片的宽度和高度
picWidth = bitmap.Width;
picHeight = bitmap.Height;
}
var height = width * picHeight / picWidth;
return new MiniWordPicture()
{
Path = resultUrl,
Height = height,
Width = width
};
}
/// <summary>
/// 获取word图片
/// </summary>
/// <param name="url"></param>
/// <param name="savePath"></param>
/// <param name="width"></param>
/// <returns></returns>
public async Task<MiniWordPicture> GetWordPicture(string url, string savePath, int width, int height)
{
var resultUrl = await this.FileDownSave(url, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"wwwroot/ReadReoprtTemplate/downLoad"));
return new MiniWordPicture()
{
Path = resultUrl,
Height = height,
Width = width
};
}
/// <summary>
/// 最大宽高
/// </summary>
/// <param name="url"></param>
/// <param name="savePath"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns></returns>
public async Task<MiniWordPicture> GetWordPictureMaxWL(string url, string savePath, int width, int height)
{
var resultUrl = await this.FileDownSave(url, savePath);
int picWidth = 0;
int picHeight = 0;
using (var bitmap = Image<Rgba32>.Load(resultUrl))
{
// 获取图片的宽度和高度
picWidth = bitmap.Width;
picHeight = bitmap.Height;
}
if (picWidth / picHeight > width / height)
{
height = width * picHeight / picWidth;
}
else
{
width = height * picWidth / picHeight;
}
return new MiniWordPicture()
{
Path = resultUrl,
Height = height,
Width = width
};
}
/// <summary>
/// 获取任务问题答案
/// </summary>
/// <param name="answerList">问题答案</param>
/// <param name="dictionList">字典数据</param>
/// <param name="unitDictionary">单位字典</param>
/// <param name="taskId">任务Id</param>
/// <param name="questionType">任务类型</param>
/// <returns></returns>
public string GetTaskanswer(List<ReadingTaskQuestionAnswer>? answerList, List<Dictionary>? dictionList, List<Dictionary>? unitDictionary, Guid taskId, QuestionType questionType)
{
var answerData = answerList.FirstOrDefault(x => x.VisitTaskId == taskId && x.ReadingQuestionTrial.QuestionType == questionType);
if (answerData == null || answerData.Answer == string.Empty)
{
return string.Empty;
}
var answer = string.Empty;
if (answerData.ReadingQuestionTrial.QuestionGenre == TableQuestionType.Dictionary)
{
answer = dictionList.Where(x => x.Code == answerData.ReadingQuestionTrial.DictionaryCode).SelectMany(x => x.ChildList).Where(x => x.Code == answerData.Answer).Select(x => x.ValueCN).FirstIsNullReturnEmpty();
}
else
{
answer = answerData.Answer;
}
if (answer != "NA" && answerData.ReadingQuestionTrial.Unit != null && answerData.ReadingQuestionTrial.Unit != ValueUnit.none)
{
answer += " " + unitDictionary.SelectMany(x => x.ChildList).Where(x => x.Code == ((int)answerData.ReadingQuestionTrial.Unit).ToString()).Select(x => x.ValueCN).FirstIsNullReturnEmpty();
}
if (answer != "NA" && answerData.ReadingQuestionTrial.ValueType == ValueOfType.Percentage)
{
answer += " %";
}
return answer;
}
public void SetPropertyDynamically(object targetObj, string targetPropName, object sourceObj, string prefix)
{
// 1. 解析目标属性名(如"CheckInfoStr"
string basePropName = targetPropName.Replace(prefix, "");
// 2. 获取源对象路径(如"VisitOne.CheckInfoStr"
string sourcePath = $"Visit{prefix}.{basePropName}";
object sourceValue = GetNestedPropertyValue(sourceObj, sourcePath);
// 3. 赋值给目标属性
PropertyInfo targetProp = targetObj.GetType().GetProperty(prefix+targetPropName);
if (targetProp != null && sourceValue != null)
{
targetProp.SetValue(targetObj, sourceValue);
}
}
public object GetNestedPropertyValue(object obj, string path)
{
foreach (string part in path.Split('.'))
{
if (obj == null) return null;
PropertyInfo prop = obj.GetType().GetProperty(part);
if (prop == null) return null;
obj = prop.GetValue(obj);
}
return obj;
}
/// <summary>
/// 获取报告No
/// </summary>
/// <param name="visitTaskInfo"></param>
/// <returns></returns>
public async Task<string> GetReportExportNo(VisitTask visitTaskInfo)
{
if (visitTaskInfo.ReportExportDate != null && visitTaskInfo.ReportExportNum != null)
{
return visitTaskInfo.ReportExportDate.Value.ToString("yyyyMMdd") + visitTaskInfo.ReportExportNum.ToString().PadLeft(4, '0');
}
else
{
DateTime today = DateTime.Today;
var reportExportNum = await _visitTaskRepository.Where(x => x.TrialId == visitTaskInfo.TrialId && x.ReportExportDate != null && x.ReportExportDate.Value.Date == today).MaxAsync(x => x.ReportExportNum);
reportExportNum = reportExportNum == null ? 0 : reportExportNum;
await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => x.Id == visitTaskInfo.Id, x => new VisitTask()
{
ReportExportDate = today,
ReportExportNum = reportExportNum + 1
});
return today.ToString("yyyyMMdd") + (reportExportNum + 1).ToString().PadLeft(4, '0');
}
}
/// <summary>
/// 获取并复制文件流
/// </summary>
/// <param name="outputFilePath"></param>
/// <returns></returns>
public Stream ReadAndReturnStream(string outputFilePath)
{
byte[] data;
using (Stream stream = new FileStream(outputFilePath, FileMode.Open, FileAccess.Read))
{
// 从流中读取数据保存到内存中
using (MemoryStream memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
data = memoryStream.ToArray();
}
}
// 返回内存中的数据作为新的流
return new MemoryStream(data);
}
/// <summary>
/// 下载并保存
/// </summary>
/// <param name="url">网络路径</param>
/// <param name="savePath">保存本地的文件夹</param>
/// <returns><placeholder>A <see cref="Task"/>
public async Task<string> FileDownSave(string url, string savePath)
{
#region 新
try
{
if (!string.IsNullOrWhiteSpace(url))
{
string[] strArry = url.Split('/');
savePath = savePath + "/" + strArry[strArry.Length - 1];
}
await _oSSService.DownLoadFromOSSAsync(url, savePath);
return savePath;
}
catch (Exception)
{
throw new BusinessValidationFailedException(_localizer["ReadingCalculate_ImageNotExist"]);
}
#endregion
#region 之前
// 之前需要有绝对路径
//try
//{
// HttpClient httpClient = new HttpClient();
// if (!string.IsNullOrWhiteSpace(url))
// {
// string[] strArry = url.Split('/');
// savePath = savePath + "/" + strArry[strArry.Length - 1];
// }
// var t = httpClient.GetByteArrayAsync(url);
// t.Wait();
// Stream responseStream = new MemoryStream(t.Result);
// Stream stream = new FileStream(savePath, FileMode.Create);
// byte[] bArr = new byte[1024];
// int size = responseStream.Read(bArr, 0, bArr.Length);
// while (size > 0)
// {
// stream.Write(bArr, 0, size);
// size = responseStream.Read(bArr, 0, bArr.Length);
// }
// stream.Close();
// responseStream.Close();
// return savePath;
//}
//catch (Exception)
//{
// throw new BusinessValidationFailedException(_localizer["ReadingCalculate_ImageNotExist"]);
//}
#endregion
}
/// <summary>
/// 获取任务表格问题答案
/// </summary>
/// <param name="tableAnswerList">表格答案</param>
/// <param name="dictionList">字典</param>
/// <param name="unitDictionary">单位字典</param>
/// <param name="taskId">任务Id</param>
/// <param name="lesionType">病灶类型</param>
/// <param name="questionMark">问题标识</param>
/// <param name="rowIndex">索引</param>
/// <returns></returns>
public string GetTaskTableAnswer(List<ReadingTableQuestionAnswer>? tableAnswerList, List<Dictionary>? dictionList, List<Dictionary>? unitDictionary, Guid taskId, LesionType lesionType, QuestionMark questionMark, decimal rowIndex,bool AutoUnit=true)
{
var answerData = tableAnswerList.FirstOrDefault(x => x.VisitTaskId == taskId && x.ReadingQuestionTrial.LesionType == lesionType && x.ReadingTableQuestionTrial.QuestionMark == questionMark && x.RowIndex == rowIndex);
if (answerData == null || answerData.Answer == string.Empty)
{
return string.Empty;
}
var answer = string.Empty;
if (answerData.ReadingTableQuestionTrial.TableQuestionType == TableQuestionType.Dictionary)
{
answer = dictionList.Where(x => x.Code == answerData.ReadingTableQuestionTrial.DictionaryCode).SelectMany(x => x.ChildList).Where(x => x.Code == answerData.Answer).Select(x => x.ValueCN).FirstIsNullReturnEmpty();
}
else
{
answer = answerData.Answer;
}
if (AutoUnit)
{
if (answer != "NA" && answerData.ReadingTableQuestionTrial.Unit != null && answerData.ReadingTableQuestionTrial.Unit != ValueUnit.none)
{
answer += " " + unitDictionary.SelectMany(x => x.ChildList).Where(x => x.Code == ((int)answerData.ReadingTableQuestionTrial.Unit).ToString()).Select(x => x.ValueCN).FirstIsNullReturnEmpty();
}
if (answer != "NA" && answerData.ReadingTableQuestionTrial.ValueType == ValueOfType.Percentage)
{
answer += " %";
}
}
return answer;
}
/// <summary>
/// 获取病灶的图片 rowinfoList要带question的信息
/// </summary>
/// <param name="rowinfoList"></param>
/// <param name="lesionType"></param>
/// <returns></returns>
public async Task<List<Dictionary<string, object>>> GetLesionPic(List<ReadingTableAnswerRowInfo> rowinfoList, LesionType lesionType, Guid DownLoadGuid)
{
var lesionRowinfo = rowinfoList.Where(x => x.PicturePath != string.Empty && x.ReadingQuestionTrial.LesionType == lesionType).OrderBy(x => x.VisitTask.VisitTaskNum).OrderBy(x => x.RowIndex).ToList();
List<Dictionary<string, object>> lesionImage = new List<Dictionary<string, object>>();
var lesionCount = lesionRowinfo.Select(x => x.VisitTask.VisitTaskNum).Distinct().OrderBy(x => x).ToList();
int picNum = 0;
foreach (var num in lesionCount)
{
var picRowinfo = lesionRowinfo.Where(x => x.VisitTask.VisitTaskNum == num).OrderBy(x => x.RowIndex).ToList();
var picCount = picRowinfo.Count();
for (int i = 0; i < Math.Ceiling((double)picCount / 2); i++)
{
lesionImage.Add(new Dictionary<string, object>()
{
{ "ImageOneMark",getPicNum(true)+ picRowinfo[2*i].VisitTask.TaskName+" "+picRowinfo[2*i].RowMark},
{ "ImageOneUrl" ,await GetWordPictureMaxWL(picRowinfo[2*i].PicturePath ,System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{DownLoadGuid}"),290,390) },
{ "ImageTwoMark",getPicNum(picCount>2*i+1) + (picCount<=2*i+1?string.Empty:picRowinfo[2*i+1].VisitTask.TaskName+" "+picRowinfo[2*i+1].RowMark) },
{ "ImageTwoUrl", picCount<=2*i+1?string.Empty:await GetWordPictureMaxWL(picRowinfo[2*i+1].PicturePath ,System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{DownLoadGuid}"),290, 390) },
});
}
}
string getPicNum(bool isHavePic)
{
if (isHavePic)
{
picNum += 1;
return $"图{picNum} ";
}
else
{
return string.Empty;
}
}
return lesionImage;
}
}
}

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