Compare commits

..

725 Commits

Author SHA1 Message Date
hang da57773cd3 邮箱验证修改
continuous-integration/drone/push Build is passing
2024-05-31 17:42:59 +08:00
hang d3c2ded3d4 返回 SliceThickness
continuous-integration/drone/push Build is passing
2024-05-31 15:56:29 +08:00
hang 37e7ab575f Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-05-31 15:39:31 +08:00
hang 39a9a0c05d 日志遗漏接口
continuous-integration/drone/push Build is passing
2024-05-31 09:09:28 +08:00
hang 570c5863c0 ip所在地遗漏
continuous-integration/drone/push Build is passing
2024-05-30 16:04:42 +08:00
hang 343f9211e2 区域 依赖注入
continuous-integration/drone/push Build is passing
2024-05-30 15:57:53 +08:00
hang 4b7fff9869 修改日志区域
continuous-integration/drone/push Build is passing
2024-05-30 15:53:16 +08:00
hang 1b1ac3ee65 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-05-28 17:39:04 +08:00
he 37b4860668 修改
continuous-integration/drone/push Build is passing
2024-05-28 14:44:54 +08:00
he 96f3ecb45d 代码提交
continuous-integration/drone/push Build is passing
2024-05-28 14:33:15 +08:00
he 4966a32bcb 问题修改
continuous-integration/drone/push Build is passing
2024-05-27 15:07:46 +08:00
he 07dcb6fe47 稽查翻译修改
continuous-integration/drone/push Build is passing
2024-05-24 14:55:24 +08:00
he f802897b14 修改
continuous-integration/drone/push Build is passing
2024-05-23 16:19:20 +08:00
he 0642b9e4fb Merge branch 'Test.Study' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-05-23 15:01:17 +08:00
he f945793d6d 稽查翻译修改 2024-05-23 15:01:16 +08:00
hang 7b4eb7a459 修改Study 加急设置
continuous-integration/drone/push Build is passing
2024-05-23 13:50:46 +08:00
hang 5fbebe9cc0 一致性核查通过自动关闭质疑
continuous-integration/drone/push Build is passing
2024-05-23 11:16:09 +08:00
hang 6feb2b20f8 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-05-23 09:15:26 +08:00
hang 2f87048f65 修改导表格式 2024-05-23 09:15:26 +08:00
he 5e613fd9d3 Merge branch 'Test.Study' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-05-23 09:08:30 +08:00
he 3fa4db75d0 异常修改 2024-05-23 09:08:29 +08:00
hang 0c4bc87ee9 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-05-23 09:00:15 +08:00
hang 6fb0562a0b 修改邮箱验证正则 2024-05-23 09:00:15 +08:00
he 10fc07ec03 修改
continuous-integration/drone/push Build is passing
2024-05-22 17:56:28 +08:00
he 400421a337 修改
continuous-integration/drone/push Build is passing
2024-05-22 17:53:31 +08:00
he 4983def85b Merge branch 'Test.Study' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-05-22 17:49:01 +08:00
he d60a2567c1 修改 2024-05-22 17:48:59 +08:00
hang 2cd9716e68 修改临床数据维护
continuous-integration/drone/push Build is passing
2024-05-22 17:39:28 +08:00
hang 1cf0ac0c53 临床数据bug
continuous-integration/drone/push Build is passing
2024-05-22 09:42:26 +08:00
hang 74dd5369cb 增加查询条件
continuous-integration/drone/push Build is passing
2024-05-20 17:43:18 +08:00
hang 9d6a046d7f 清理多余的字段
continuous-integration/drone/push Build is passing
2024-05-20 15:36:10 +08:00
hang a31eef5ccd 修改评估结果
continuous-integration/drone/push Build is passing
2024-05-20 15:34:24 +08:00
hang 21beeecb7d Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-05-20 15:19:31 +08:00
hang c5c3c3334d 缓存清理 2024-05-20 15:19:29 +08:00
he 92008fe6ba Merge branch 'Test.Study' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-05-20 15:10:02 +08:00
he 138a967283 修改 2024-05-20 15:10:01 +08:00
hang ed72ed9a5e 自定义阅片显示评估结果
continuous-integration/drone/push Build is passing
2024-05-20 15:04:25 +08:00
hang 5d0dca121f 修改site 和hospital 以及增加字段
continuous-integration/drone/push Build is passing
2024-05-20 14:34:35 +08:00
hang 3d656dfa17 修改提交事务地点
continuous-integration/drone/push Build is passing
2024-05-16 14:25:55 +08:00
hang 7adb291a0f 先一致性核查,再确认标准的时候,批量生成任务的时候,前序任务是否需要签名但是没签名状态有误
continuous-integration/drone/push Build is passing
2024-05-16 14:02:20 +08:00
hang 3c790965fe 阅片界面调整-查询条件 2024-05-15 13:27:39 +08:00
hang da4fe122ab 重阅跟踪修改 2024-05-15 13:27:14 +08:00
hang e029f32bad 迁移study 打包
continuous-integration/drone/push Build is failing
2024-05-06 14:00:43 +08:00
hang 4320f06b77 x 2024-04-17 10:06:51 +08:00
hang ac43952c18 修改测试环境存放bucket 2024-04-17 09:59:42 +08:00
hang 5ef97ff742 修改PI 自动审核通过的 2024-04-15 17:01:32 +08:00
hang 2c8056c77b 设置访视上入组和pd默认值 2024-04-15 16:17:17 +08:00
hang 5ac6e186c0 修改中心调研bug 需要迁移 2024-04-10 14:54:56 +08:00
hang e4e02225c5 稽查排序修改,需要迁移 2024-04-08 17:40:01 +08:00
hang 72b21fc021 study 列表修改
continuous-integration/drone/push Build is passing
2024-04-07 15:01:47 +08:00
he b8175c8ed5 修改 2024-04-02 13:09:17 +08:00
hang 885b115927 修改访视默认值 2024-03-19 10:45:54 +08:00
hang 776c8f5c5e 修改阅片任务查询 2024-03-19 10:05:17 +08:00
hang 5564d8cc42 一致性分析修改 2024-03-06 14:09:19 +08:00
hang 2b9d3785d6 修改生产配置文件
continuous-integration/drone/push Build is passing
2024-02-02 17:40:19 +08:00
hang 46db19f513 修改邮件bug
continuous-integration/drone/push Build is passing
2024-02-02 15:22:25 +08:00
hang 3a479fe724 修改邮件发送
continuous-integration/drone/push Build is passing
2024-02-02 15:20:34 +08:00
hang a1afb299b3 修改邮件发送bug 2024-02-02 15:03:37 +08:00
hang c54074dd3d Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-02-01 16:54:24 +08:00
he 203bce15ea 修改查询阅片图像
continuous-integration/drone/push Build is passing
2024-02-01 13:40:37 +08:00
he c1096ae473 阅片图像查询修改
continuous-integration/drone/push Build is passing
2024-02-01 13:30:20 +08:00
hang f2cd5f35e3 [修改一致性核查模板] 2024-01-31 16:37:17 +08:00
hang 40afae1f37 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-01-31 11:05:38 +08:00
hang 845c532134 [修改subject 查询 不依赖系统site] 2024-01-31 11:04:36 +08:00
hang 8615c90ebe 【修改 查询写入dicom的信息】 2024-01-31 11:04:29 +08:00
he eb1d90e304 study去掉疲劳阅片
continuous-integration/drone/push Build is passing
2024-01-29 14:34:50 +08:00
hang 88f015183d [赋值study code dicom]
continuous-integration/drone/push Build is passing
2024-01-26 12:36:42 +08:00
hang 4f9560c3a6 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-01-26 11:11:59 +08:00
hang 9abb78400a [site搜索三个名字] 2024-01-26 09:41:03 +08:00
he 8f5e2c5b0c 添加LimitShow 限制显示
continuous-integration/drone/push Build is passing
2024-01-25 16:03:35 +08:00
he efe96203d9 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-01-25 16:00:35 +08:00
hang 65de94079a Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-01-25 15:52:57 +08:00
hang 6e706c4fc9 [上传监控增加字段] 2024-01-25 15:52:31 +08:00
hang 84e2e14b73 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-01-24 14:20:22 +08:00
hang 49d4a71f36 [修改回退] 2024-01-24 14:20:20 +08:00
hang 7dcf73176c 去掉内存缓存
continuous-integration/drone/push Build is passing
2024-01-24 12:28:33 +08:00
hang f9bf9d752c 测试
continuous-integration/drone/push Build is passing
2024-01-24 12:20:38 +08:00
hang acac7ec995 升级net8 准备
continuous-integration/drone/push Build is passing
2024-01-24 12:17:02 +08:00
hang 6cfcb9bfe1 修改测试
continuous-integration/drone/push Build is passing
2024-01-24 11:22:20 +08:00
hang 9adf2ad52b 请求前端国际化增加缓存-需要迁移 2024-01-24 11:21:47 +08:00
hang 403885ef3f 修改国际化取消权限限制 2024-01-24 11:21:43 +08:00
hang 7b1a0affbe 增加前端国际化修改 2024-01-24 11:21:32 +08:00
hang 85897f990d [邮件模板启用与否没用bug修复]
continuous-integration/drone/push Build is passing
2024-01-24 10:14:18 +08:00
hang be477818d7 [AWS 对接上传 需要传递文件大小] 2024-01-24 10:13:22 +08:00
hang 41bbb75407 [修改重传没有检查id] 2024-01-24 10:13:13 +08:00
hang fd9fdcb8be [修改医生bug 和site bug] 2024-01-24 10:13:06 +08:00
hang 0e8ecdaf46 [上传失败过,返回标志] 2024-01-24 10:12:22 +08:00
hang 81b033885e [上传监控增加字段] 2024-01-24 10:11:06 +08:00
hang fca2a81c66 [遗漏 get set] 2024-01-24 10:10:59 +08:00
hang 353f5df217 [修改上传,失败数量传递不准问题] 2024-01-24 10:10:54 +08:00
hang 4874533804 [增加默认值] 2024-01-24 10:10:48 +08:00
hang 025a8e7af1 [上传增加稽查字段]迁移 2024-01-24 10:10:40 +08:00
hang 79c5824051 统一日志记录信息 2024-01-24 10:08:32 +08:00
hang 2c47842e13 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study 2024-01-24 10:03:24 +08:00
hang 39d9cefda9 [上传监控修改,增加搜索条件] 2024-01-24 09:58:51 +08:00
hang 2c0d1cdc82 [邮件模板启用与否没用bug修复] 2024-01-24 09:55:22 +08:00
hang af77d5be56 修改邮件模板
continuous-integration/drone/push Build is passing
2024-01-22 11:09:19 +08:00
he f662a988e0 修改 2024-01-16 10:27:48 +08:00
hang b9cace17b2 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-01-15 16:10:46 +08:00
hang c8d0ef9043 修改study 配置文件 2024-01-15 16:10:44 +08:00
hang 2491fd1fff 请求前端国际化增加缓存-需要迁移 2024-01-11 18:03:25 +08:00
hang 7cc9731edf 修改国际化取消权限限制 2024-01-11 18:03:21 +08:00
hang ff333219d4 增加前端国际化修改 2024-01-11 18:03:16 +08:00
hang 0eae520f0d 适配AWS 和MinIO
continuous-integration/drone/push Build is passing
2024-01-11 17:59:49 +08:00
hang 0a2513245c 升级net8 模型要求严格了 2024-01-05 17:09:25 +08:00
hang f10cc0adbf 修改稽查上传文件路径
continuous-integration/drone/push Build is passing
2024-01-05 12:56:26 +08:00
hang 58b2f9c7a9 修改配置文件
continuous-integration/drone/push Build is passing
2024-01-05 12:40:13 +08:00
hang 472e744b6c 修改生产数据库
continuous-integration/drone/push Build is passing
2024-01-05 12:27:11 +08:00
hang 699df338c1 修改待阅列表 临床数据未签名但是可以做后续访视,生成任务逻辑遗漏
continuous-integration/drone/push Build is passing
2024-01-04 15:20:00 +08:00
hang a64127537e Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-01-04 12:16:39 +08:00
hang 2287c8869d 修改导表错误 2024-01-04 12:16:31 +08:00
he 0d8319feaa 代码修改
continuous-integration/drone/push Build is passing
2024-01-03 17:28:15 +08:00
he 676c5b0e74 再次修改
continuous-integration/drone/push Build is passing
2024-01-03 17:17:33 +08:00
he a76654c210 修改状态
continuous-integration/drone/push Build is passing
2024-01-03 17:08:39 +08:00
he 0a29d431dc 修改状态
continuous-integration/drone/push Build is passing
2024-01-03 16:58:43 +08:00
he 86562b39e3 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-01-03 16:47:51 +08:00
he 86fe43aa93 代码修改 修改阅片状态 2024-01-03 16:47:49 +08:00
hang 082998da09 修改监控导出
continuous-integration/drone/push Build is passing
2024-01-03 15:39:43 +08:00
hang d209a8de4d 修改中心调研导表
continuous-integration/drone/push Build is passing
2024-01-03 15:26:40 +08:00
he b1608812ec Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2024-01-03 14:24:57 +08:00
he 20c18d957a 阅片状态修改 2024-01-03 14:24:55 +08:00
hang 7a7011e7ef 打开文件修改监控
continuous-integration/drone/push Build is passing
2024-01-03 13:43:31 +08:00
hang 24a395f8c8 增加真实名字
continuous-integration/drone/push Build is passing
2024-01-03 13:42:01 +08:00
hang df2f179917 xx
continuous-integration/drone/push Build is passing
2024-01-03 13:39:17 +08:00
hang 1bcc831937 不监测修改
continuous-integration/drone/push Build is passing
2024-01-03 13:32:03 +08:00
hang 75bf85997a 禁止热更新
continuous-integration/drone/push Build is passing
2024-01-03 13:20:27 +08:00
hang 074cba906c xx
continuous-integration/drone/push Build is passing
2024-01-03 13:18:11 +08:00
hang 86db676df8 必须在镜像里面修改
continuous-integration/drone/push Build is passing
2024-01-03 13:12:36 +08:00
hang bc67f16735 docker 部署方式解决
continuous-integration/drone/push Build is passing
2024-01-03 12:13:47 +08:00
hang 3e046e24e9 增加上传人
continuous-integration/drone/push Build is passing
2024-01-03 11:43:04 +08:00
hang c971161d31 修改utf-8
continuous-integration/drone/push Build is passing
2024-01-03 11:19:07 +08:00
hang a63904c0bb 暂时屏蔽
continuous-integration/drone/push Build is passing
2024-01-03 11:11:57 +08:00
hang 572d4ea4b8 修改docker-compose 文件打开文件修改跟踪
continuous-integration/drone/push Build is passing
2024-01-03 11:05:19 +08:00
hang ae4345cfcc x 监控文件错误 测试
continuous-integration/drone/push Build is passing
2024-01-03 10:06:30 +08:00
hang a536c33302 自动打包修改
continuous-integration/drone/push Build is passing
2024-01-03 09:29:07 +08:00
hang be5c9b636e 修改国际化邮件代码 2024-01-03 09:23:55 +08:00
hang c71bf65cd9 系统签名文档废除
continuous-integration/drone/push Build encountered an error
2023-12-29 17:36:08 +08:00
he 69c5ce9841 代码统计修改 查询数量 2023-12-29 17:36:00 +08:00
hang 2139193df4 清理裁判任务Id
continuous-integration/drone/push Build encountered an error
2023-12-29 17:35:11 +08:00
he 9aa2f23a67 修改代码 需要发study
continuous-integration/drone/push Build encountered an error
2023-12-28 13:25:02 +08:00
he 531e0fa228 计算小数位修改 需要同步study 2023-12-28 13:24:35 +08:00
hang 250c478687 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build encountered an error
2023-12-27 11:13:29 +08:00
hang 09ba37ec6d 修改测试环境数据库地址 2023-12-27 11:13:27 +08:00
hang 913b673b72 迁移修改
continuous-integration/drone/push Build is passing
2023-12-23 11:30:15 +08:00
hang 5ee8a3db21 迁移修改数据库连接地址
continuous-integration/drone/push Build is failing
2023-12-22 18:01:29 +08:00
hang 3c41789ba9 修改导表 5 2023-12-20 16:44:40 +08:00
hang d2268f0706 裁判任务失效的时候,清理裁判任务id 需要迁移 2023-12-20 16:44:36 +08:00
hang e8496df81a 修改模板文件位置 4 2023-12-20 16:43:49 +08:00
hang 3e24fe9461 修改路径bug 3 2023-12-20 16:43:45 +08:00
hang d771ab0f6f 修改文档删除2 2023-12-20 16:43:39 +08:00
hang 29dfa03d0f 修改导表时间格式2 2023-12-20 16:43:34 +08:00
hang 44e9b211c2 更新模板的时候,清理之前的文档,需要迁移 2023-12-20 16:43:29 +08:00
hang b1154ea594 修改导表时间格式 2023-12-20 16:43:25 +08:00
he 6dd12b419b 临床数据查询修改
continuous-integration/drone/push Build is passing
2023-12-13 09:57:18 +08:00
he bce7c1cc99 临床数据查询修改
continuous-integration/drone/push Build is failing
2023-12-13 09:51:24 +08:00
he a660eb4f37 临床数据修改 2023-12-13 09:51:17 +08:00
he 3ade13a922 临床数据修改
continuous-integration/drone/push Build is passing
2023-12-13 09:47:51 +08:00
he a5fed78c19 临床数据修改 2023-12-13 09:47:18 +08:00
he 5207fef130 医学审核加是否有临床数据 2023-12-13 09:47:07 +08:00
he b8ad8085cd Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2023-12-13 09:45:48 +08:00
hang dc8451f55c windows linux 环境路径修改 迁移
continuous-integration/drone/push Build is passing
2023-12-08 12:45:02 +08:00
hang dd9ec3d8fe 用户登录国际化
continuous-integration/drone/push Build is passing
2023-12-08 09:01:06 +08:00
hang 589cd83576 修改编码格式
continuous-integration/drone/push Build is passing
2023-12-07 10:27:59 +08:00
hang 6c2a1e0a4b 修改文件格式
continuous-integration/drone/push Build is passing
2023-12-07 10:02:32 +08:00
hang 7a927b3133 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2023-12-06 17:14:13 +08:00
hang 3dbf6dc897 修改为utf8 测试 2023-12-06 17:14:11 +08:00
he bb5401f78c 代码修改
continuous-integration/drone/push Build is passing
2023-12-06 16:55:49 +08:00
he 59e9d9df69 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2023-12-06 16:53:56 +08:00
hang 9a70193e7a hospital修改 需要迁移
continuous-integration/drone/push Build is passing
2023-12-06 16:12:59 +08:00
hang b44a9ecc63 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2023-12-06 11:48:25 +08:00
hang fb45173106 修改trigger 注入服务异常 2023-12-06 11:47:46 +08:00
hang bf2996bd1c 修改合并bug
continuous-integration/drone/push Build is passing
2023-12-05 17:33:28 +08:00
hang d840f14a2f x
continuous-integration/drone/push Build is passing
2023-12-05 16:11:24 +08:00
hang 4101c68d37 修改国际化
continuous-integration/drone/push Build is passing
2023-12-05 14:56:45 +08:00
hang 91503dc599 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study 2023-12-05 14:53:09 +08:00
hang debe22fdc3 清理无用的文件 2023-12-05 14:41:00 +08:00
hang 8f4f9a91c2 修改一致性核查国际化
continuous-integration/drone/push Build is passing
2023-12-05 13:59:21 +08:00
hang a53e306427 修改调研表 增加SR
continuous-integration/drone/push Build is passing
2023-12-05 11:03:58 +08:00
hang 02183affc3 修改study 生成用户类型
continuous-integration/drone/push Build is passing
2023-12-05 10:50:45 +08:00
hang e81c97037a 修改 验证 和生产配置文件
continuous-integration/drone/push Build is passing
2023-12-04 17:07:58 +08:00
hang 1fd02cbbc5 修改后端上传OSS 解析
continuous-integration/drone/push Build is passing
2023-12-04 15:32:25 +08:00
hang 55cbbffba6 oss 直接返回secret
continuous-integration/drone/push Build is passing
2023-12-04 11:35:34 +08:00
hang 4a1bf759cf OSS 大写改为小写 2023-12-04 11:31:22 +08:00
hang 703ab03b7f 阿里云临时token改为直接返回token和秘钥 2023-12-04 11:29:42 +08:00
he 0582390b2c 代码修改
continuous-integration/drone/push Build is passing
2023-12-04 09:27:43 +08:00
he cdf1119764 缓存时间修改 需要同步 2023-12-04 09:27:32 +08:00
hang 72cb407766 删除无用的服务
continuous-integration/drone/push Build is passing
2023-12-01 14:15:20 +08:00
hang 9f80386a19 修改警告4 2023-12-01 14:13:22 +08:00
hang 3a96710210 修改警告7 2023-12-01 14:12:45 +08:00
hang b8b63e33b8 修改警告6 2023-12-01 14:12:05 +08:00
hang 98d09886de 修改警告5 2023-12-01 14:11:10 +08:00
hang 91671c5003 修改警告4 2023-12-01 14:09:56 +08:00
hang 35ef014391 修改警告4 2023-12-01 14:07:43 +08:00
hang 82fc9bfc75 警告修改2 2023-12-01 14:05:31 +08:00
hang d6d47a6f85 修改警告 1 2023-12-01 14:03:22 +08:00
hang 32d6cce33e 服务循环依赖
continuous-integration/drone/push Build is passing
2023-12-01 13:59:28 +08:00
hang 06ca624886 x
continuous-integration/drone/push Build is passing
2023-11-30 15:29:59 +08:00
hang 88231fffb4 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2023-11-30 15:29:11 +08:00
hang 12ab0d3eb4 合并代码修改 2023-11-30 15:29:09 +08:00
hang 6faeecebb0 修改统计,需要迁移 2023-11-30 15:13:15 +08:00
hang 48b778c95a linux 下适配 转换pdf 2023-11-30 15:13:09 +08:00
hang dee286cc90 验证环境发布 2023-11-30 15:09:53 +08:00
hang 2e96f7a936 日志提示当前部署平台 2023-11-30 15:07:52 +08:00
he ebb33f45ba 临床数据修改
continuous-integration/drone/push Build is passing
2023-11-30 15:00:04 +08:00
he 9d32be658c Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2023-11-30 14:24:33 +08:00
he 27fd819c9c 临床数据维护 2023-11-30 14:24:12 +08:00
he 937f8a5b66 临床数据问题修改 2023-11-30 14:24:09 +08:00
hang 53544001a7 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2023-11-28 13:25:20 +08:00
hang f08cd1c818 1127 稽查修改 2023-11-28 13:24:34 +08:00
hang 2c377d02f9 中心调研修改 需要迁移 2023-11-28 13:23:03 +08:00
hang 29f8648287 修改OSS 配置
continuous-integration/drone/push Build is passing
2023-11-24 14:47:12 +08:00
hang f0725873e1 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2023-11-24 11:25:17 +08:00
hang dc12e57494 迁移提交 2023-11-24 11:25:15 +08:00
hang d4a731d544 OSS 稽查修改 ,新增健康检查
continuous-integration/drone/push Build is passing
2023-11-24 11:23:39 +08:00
hang 6e22515603 迁移修改
continuous-integration/drone/push Build is passing
2023-11-24 09:51:50 +08:00
hang abd5c8942d 上传文件到OSS 需要迁移 2023-11-24 09:37:12 +08:00
hang 3decef7693 修改统计bug,医学审核增加最新回复人 2023-11-24 09:29:30 +08:00
hang ae83c753cb 统计排序 03
continuous-integration/drone/push Build is failing
2023-11-24 09:20:29 +08:00
hang 53ae0527ff 修改稽查和界面统计 需要迁移02 2023-11-24 09:20:21 +08:00
hang a234e0746d 修改重阅稽查 2023-11-24 09:18:20 +08:00
hang c88d927c4b 稽查修改 2023-11-24 09:18:04 +08:00
hang 245898e22e 医学审核稽查修改 2023-11-24 09:16:41 +08:00
he 93d3024b0f 修改
continuous-integration/drone/push Build is passing
2023-11-21 13:12:31 +08:00
he 35be7f3144 Merge branch 'Test.Study' of http://192.168.3.68:2000/XCKJ/irc-netcore-api into Test.Study
continuous-integration/drone/push Build is passing
2023-11-21 13:11:57 +08:00
hang 62ac9418b5 修改统计bug,
continuous-integration/drone/push Build is passing
2023-11-21 11:13:56 +08:00
hang ea5de83364 修改统计03 -需迁移 2023-11-21 11:13:00 +08:00
hang cf5a8b20e4 CRC 影像质疑 2023-11-21 11:12:55 +08:00
hang ea95ece331 修改页面查询结果显示 2023-11-21 11:12:51 +08:00
hang 894b9eb67b Merge branch 'Test.Study' of http://192.168.3.69:2000/XCKJ/irc-netcore-api into Test.Study 2023-11-08 18:28:02 +08:00
hang d7e5b3f57c 没有建议完成时间 2023-11-08 18:27:58 +08:00
hang 29a47e7351 修改邮件 2023-11-08 16:43:52 +08:00
he 6d2cddfcfc 修改 2023-11-08 16:07:31 +08:00
he 60b2978deb Merge branch 'Test.Study' of http://192.168.3.69:2000/XCKJ/irc-netcore-api into Test.Study 2023-11-08 16:06:30 +08:00
hang 79187772a6 Merge branch 'Test.Study' of http://192.168.3.69:2000/XCKJ/irc-netcore-api into Test.Study 2023-11-07 11:59:56 +08:00
hang 105da818a8 修改删除 2023-11-07 11:59:19 +08:00
hang 584516f936 修改项目列表 2023-11-07 11:46:47 +08:00
hang a7429c1739 通用文档下载 2023-11-06 13:58:34 +08:00
hang 75f227e547 增加权限 2023-11-06 13:39:30 +08:00
hang 60c31b470c 导表bug 2023-11-06 13:32:06 +08:00
hang 731f049fc0 修改国际化,导表,增加查看角色类型 2023-11-06 13:10:13 +08:00
hang 201c24238c 权限增加 2023-11-06 11:14:41 +08:00
hang 71e28f1a37 x 2023-11-03 15:44:39 +08:00
he 375e50bab7 Merge branch 'Test.Study' of http://192.168.3.69:2000/XCKJ/irc-netcore-api into Test.Study 2023-11-03 12:27:57 +08:00
he 39e2651edf 修改 2023-11-03 12:27:54 +08:00
hang b461216d87 修改配置文件 2023-11-03 12:15:13 +08:00
he dc6ae39130 修改 2023-11-03 09:55:05 +08:00
he 4b65f1e922 Merge branch 'Test.Study' of http://192.168.3.69:2000/XCKJ/irc-netcore-api into Test.Study 2023-11-03 09:51:44 +08:00
hang 99439a4809 容器真实ip 2023-11-02 15:53:09 +08:00
hang 419d5de7f1 admin 项目列表查看 2023-11-02 10:06:53 +08:00
hang a56ffaee58 admin 可以看到项目列表 2023-11-01 13:21:17 +08:00
hang e925d5bdb2 x 2023-11-01 11:18:53 +08:00
hang 9ec97f7d37 拷贝病灶修改 2023-10-31 15:21:35 +08:00
hang 3c532389d9 项目默认邮件配置 2023-10-30 16:20:33 +08:00
hang 1094f318f9 预留项目配置系统邮件配置 2023-10-30 16:13:26 +08:00
hang 56f261b8ce 拷贝表单屏蔽 2023-10-30 15:26:59 +08:00
hang 34b12b89e4 访视拷贝表单测试 2023-10-30 14:43:36 +08:00
hang bca8f2ddb9 数据库保存异常提示 2023-10-18 10:41:20 +08:00
hang 4023a59097 Merge branch 'Test.Study' of http://192.168.3.69:2000/XCKJ/irc-netcore-api into Test.Study 2023-10-16 09:21:59 +08:00
hang 8afcbf3d5e 打开分布式锁 2023-10-16 09:21:58 +08:00
hang 69c2cd339c 打开分布式锁 2023-10-16 09:20:44 +08:00
hang 4c7ce217da nuget 包确认 2023-10-13 23:38:04 +08:00
hang d66209452c 升级EF core 7 2023-10-13 22:48:00 +08:00
hang 77352245fc 测试 升级nuget包ok 2023-10-13 22:38:28 +08:00
hang 17ebdce96e 移除废弃的包 2023-10-13 22:17:11 +08:00
hang 3962178c68 efcore 6 升级到6版本最新,同时EFCore.BulkExtensions 也是6版本最新,但是projectable 不能升级 2023-10-13 21:28:10 +08:00
hang 7c6dcbbe38 回退包,查询临时方案 2023-10-13 18:02:33 +08:00
hang 75ed6375c2 修改nuget包位置 2023-10-13 11:53:52 +08:00
hang 290578d824 删除没用的文件 2023-10-13 11:34:55 +08:00
hang cd2f5aa1e1 Merge branch 'Test.Study' of http://192.168.3.69:2000/XCKJ/irc-netcore-api into Test.Study 2023-10-13 11:27:21 +08:00
hang 79d150829a EntityFrameworkCore.Projectables 包问题 导致更新出错 2023-10-13 11:21:21 +08:00
hang 270de86658 批量删除修改 2023-10-12 17:28:34 +08:00
hang edefc8f3e7 修改nuget 2023-10-12 15:16:52 +08:00
hang f1b3ec7d7c 更新nuget 2023-10-12 14:20:03 +08:00
hang 5171af975d nuget 包升级,清理没用的包,预备net8 2023-10-12 14:07:33 +08:00
hang 33b9113993 nuget 包升级,清理没用的包,预备net8 2023-10-12 14:03:30 +08:00
he a53626b66c 修改缓存 2023-10-12 13:56:39 +08:00
hang a27dcd6399 升级efcore 清理之前的写法 2023-10-12 13:31:52 +08:00
hang 14908c4eed 分布式锁 sqlserver 05 项目迁移修改 2023-10-12 09:34:09 +08:00
hang dfef88d663 分布式锁 sqlserver 测试 04 增加日志 2023-10-11 17:44:13 +08:00
hang 1afe020e83 分布式锁 sqlserver 测试 03 2023-10-11 17:38:34 +08:00
hang 7544e0c2e9 引入分布式组件 redis 2023-10-11 16:29:57 +08:00
hang 68d72fce53 引入 EasyCaching redis 准备工作完毕 2023-10-11 13:16:57 +08:00
hang 423f2fcb7c 修改PI 审核 2023-10-07 10:55:04 +08:00
hang 92b715de3a Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-10-07 10:53:28 +08:00
hang 912bc2edb8 修改pi 审核 2023-10-07 10:53:26 +08:00
hang a5f6c24aec 修改pi 审核 2023-10-07 10:49:20 +08:00
hang 8fc886a1db 修改异常提示 2023-09-28 11:37:49 +08:00
hang 5832610d3d x 2023-09-27 13:19:52 +08:00
hang e675542136 x 2023-09-27 13:19:30 +08:00
hang 8f7a3ab713 删除表 2023-09-27 11:42:10 +08:00
hang 02d98cfa75 x 2023-09-26 15:31:38 +08:00
hang 8bb1e8cf43 x 2023-09-26 14:20:35 +08:00
hang b3e37c7ea4 测试oss 改为1分钟 2023-09-26 14:13:07 +08:00
he 5bdb89df7d 维护临床数据 2023-09-26 11:25:21 +08:00
hang 10d50f3b5a 修改 2023-09-26 11:23:45 +08:00
hang bb6d36c8be 修改site 2023-09-25 17:25:59 +08:00
hang d91f4dc728 CRA 签名权限 以及Site 列表 2023-09-25 16:58:33 +08:00
hang f01e5335d6 增加地址 2023-09-22 15:32:26 +08:00
hang 3e8794b335 邮件发送 2023-09-22 15:23:42 +08:00
hang 79375f7106 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-22 15:22:35 +08:00
hang 72b2047862 修改site 查询 2023-09-22 15:22:29 +08:00
he 8b124e1c60 关键序列修改 2023-09-21 13:14:02 +08:00
he 5b2449b607 预览新增ParentTriggerValueList
RelevanceValueList 字段
2023-09-21 11:43:22 +08:00
he 3f4a5e3040 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-21 11:41:57 +08:00
hang 75a24b8aef Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-19 13:38:22 +08:00
hang 493c46ed15 修改数据库配置 2023-09-19 13:38:20 +08:00
he 5c2467bdbb Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-19 11:19:53 +08:00
he 0777ea830c 修改端口 2023-09-19 11:19:46 +08:00
hang b75223f8a0 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-18 11:42:15 +08:00
hang 6a4e42f9dc 修改cookie 测试 2023-09-18 11:42:14 +08:00
he f7eec6327a 两个问题bug修改 2023-09-18 10:24:42 +08:00
he 1a4301233c 临床数据排序 自定义标准关键序列 2023-09-18 10:16:26 +08:00
he b6b5a5d0de Revert "添加问题分类字段"
This reverts commit da9a7affa9.
2023-09-14 15:45:32 +08:00
he 92c435cf23 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-14 15:45:13 +08:00
hang 8697ec952c Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-14 14:17:16 +08:00
hang c6d3ae7c8b VisitBaseDataDes 遗漏 2023-09-14 14:17:13 +08:00
he 376c02f44c Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-14 14:02:34 +08:00
he da9a7affa9 添加问题分类字段 2023-09-14 14:02:23 +08:00
hang ac62f48a71 给默认值 2023-09-14 11:44:15 +08:00
hang 3d8cdd6ac6 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-14 10:37:14 +08:00
hang 9380b40c28 增加访视基准日期说明 2023-09-14 10:37:11 +08:00
he cc823daee5 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-13 14:08:24 +08:00
he b4594a4c47 获取下一个质控任务 2023-09-13 14:08:22 +08:00
hang c8660c0426 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-12 10:36:19 +08:00
hang 375a724169 修改邮件 2023-09-12 10:36:06 +08:00
he 67375c3cbd 去掉doctor筛选 2023-09-07 17:59:52 +08:00
he 1645aaf69a Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-07 17:39:05 +08:00
hang 99b7d3a4f8 x 2023-09-07 14:32:21 +08:00
hang eac77e45d2 x 2023-09-07 14:22:09 +08:00
hang ebf05df568 修改下拉框 2023-09-07 14:21:38 +08:00
hang f464b25c2b 修改下拉框 2023-09-07 14:20:50 +08:00
hang b0dbe1442c 修改json 2023-09-07 10:27:51 +08:00
hang 5ae3220e67 修改稽查查询 2023-09-06 14:39:31 +08:00
hang f31a6408ac 修改已阅片任务 2023-09-06 11:06:49 +08:00
hang 9234e7ebe9 x 2023-09-05 15:52:49 +08:00
hang 609a7fb427 修改配置 2023-09-05 13:38:34 +08:00
hang a92bbbb275 x 2023-09-05 13:17:32 +08:00
hang c2bf16e1ff 稽查查询 2023-09-05 11:49:35 +08:00
hang dce2509613 oss 2023-09-05 11:11:57 +08:00
hang 1ac336220e oss 权限修改 2023-09-05 10:45:01 +08:00
hang a47f2fd496 x 2023-09-04 17:25:42 +08:00
hang 45c0704b40 修改邮件发送逻辑 2023-09-04 17:23:03 +08:00
hang 97cf5ce93c 邮件用户名修改 2023-09-04 16:35:26 +08:00
hang 786367f9fe x 2023-09-04 16:31:17 +08:00
hang f8c9cb1564 x 2023-09-04 16:20:22 +08:00
hang ee11290037 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-04 16:05:38 +08:00
hang 42f3f6fb67 修改PI 审核发送邮件 2023-09-04 16:05:35 +08:00
he 2a844b11bd Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-04 15:47:28 +08:00
hang 5579fe4e95 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-04 09:21:36 +08:00
hang ee96435379 object 参数会必传 2023-09-04 09:21:34 +08:00
he 4fce96db0e 代码修改 2023-09-04 09:21:01 +08:00
he 14e7ecd171 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-04 09:13:26 +08:00
hang ffeece79fe 修改中心查询 2023-09-01 17:36:04 +08:00
hang 5c86989dfa x 2023-09-01 17:18:28 +08:00
hang c6a8c4d24f Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-01 15:53:18 +08:00
hang 477691ec70 修改中心 2023-09-01 15:53:17 +08:00
he 5518609d54 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-09-01 15:47:02 +08:00
he 9f706d3123 临床数据表格问题添加依赖父问题 2023-09-01 15:46:56 +08:00
hang 5956d32c36 修改中心 2023-09-01 15:45:20 +08:00
hang a60e00159d 邮件发送翻译 2023-09-01 15:16:25 +08:00
hang 47277086ac xx 2023-09-01 14:29:54 +08:00
hang c7571570e9 x 2023-09-01 14:23:16 +08:00
hang 83d6859347 修改问题 2023-09-01 14:19:39 +08:00
hang a42986dcab 修改 2023-09-01 14:10:45 +08:00
hang 13fbf36de0 修改查询 2023-09-01 14:00:54 +08:00
hang 4ba2aa4769 修改PI 审核 2023-09-01 11:54:52 +08:00
hang 6b1a6a81eb 修改邮件--034 2023-09-01 10:35:13 +08:00
hang 62f8d5823f 调研表 2023-08-31 17:00:01 +08:00
hang 5cbefec0b0 修改提示 2023-08-31 16:33:34 +08:00
hang b154540885 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-08-31 16:20:50 +08:00
hang 9eda07b253 修改启动 2023-08-31 16:20:47 +08:00
he 2995d2273a Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-08-31 16:14:06 +08:00
he 8fffdb244d oos 上传 2023-08-31 16:14:00 +08:00
hang 657da0c554 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-08-31 16:04:21 +08:00
hang 1912e1cfcd 一致性核查文件名修改 2023-08-31 16:04:19 +08:00
he 3313c0223d Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-08-31 15:46:31 +08:00
hang 3c9b87ba01 修改上传bug 2023-08-31 13:30:39 +08:00
hang 65b52a1836 修改稽查 2023-08-31 10:10:29 +08:00
hang 684dbbd8e1 修改日志查询 2023-08-31 10:10:22 +08:00
hang 5a3127bb8e x 2023-08-30 16:42:45 +08:00
hang 0b9cf600ba 加 看内存缓存数据接口 2023-08-30 16:34:24 +08:00
hang b2f4fa3fb9 修改邮件--033 2023-08-30 15:14:08 +08:00
hang ecae4f663a 修改邮件--032 2023-08-30 15:08:38 +08:00
he 200da3375b Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-08-30 14:45:30 +08:00
he a3cedaa7b8 OSS上传 2023-08-30 14:45:25 +08:00
hang 37fc48c64d Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-08-30 14:40:17 +08:00
hang 1e4ee0a5e9 修改邮件--031 2023-08-30 14:40:13 +08:00
he bc383d9b23 OOS上传 2023-08-30 11:11:22 +08:00
he 27634b5aac Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-08-30 11:10:47 +08:00
he 2d479a15ec OOS 上传 2023-08-30 11:10:37 +08:00
hang a719ca752f 调研表--30 2023-08-29 17:47:08 +08:00
hang 089e329e4c Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-08-29 17:33:49 +08:00
hang b84abaa0a9 修改医学审核 2023-08-29 17:33:46 +08:00
he 6f4d85ea2b Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-08-29 16:54:48 +08:00
he 0f47a14e69 国际化修改 2023-08-29 16:54:38 +08:00
hang 788c24a6f3 修改邮件发送和稽查 2023-08-29 14:31:11 +08:00
hang a6c0bc7a21 Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-08-28 18:05:43 +08:00
hang 661140ebf8 邮件发送逻辑修改--029 项目邮件配置增加是否启用 2023-08-28 18:05:40 +08:00
he 9692ae569e Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-08-28 14:09:10 +08:00
he f6d46bcf12 国际化修改 2023-08-28 14:09:08 +08:00
he 595635d93d 国际化修改 2023-08-28 14:08:23 +08:00
hang 89d92baf56 邮件发送逻辑修改--028 2023-08-25 19:21:43 +08:00
hang 995605a2b6 邮件修改 2023-08-25 18:59:11 +08:00
hang 749c123229 x 2023-08-25 18:50:05 +08:00
hang f24f60cdef 修改映射 2023-08-25 18:46:58 +08:00
hang 451ffec65b 邮件发送逻辑修改--028 2023-08-25 18:36:27 +08:00
hang 033ac555f2 邮件发送逻辑修改--027 2023-08-25 18:05:01 +08:00
hang 14b57769d3 中心调研--026 2023-08-25 17:27:20 +08:00
hang 7c5b1b6fd1 x 2023-08-25 17:26:58 +08:00
hang 14bc9f4429 修改邮件发送枚举--026 2023-08-25 17:16:09 +08:00
hang b72b13509b xx 2023-08-25 11:25:26 +08:00
hang daaf4540a4 修改邮件发送枚举--025 2023-08-25 10:28:43 +08:00
hang eee828ca46 hangfire授权--025 2023-08-25 09:56:23 +08:00
hang a084a6b49b 测试路径 2023-08-24 16:36:47 +08:00
hang 1676056e43 测试路径 2023-08-24 16:04:58 +08:00
hang a601cf3ef8 虚拟路径测试 2023-08-24 15:34:38 +08:00
hang 3a7ddab1f3 修改访问路径 2023-08-24 15:23:42 +08:00
hang d1634d0813 继续测试 2023-08-24 14:55:49 +08:00
hang 31ccf4cefa x 2023-08-24 14:44:26 +08:00
hang f528b7ff5e 访问路径测试 2023-08-24 14:38:31 +08:00
hang d48333e71e 项目邮件配置修改--024 2023-08-24 13:09:28 +08:00
hang 7c0c096be4 项目邮件配置修改--023 2023-08-24 11:38:51 +08:00
hang b23befe18c x 2023-08-24 11:38:37 +08:00
hang ea48a57f95 x 2023-08-23 18:20:26 +08:00
hang c7faf920db 项目邮件配置修改--022 2023-08-23 18:12:58 +08:00
hang 6f722a43f5 修改定时任务 2023-08-23 18:06:07 +08:00
hang cbe66ac397 项目邮件配置修改--021 2023-08-23 17:54:48 +08:00
hang 0006f12151 修改定时任务 2023-08-23 17:49:06 +08:00
hang 8a3db78cd0 项目邮件配置修改--020 2023-08-23 17:48:56 +08:00
hang 3dfe229024 项目邮件配置修改--019 2023-08-23 17:46:31 +08:00
hang a8e4d6285d 项目邮件配置修改--018 修改邮件查询条件 2023-08-23 10:48:41 +08:00
hang bfe82bd322 修改发送邮件的方式test 2023-08-23 10:46:02 +08:00
hang e0ebd083b9 临床数据质询 增加新的表和回复接口 2023-08-23 09:46:59 +08:00
hang 6c6b18818a 项目邮件配置修改--017 2023-08-23 09:46:29 +08:00
hang 4338481f9f 项目邮件配置修改--016 2023-08-22 17:12:41 +08:00
hang e05f43b0b8 项目邮件配置修改--015 2023-08-22 14:54:30 +08:00
hang a4e26f9895 项目邮件配置修改--014 2023-08-22 14:14:31 +08:00
hang bc1e39450d 项目邮件配置修改--013 2023-08-22 13:31:40 +08:00
hang 87aa2cd8da 项目邮件配置修改--012 2023-08-22 11:07:01 +08:00
hang 9fa9896f0a 项目邮件配置修改--011 2023-08-22 11:06:16 +08:00
hang c4c034f2bb 修改字典表bug 2023-08-22 10:38:23 +08:00
hang aaed933eb9 项目邮件配置修改--010 2023-08-22 10:36:08 +08:00
hang c7b541dec6 项目邮件配置修改--009 2023-08-21 17:30:08 +08:00
hang e24933f0dd 项目邮件配置修改--008 2023-08-21 17:18:17 +08:00
hang e46b51d6a1 项目邮件配置修改--007 2023-08-21 16:15:44 +08:00
hang f3f00e3d0f Merge branch 'Test.Study' of http://192.168.3.69:3000/XCKJ/irc-netcore-api into Test.Study 2023-08-21 15:47:04 +08:00
hang 5a71e3eb25 系统邮件配置预先修改-005 2023-08-21 15:47:02 +08:00
hang d9b108553a 系统邮件配置预先修改-004 2023-08-21 15:43:07 +08:00
hang b9a99cef90 修改名称 2023-08-21 15:41:42 +08:00
hang 2f366b55d9 系统邮件配置预先修改-003 2023-08-21 15:34:18 +08:00
hang 13263cf39c 系统邮件配置预先修改-002 2023-08-21 15:28:26 +08:00
hang e03e93b0f5 修改上传路径 2023-08-21 15:13:56 +08:00
hang d62d1f2047 修改上传 2023-08-21 15:04:42 +08:00
hang ca3f3b6f9d 系统邮件配置预先修改-001 2023-08-21 15:04:30 +08:00
hang 96e1a2c393 修改中心调研,引入hangfire 2023-08-18 17:55:43 +08:00
hang b6403580de 修改退出改为加入 2023-08-18 14:44:36 +08:00
hang 8c5cca7ba5 修改中心调研限制条件 2023-08-18 13:19:51 +08:00
hang 4200daa1b9 修改调研表 2023-08-18 10:27:49 +08:00
hang 1a5cfa8bbd 修改废除状态 2023-08-18 09:23:35 +08:00
hang c371c4b127 OK 2023-08-18 08:57:39 +08:00
hang bd8123af59 修改调研表限制 2023-08-18 08:56:57 +08:00
hang 00cb2fc67c 修改调研表限制 2023-08-18 08:56:44 +08:00
hang ea157cdb71 修改调研表查询和提交 2023-08-17 18:07:34 +08:00
hang aa343ade2e xx 2023-08-17 17:11:02 +08:00
hang 536e9ef262 修改更新后的状态 2023-08-17 16:44:55 +08:00
hang d200f12fa8 修改人员状态变更 2023-08-17 16:42:05 +08:00
hang c85bb7f22b 修改调研验证提示 2023-08-17 16:21:34 +08:00
hang d575d8ac73 修改中心调研拷贝数据逻辑错误 2023-08-17 15:59:11 +08:00
hang 585b665b53 继续test 2023-08-17 15:17:06 +08:00
hang 8ffe69d38e 修改服务器时间,自动发布测试 2023-08-17 15:03:40 +08:00
hang 5e743b162d 提交中心调研 2023-08-17 14:54:44 +08:00
hang b9ccf4bb12 中心调研临时提交 2023-08-17 11:18:01 +08:00
hang 4bc2c3107a 前端限制查询配置增加 2023-08-16 13:10:51 +08:00
hang 008f5203c0 外部用户修改 2023-08-15 16:40:36 +08:00
hang 5d2acf44c1 修改中心调研 isJoin 2023-08-15 15:25:18 +08:00
hang c04d3a3fe4 修改PI 审核 2023-08-14 18:24:45 +08:00
hang 33ef76ad98 返回字段控制界面tab显示与否 2023-08-14 17:48:44 +08:00
hang c77cf1bf1e 废除的也可以看到调研信息 2023-08-10 17:44:10 +08:00
hang f9274c8fda 修改锁定废除 2023-08-10 17:21:32 +08:00
hang 5ae02e0d1f 修改调研查询trialId 2023-08-10 16:56:22 +08:00
hang dcdf03ca8e x 2023-08-10 16:40:01 +08:00
hang 775927c484 修改 Test.Study 2023-08-10 13:54:36 +08:00
hang bf230924d7 显示指定缓存发布尝试 2023-08-10 11:52:33 +08:00
hang d81fee17ba bat 执行一部分 测试时间 2023-08-10 11:36:28 +08:00
hang 0a398bd712 增加Test.IRC发布配置 2023-08-10 10:56:39 +08:00
hang a7d41772f7 ps 等待执行结束测试 2023-08-09 18:18:40 +08:00
hang 08754b9a24 尝试call 2023-08-09 18:15:25 +08:00
hang 133120e8c0 修改自动发布配置文件 2023-08-09 18:05:48 +08:00
hang ce3bfaeb5c 修改中心调研 2023-08-09 17:18:21 +08:00
hang 7e518bf3ab 修改中心调研 2023-08-08 14:53:07 +08:00
hang 106cbfacce 修改 参数可传与否 2023-08-08 13:14:38 +08:00
hang eb58745f19 增加Uat环境 2023-08-08 09:27:35 +08:00
hang cf0fa32101 Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-08-07 17:28:57 +08:00
hang d8894e92c0 修改邮件模板 2023-08-07 17:28:21 +08:00
he fc800672e1 代码修改 2023-08-07 16:44:32 +08:00
he 462ef4671e Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-08-07 16:31:46 +08:00
hang 212701fa8c 修改阅片任务 2023-08-07 14:57:27 +08:00
hang 75ccbe9bfb 删除多余的配置文件 2023-08-07 14:06:49 +08:00
hang 56e3bf64f2 任务阅片修改 2023-08-07 12:22:17 +08:00
hang 228254db09 调研表修改 2023-08-07 12:22:03 +08:00
hang 711c3f3639 修改退回 2023-08-03 13:53:42 +08:00
hang 5aa4c81c0d Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-08-03 11:49:08 +08:00
hang db9ce69594 修改引用包 2023-08-03 11:48:59 +08:00
he 891044eaf7 S-102 自定义标记 2023-08-03 10:53:13 +08:00
he 2e84fb8063 S-101 自定义标记 2023-08-03 10:52:40 +08:00
he d0e6f06f38 S-100 国际化修改 2023-08-03 10:52:14 +08:00
he 32a7fc3239 Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-08-03 10:51:11 +08:00
hang 29e4df9792 修改任务生成 2023-08-03 10:19:33 +08:00
hang 447bc6cb13 修改查询 2023-08-03 09:38:21 +08:00
hang dbb23132b3 修改instanceId 2023-08-01 13:02:41 +08:00
hang 179c283d75 修改DTO 2023-07-31 17:04:01 +08:00
hang 427cb38f39 修改非dicom 上传 2023-07-31 13:20:04 +08:00
hang ca9193438b Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-07-31 09:25:32 +08:00
hang d3d991cb3a 修改领取逻辑 2023-07-31 09:24:42 +08:00
he d8ea93dcd6 提示语言修改 2023-07-28 13:32:43 +08:00
he 3a649cfcfc S-99 临床数据 2023-07-27 16:04:58 +08:00
he 446d47167b Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-07-27 15:41:10 +08:00
he 7b10424238 修改 2023-07-27 15:40:46 +08:00
hang 9bfca25044 修改退回逻辑 2023-07-27 09:50:44 +08:00
hang 2bde5d1309 暂存修改 2023-07-27 09:38:41 +08:00
hang 93646d8f58 Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-07-27 09:23:23 +08:00
hang 9162f6ec99 删除没用的数据 2023-07-27 09:23:13 +08:00
he e413191bf4 S-98 时间修改 2023-07-26 11:14:42 +08:00
he 36cb770a86 S-97 添加分组 2023-07-26 11:01:25 +08:00
he 7a383a3fa5 Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-07-26 10:50:35 +08:00
he c9342b6ad1 S-96 添加时间 2023-07-26 10:50:14 +08:00
hang aadbc191a8 Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-07-25 18:06:24 +08:00
hang 4c9b46a20c 序列bug 2023-07-25 18:06:16 +08:00
he 0bde983ae9 Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-07-25 10:38:59 +08:00
he f55e295c01 添加映射 2023-07-25 10:38:37 +08:00
hang e06f564905 修改退回重阅片 2023-07-24 17:20:31 +08:00
he 1a64de066e 修改映射关系 2023-07-24 17:19:42 +08:00
he 53251e53a0 删除不要的功能 2023-07-24 14:40:31 +08:00
he f0cde942fb Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-07-24 13:30:44 +08:00
hang 7c9a07f384 Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-07-24 10:52:07 +08:00
hang 96b9d264a9 hang-清除工作量脏数据 2023-07-24 10:51:55 +08:00
he 0f3802474d 阅片关联去掉DoctorId 2023-07-24 10:12:24 +08:00
he f4c8d6c999 S-95 2023-07-21 15:56:27 +08:00
he fd25c99609 S-94 2023-07-21 15:56:22 +08:00
he 79da2c0adc S-93 2023-07-21 15:56:16 +08:00
he 7ec682668c S-92 2023-07-21 15:56:10 +08:00
he 93df8b81b7 S-91 2023-07-21 15:56:03 +08:00
he a089807bf0 S-90 2023-07-21 15:55:58 +08:00
he f97956c181 S-90 2023-07-21 15:55:53 +08:00
he 8bc59c53b6 S-89 2023-07-21 15:55:48 +08:00
he a136ed3f87 S-88 2023-07-21 15:55:42 +08:00
he d903e76d7a S-87 2023-07-21 15:55:37 +08:00
he ac1c0e6baa S-86 2023-07-21 15:55:32 +08:00
he e57617c305 S-85 2023-07-21 15:55:27 +08:00
he 4d307bc6fa S-84 2023-07-21 15:55:20 +08:00
he f3f3eb463b S-83 2023-07-21 15:55:12 +08:00
he a8232341dd S-82 2023-07-21 15:55:04 +08:00
he 4e2b03000d S-81 2023-07-21 15:54:56 +08:00
he 4e777e05db S-80 2023-07-21 15:54:49 +08:00
he 1f7fe0d854 S-79 2023-07-21 15:54:43 +08:00
he a58d7c9314 S-78 2023-07-21 15:54:37 +08:00
he 22d66ce856 S-77 2023-07-21 15:54:31 +08:00
he 546d7e7280 S-76 2023-07-21 15:54:25 +08:00
he 9f2d241d87 S-75 2023-07-21 15:54:19 +08:00
he bcdd8b7e2b S-74 2023-07-21 15:54:12 +08:00
he 11ad8f8d5f S-73 2023-07-21 15:54:04 +08:00
he 24b2067f50 S-72 2023-07-21 15:53:58 +08:00
he f85c51f7de S-71 2023-07-21 15:53:51 +08:00
he 449098ad72 S-70 2023-07-21 15:53:46 +08:00
he d8c1f9ee6f S-69 2023-07-21 15:53:42 +08:00
he 05bc298cfc S-68 2023-07-21 15:53:36 +08:00
he d03c405d54 S-67 2023-07-21 15:53:29 +08:00
he be786c2cbe S-66 同步 2023-07-21 15:53:23 +08:00
he 3a32825642 S-65 确认就同步标准 2023-07-21 15:53:17 +08:00
he 72e6bcc297 S-64 2023-07-21 15:53:12 +08:00
he 586000a98d S-63 2023-07-21 15:53:06 +08:00
he eae14095c0 S-62 2023-07-21 15:53:01 +08:00
he f7027d3fe6 S-61 2023-07-21 15:52:55 +08:00
he ca0a29b033 S-60 VisitHelper 任务临床状态维护 2023-07-21 15:52:50 +08:00
he 9e695dcfe8 S-59 2023-07-21 15:52:44 +08:00
he 4a8fd956ff S-58 2023-07-21 15:52:39 +08:00
he 284495700a S-57 2023-07-21 15:52:31 +08:00
he 1ba147009b S-56 2023-07-21 15:52:24 +08:00
he 2c541e68e1 S-55 2023-07-21 15:52:19 +08:00
he 95b39ea5e7 S-54 2023-07-21 15:52:12 +08:00
he 44e109cefa S-53 2023-07-21 15:52:05 +08:00
he 48763989d9 S-52 2023-07-21 15:52:00 +08:00
he f88bbee37b S-51 2023-07-21 15:51:55 +08:00
he fa3e1a6c35 S-50 2023-07-21 15:51:49 +08:00
he 6a5ce9aaa6 S-50 2023-07-21 15:51:43 +08:00
he bd7f840536 S-49 任务的临床状态维护 2023-07-21 15:51:35 +08:00
he 53fab12535 S-48 2023-07-21 15:51:30 +08:00
he 77745cfae6 S-47 2023-07-21 15:51:25 +08:00
he 73cb05956f S-46 2023-07-21 15:51:17 +08:00
he b3386c20ab S-45 2023-07-21 15:51:10 +08:00
he 83f419bff1 S-44 2023-07-21 15:50:55 +08:00
he c6a4a2dd0b S-43 2023-07-21 15:50:48 +08:00
he de3c59b7f5 S-42 2023-07-21 15:50:42 +08:00
he 28c89ce51d S-41 2023-07-21 15:50:36 +08:00
he a6fcf3421c S-40 2023-07-21 15:50:31 +08:00
he 2fcb2493d1 S-39 2023-07-21 15:50:25 +08:00
he 64b2b7850f S-38 2023-07-21 15:50:18 +08:00
he 429b53feba S-37 2023-07-21 15:50:11 +08:00
he a7042ba8a6 S-36 2023-07-21 15:50:05 +08:00
he f4c0413360 S-35 2023-07-21 15:49:57 +08:00
he 216b14663c S-34 2023-07-21 15:49:51 +08:00
he 895bda2e3f S-33 2023-07-21 15:49:45 +08:00
he 459866e924 S-32 2023-07-21 15:49:38 +08:00
he bdada76518 S-31 2023-07-21 15:49:33 +08:00
he 53129d2fcb S-30 2023-07-21 15:49:28 +08:00
he f174a555dd S-29 2023-07-21 15:49:23 +08:00
he 21da76f493 S-28 2023-07-21 15:49:17 +08:00
he 4d74de93ba S-27 2023-07-21 15:49:12 +08:00
he 92780b7152 S-26 2023-07-21 15:49:07 +08:00
he 0d73d19e44 S-25 2023-07-21 15:49:01 +08:00
he 689511a130 S-24 2023-07-21 15:48:55 +08:00
he d22d4d01c5 S-23 2023-07-21 15:48:49 +08:00
he fe691c2460 S-22 2023-07-21 15:48:44 +08:00
he f0d3c787d9 S-21 2023-07-21 15:48:37 +08:00
he 6b0945dc6f S-20 2023-07-21 15:48:31 +08:00
he d84358db3a S-19 2023-07-21 15:48:25 +08:00
he 5bb90e6f15 S-18 2023-07-21 15:48:18 +08:00
he 0840ac2c8b S-17 2023-07-21 15:48:13 +08:00
he 44a153ebb0 S-16 2023-07-21 15:48:07 +08:00
he 2214bdc1ad S-15 2023-07-21 15:45:38 +08:00
he c958e49118 S_014 2023-07-21 15:45:08 +08:00
he f7ae01ddc1 S-13 2023-07-21 15:44:56 +08:00
he 71b68f3354 修改 2023-07-21 15:44:49 +08:00
he a7e2e56175 S-011 2023-07-21 15:44:42 +08:00
he 7f4e82c27c S-010 2023-07-21 15:44:32 +08:00
he 6e2013f0c7 S-009 2023-07-21 15:44:26 +08:00
he 438e0947ac S-008 2023-07-21 15:44:19 +08:00
he 2e2d912aeb S-007 2023-07-21 15:44:13 +08:00
he 44d0f67e18 S-006 临床数据 2023-07-21 15:44:06 +08:00
he 22225dd841 修改 2023-07-21 15:43:53 +08:00
he 650d1e9647 S-004 临床数据 2023-07-21 15:43:42 +08:00
he 9265147e12 S-003 临床数据 2023-07-21 15:43:34 +08:00
he 8358d67f3e S-002 临床数据修改 2023-07-21 15:43:16 +08:00
he 2930c2b640 S-01临床数据 2023-07-21 15:32:08 +08:00
he 42e64d77cb Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-07-21 15:30:36 +08:00
hang 440fc103b1 修改医学审核返回字段 2023-07-21 08:48:59 +08:00
hang 128e3c747e 修改角色 2023-07-20 14:30:18 +08:00
hang a9439758c9 修改查询 2023-07-20 14:01:19 +08:00
hang 1247baaa36 修改未读任务查询 2023-07-20 13:43:25 +08:00
hang 59239060a6 修改中心调研 2023-07-20 11:41:56 +08:00
hang 42eae556e8 修改中心调研 2023-07-20 09:25:09 +08:00
hang a61b20ace6 修改PI 审核空数组 2023-07-19 16:38:13 +08:00
hang 9425fc521e 自动发送邮件代码屏蔽 2023-07-18 14:23:55 +08:00
hang 47c629f9a1 hang- 修改CRC 看到的检查列表 2023-07-18 11:14:20 +08:00
hang 11a669bf99 国际化修改 2023-07-17 14:26:02 +08:00
hang 366aba68ce 前端限制 界面显示,加字段 2023-07-17 10:41:46 +08:00
hang 2f5a4d5515 修改查询 2023-07-17 10:17:47 +08:00
hang f7c41d1b9a 修改中心调研 2023-07-14 13:39:15 +08:00
hang fbd24fd059 修改中心调研 2023-07-14 12:43:43 +08:00
hang cc6994e238 修改中心调研 2023-07-14 11:29:30 +08:00
hang 96c07f86b5 发送邮件修改 2023-07-14 09:30:16 +08:00
hang e502721d13 发布修改 2023-07-13 16:06:31 +08:00
hang a3b52dc9ff hang-用户登录日志 -04 2023-07-13 14:07:13 +08:00
hang e07fe76e39 修改任务 2023-07-13 14:06:56 +08:00
hang a4ee90ca5c hang-用户登录日志 -03 2023-07-13 11:29:16 +08:00
hang c016187498 hang-用户登录日志 -02 2023-07-13 11:12:05 +08:00
hang b0d74d31de hang - 用户登录日志修改-01 2023-07-13 10:49:09 +08:00
hang a85255b5fd PI 审核 2023-07-13 09:34:23 +08:00
hang 888dfbcafb 修改解决方案依赖 2023-07-12 15:07:04 +08:00
hang 5de4745303 发送邮件 2023-07-12 14:03:57 +08:00
hang 6883e3b5fa 修改查询 2023-07-12 13:18:24 +08:00
hang ef15b96f15 修改查询列表 2023-07-12 11:41:58 +08:00
hang 03810e0093 国际化 2023-07-12 09:03:50 +08:00
hang bbbc9da76e 修改审核 2023-07-11 16:23:08 +08:00
hang 11b4cf0351 PI 审核接口提交 2023-07-11 11:06:16 +08:00
hang 6df64d68af 修改中心调研 2023-07-11 09:58:09 +08:00
hang 3925fe74af 修改中心调研 2023-07-07 17:59:22 +08:00
hang edb48d8364 修改查询 2023-07-07 17:16:56 +08:00
hang 1d6b67658e 国际化修改 2023-07-07 16:24:37 +08:00
hang bcd1476d2d 修改阅片 2023-07-07 16:18:11 +08:00
hang d2251e4cb2 修改重阅列表 2023-07-07 11:21:38 +08:00
hang bd275539d1 修改定时任务 2023-07-06 16:39:39 +08:00
hang 6042909915 修改默认值 2023-07-06 16:03:24 +08:00
hang 38fc05e0d9 定时任务 2023-07-06 15:10:50 +08:00
hang 3ddbd59995 修改中心调研 2023-07-06 10:23:19 +08:00
hang 0a2a5bdd7a 修改查询条件 2023-07-05 14:39:50 +08:00
hang 088aa83fea 重阅跟踪修改 2023-07-05 14:36:43 +08:00
hang 0797b8b262 中心调研两个版本修改 2023-07-05 11:43:32 +08:00
hang 54a9db2acb 修改调研下拉框 2023-07-05 11:40:04 +08:00
hang e9f88a9c92 修改中心调研 2023-07-05 11:35:31 +08:00
hang 311d651ba7 修改用户类型筛选 2023-07-05 11:24:49 +08:00
hang 7789252f76 修改用户过滤 2023-07-05 10:47:17 +08:00
hang c58e96bce7 修改用户登录日志 2023-07-05 10:35:08 +08:00
hang 2a0ee12780 修改过滤查询 2023-07-05 10:27:26 +08:00
hang e7bc9168ae TA筛选人员,PM 根据标准筛选人员 2023-07-05 10:00:09 +08:00
he 98e5cb4979 修改 2023-07-05 09:37:50 +08:00
hang 6fc6829bc8 hang-S-002增加枚举,修改密码,重置密码,记录日志 2023-07-05 09:37:42 +08:00
hang 516f0fa1b4 hang_S_1_可逆加密算法增加 2023-07-05 09:37:37 +08:00
hang 6f556c45df 用户日志修改 2023-07-04 17:02:51 +08:00
hang e237d58906 修改用户类型 2023-07-04 15:53:38 +08:00
hang cc9807846e Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-07-04 15:04:54 +08:00
hang df7f9dbaeb 编译错误 2023-07-04 15:04:50 +08:00
he dee350742f 修改 2023-07-04 14:35:12 +08:00
he 735f9a9534 修改 2023-07-04 14:35:08 +08:00
he 859f10ee1f 修改 2023-07-04 14:35:06 +08:00
he a002eeed25 修改 2023-07-04 14:35:04 +08:00
he c9c5e5658f 修改 2023-07-04 14:35:01 +08:00
he edfcb53491 修改 2023-07-04 14:34:58 +08:00
he d158c13c7c 修改 2023-07-04 14:34:52 +08:00
he f2dc43b47f 修改 2023-07-04 14:34:47 +08:00
he e7cb246639 修改 2023-07-04 14:34:32 +08:00
he 19d109b3bf 修改 2023-07-04 14:33:46 +08:00
he b2fc4b9886 修改 2023-07-04 14:33:31 +08:00
he e6dd0f0abe 修改 2023-07-04 14:33:27 +08:00
he 6f4186ae07 修改 2023-07-04 14:33:26 +08:00
hang 44a3d03974 修改接口名字 2023-07-04 14:11:50 +08:00
hang 649f6897a4 Merge branch '中心影像_Test环境' of http://192.168.1.2:8033/IRaCIS_Core_Api into 中心影像_Test环境 2023-07-04 14:04:56 +08:00
hang 9edc30cef0 修改限制配置时间 2023-07-04 14:03:06 +08:00
he b0aaa2b791 修改 2023-07-04 13:58:24 +08:00
hang 108a4ee2bf 修改用户类型角色 2023-07-04 13:57:05 +08:00
hang 1083b80849 测试环境修改配置环境,同步中心影像测试 2023-07-04 13:48:05 +08:00
hang a2ff420f89 医学审核修改,暂时不让报错,需要修改之前的接口,待定 2023-07-04 13:34:16 +08:00
hang 5d718f7621 医学审核修改,暂时不让报错,需要修改之前的接口,待定 2023-07-04 13:32:17 +08:00
hang 63096d5919 测试挑拣 2023-07-03 17:13:07 +08:00
hang b80f1794e2 修改配置文件 2023-07-03 17:05:40 +08:00
hang 166c64798e 暂时不让统计报错 2023-07-03 16:58:37 +08:00
hang 150b51b327 修改阅片单元配置 2023-07-03 15:16:52 +08:00
hang 878e9541da 角色列表查询增加展示具体的枚举值 2023-07-03 14:01:18 +08:00
hang 8b416b113c 修改冲突 2023-07-03 13:58:09 +08:00
hang b8dd85c88f 新增配置,加字段,修改查询、编辑接口 2023-07-03 13:57:30 +08:00
hang 7098b15d0d 新增配置,加字段,修改查询、编辑接口 2023-07-03 13:56:51 +08:00
hang 1bd796cd94 项目表增加字段 2023-07-03 13:32:32 +08:00
hang cd41f8f060 模拟提交2 2023-07-03 11:34:43 +08:00
hang 2e117d6641 去掉添加修改项目里面写死的权限控制 2023-07-03 11:21:59 +08:00
hang 70513ff8b8 中心影像首次提交 2023-07-03 11:03:09 +08:00
700 changed files with 21587 additions and 59472 deletions
+1 -6
View File
@@ -22,9 +22,4 @@
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**
README.md
+37 -5
View File
@@ -126,14 +126,46 @@ csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
# SA0001: XML comment analysis disabled
dotnet_diagnostic.SA0001.severity = suggestion
dotnet_diagnostic.CS1570.severity = none
dotnet_diagnostic.CS1587.severity = none
dotnet_diagnostic.CS8619.severity = none
dotnet_diagnostic.CS8620.severity = none
dotnet_diagnostic.CS8632.severity = none
# SA1002: Semicolons should be spaced correctly
dotnet_diagnostic.SA1002.severity = suggestion
# SA1005: Single line comments should begin with single space
dotnet_diagnostic.SA1005.severity = none
dotnet_diagnostic.CS8618.severity = none
dotnet_diagnostic.CS8604.severity = none
dotnet_diagnostic.CS8600.severity = none
dotnet_diagnostic.CS1570.severity = none
dotnet_diagnostic.CS8601.severity = none
dotnet_diagnostic.CS8632.severity = none
dotnet_diagnostic.CS8625.severity = none
dotnet_diagnostic.CS8603.severity = none
dotnet_diagnostic.CS8602.severity = none
dotnet_diagnostic.CS1998.severity = none
dotnet_diagnostic.CS0168.severity = none
dotnet_diagnostic.CS0219.severity = none
dotnet_diagnostic.CS0108.severity = none
dotnet_diagnostic.CS0120.severity = none
dotnet_diagnostic.CS8620.severity = none
dotnet_diagnostic.CS8619.severity = none
dotnet_diagnostic.CS0162.severity = none
dotnet_diagnostic.CS0472.severity = none
dotnet_diagnostic.CS8629.severity = none
dotnet_diagnostic.CS8073.severity = none
dotnet_diagnostic.CS0414.severity = none
dotnet_diagnostic.CS1573.severity = none
dotnet_diagnostic.CS0109.severity = none
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
dotnet_diagnostic.SA1003.severity = silent
dotnet_diagnostic.SA1108.severity = silent
dotnet_diagnostic.SA1107.severity = silent
[*.vb]
#### 命名样式 ####
+26 -4
View File
@@ -1,4 +1,26 @@
FROM registry.cn-shanghai.aliyuncs.com/extimaging/aspnetcore:v8.2
WORKDIR /app
COPY publish .
ENTRYPOINT ["dotnet", "IRaCIS.Core.API.dll"]
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["IRaCIS.Core.API/IRaCIS.Core.API.csproj", "IRaCIS.Core.API/"]
COPY ["IRaCIS.Core.Application/IRaCIS.Core.Application.csproj", "IRaCIS.Core.Application/"]
COPY ["IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj", "IRaCIS.Core.Infra.EFCore/"]
COPY ["IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj", "IRaCIS.Core.Domain/"]
COPY ["IRaCIS.Core.Domain.Share/IRaCIS.Core.Domain.Share.csproj", "IRaCIS.Core.Domain.Share/"]
COPY ["IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj", "IRaCIS.Core.Infrastructure/"]
RUN dotnet restore "IRaCIS.Core.API/IRaCIS.Core.API.csproj"
COPY . .
WORKDIR "/src/IRaCIS.Core.API"
RUN dotnet build "IRaCIS.Core.API.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "IRaCIS.Core.API.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "IRaCIS.Core.API.dll"]
@@ -1,37 +0,0 @@
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Localization;
using Newtonsoft.Json;
namespace IRaCIS.Core.SCP.Filter
{
public class ModelActionFilter : ActionFilterAttribute, IActionFilter
{
public IStringLocalizer _localizer;
public ModelActionFilter(IStringLocalizer localizer)
{
_localizer = localizer;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
var validationErrors = context.ModelState
.Keys
.SelectMany(k => context.ModelState[k]!.Errors)
.Select(e => e.ErrorMessage)
.ToArray();
//---提供给接口的参数无效。
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["ModelAction_InvalidAPIParameter"] + JsonConvert.SerializeObject( validationErrors)));
}
}
}
}
@@ -1,28 +0,0 @@
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace IRaCIS.Core.SCP.Filter
{
#region snippet_DisableFormValueModelBindingAttribute
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
var factories = context.ValueProviderFactories;
//factories.RemoveType<FormValueProviderFactory>();
factories.RemoveType<FormFileValueProviderFactory>();
factories.RemoveType<JQueryFormValueProviderFactory>();
context.HttpContext.Request.EnableBuffering();
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
}
#endregion
}
@@ -1,61 +0,0 @@
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
namespace IRaCIS.Core.SCP.Filter
{
public class ProjectExceptionFilter : Attribute, IExceptionFilter
{
private readonly ILogger<ProjectExceptionFilter> _logger;
public IStringLocalizer _localizer;
public ProjectExceptionFilter(IStringLocalizer localizer, ILogger<ProjectExceptionFilter> logger)
{
_logger = logger;
_localizer = localizer;
}
public void OnException(ExceptionContext context)
{
//context.ExceptionHandled;//记录当前这个异常是否已经被处理过了
if (!context.ExceptionHandled)
{
if (context.Exception.GetType().Name == "DbUpdateConcurrencyException")
{
//---并发更新,当前不允许该操作
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["ProjectException_ConcurrentUpdateNotAllowed"] + context.Exception.Message));
}
if (context.Exception.GetType() == typeof(BusinessValidationFailedException))
{
var error = context.Exception as BusinessValidationFailedException;
context.Result = new JsonResult(ResponseOutput.NotOk(context.Exception.Message, error!.Code));
}
else if(context.Exception.GetType() == typeof(QueryBusinessObjectNotExistException))
{
context.Result = new JsonResult(ResponseOutput.NotOk( context.Exception.Message, ApiResponseCodeEnum.DataNotExist));
}
else
{
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["Project_ExceptionContactDeveloper"] + (context.Exception.InnerException is null ? (context.Exception.Message /*+ context.Exception.StackTrace*/)
: (context.Exception.InnerException?.Message /*+ context.Exception.InnerException?.StackTrace*/)), ApiResponseCodeEnum.ProgramException));
}
_logger.LogError(context.Exception.InnerException is null ? (context.Exception.Message + context.Exception.StackTrace) : (context.Exception.InnerException?.Message + context.Exception.InnerException?.StackTrace));
}
else
{
//继续
}
context.ExceptionHandled = true;//标记当前异常已经被处理过了
}
}
}
@@ -1,120 +0,0 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Services.BusinessFilter
{
/// <summary>
/// 统一返回前端数据包装,之前在控制器包装,现在修改为动态Api 在ResultFilter这里包装,减少重复冗余代码
/// by zhouhang 2021.09.12 周末
/// </summary>
public class UnifiedApiResultFilter : Attribute, IAsyncResultFilter
{
/// <summary>
/// 异步版本
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
if (context.Result is ObjectResult objectResult)
{
var statusCode = objectResult.StatusCode ?? context.HttpContext.Response.StatusCode;
//是200 并且没有包装 那么包装结果
if (statusCode == 200 && !(objectResult.Value is IResponseOutput))
{
//if (objectResult.Value == null)
//{
// var apiResponse = ResponseOutput.DBNotExist();
// objectResult.Value = apiResponse;
// objectResult.DeclaredType = apiResponse.GetType();
//}
//else
//{
var type = objectResult.Value?.GetType();
if ( type!=null&& type.IsGenericType&&(type.GetGenericTypeDefinition()==typeof(ValueTuple<,>)|| type.GetGenericTypeDefinition()==typeof(Tuple<,>)))
{
//报错
//var tuple = (object, object))objectResult.Value;
//var (val1, val2) = ((dynamic, dynamic))objectResult.Value;
//var apiResponse = ResponseOutput.Ok(val1, val2);
//OK
var tuple = (dynamic)objectResult.Value;
var apiResponse = ResponseOutput.Ok(tuple.Item1, tuple.Item2);
objectResult.Value = apiResponse;
objectResult.DeclaredType = apiResponse.GetType();
}
else
{
var apiResponse = ResponseOutput.Ok(objectResult.Value);
objectResult.Value = apiResponse;
objectResult.DeclaredType = apiResponse.GetType();
}
//}
}
//如果不是200 是IResponseOutput 不处理
else if (statusCode != 200 && (objectResult.Value is IResponseOutput))
{
}
else if(statusCode != 200&&!(objectResult.Value is IResponseOutput))
{
//---程序错误,请联系开发人员。
var apiResponse = ResponseOutput.NotOk(StaticData.International("UnifiedAPI_ProgramError"));
objectResult.Value = apiResponse;
objectResult.DeclaredType = apiResponse.GetType();
}
}
await next.Invoke();
}
public static bool IsTupleType(Type type, bool checkBaseTypes = false)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
if (type == typeof(Tuple))
return true;
while (type != null)
{
if (type.IsGenericType)
{
var genType = type.GetGenericTypeDefinition();
if (genType == typeof(Tuple<>)
|| genType == typeof(Tuple<,>)
|| genType == typeof(Tuple<,>))
return true;
}
if (!checkBaseTypes)
break;
type = type.BaseType;
}
return false;
}
}
}
-62
View File
@@ -1,62 +0,0 @@
using FellowOakDicom.Imaging;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using System.Security.Cryptography;
using System.Text;
namespace IRaCIS.Core.Application.Helper;
public static class ImageHelper
{
// 采用ImageSharp组件 跨平台,不依赖windows 平台图像处理组件,这里大坑(net 6 下,之前由于Dicom处理最新组件 依赖了这个库的一个旧版本,导致缩略图bug,单独升级依赖组件才解决)
public static void ResizeSave(string filePath, string? fileStorePath)
{
fileStorePath = fileStorePath ?? filePath + ".preview.jpeg";
using (var image = SixLabors.ImageSharp.Image.Load(filePath))
{
image.Mutate(x => x.Resize(500, 500));
image.Save(fileStorePath);
}
}
public static Stream RenderPreviewJpeg(string filePath)
{
string jpegPath = filePath + ".preview.jpg";
if (!File.Exists(jpegPath))
{
using (Stream stream = new FileStream(jpegPath, FileMode.Create))
{
DicomImage image = new DicomImage(filePath);
var sharpimage = image.RenderImage().AsSharpImage();
sharpimage.Save(stream, new JpegEncoder());
}
}
return new FileStream(jpegPath, FileMode.Open);
}
public static void RemovePreviewJpeg(string filePath)
{
string jpegPath = filePath + ".preview.jpg";
if (File.Exists(jpegPath)) File.Delete(jpegPath);
}
}
@@ -1,57 +0,0 @@
using Autofac;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Http;
using Panda.DynamicWebApi;
using System;
using System.Linq;
using System.Reflection;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Application.Services;
using AutoMapper;
using IRaCIS.Core.SCP.Service;
namespace IRaCIS.Core.SCP
{
// ReSharper disable once IdentifierTypo
public class AutofacModuleSetup : Autofac.Module
{
protected override void Load(ContainerBuilder containerBuilder)
{
#region byzhouhang 20210917 Domain层 Infra.EFcore
containerBuilder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepository<>)).InstancePerLifetimeScope();//注册泛型仓储
containerBuilder.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
#endregion
#region autofac https://www.cnblogs.com/xwhqwer/p/15320838.html
//获取所有控制器类型并使用属性注入
containerBuilder.RegisterAssemblyTypes(typeof(BaseService).Assembly)
.Where(type => typeof(IDynamicWebApi).IsAssignableFrom(type))
.PropertiesAutowired();
#endregion
Assembly application = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + typeof(BaseService).Assembly.GetName().Name+".dll");
containerBuilder.RegisterAssemblyTypes(application).Where(t => t.FullName.Contains("Service"))
.PropertiesAutowired().AsImplementedInterfaces();
//containerBuilder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
//containerBuilder.RegisterType<UserInfo>().As<IUserInfo>().InstancePerLifetimeScope();
}
}
}
-64
View File
@@ -1,64 +0,0 @@
using EntityFramework.Exceptions.SqlServer;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore;
using Medallion.Threading;
using Medallion.Threading.SqlServer;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace IRaCIS.Core.SCP
{
public static class EFSetup
{
public static void AddEFSetup( this IServiceCollection services, IConfiguration configuration)
{
services.AddHttpContextAccessor();
services.AddScoped<IUserInfo, UserInfo>();
services.AddScoped<ISaveChangesInterceptor, AuditEntityInterceptor>();
//这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext
//Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点
services.AddDbContext<IRaCISDBContext>((sp, options) =>
{
// 在控制台
//public static readonly ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });
var logFactory = LoggerFactory.Create(builder => { builder.AddDebug(); });
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value,
contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
options.UseLoggerFactory(logFactory);
options.UseExceptionProcessor();
options.EnableSensitiveDataLogging();
options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor());
options.AddInterceptors(sp.GetServices<ISaveChangesInterceptor>());
options.UseProjectables();
});
//// Register an additional context factory as a Scoped service, which gets a pooled context from the Singleton factory we registered above,
//services.AddScoped<IRaCISDBScopedFactory>();
//// Finally, arrange for a context to get injected from our Scoped factory:
//services.AddScoped(sp => sp.GetRequiredService<IRaCISDBScopedFactory>().CreateDbContext());
//注意区分 easy caching 也有 IDistributedLockProvider
services.AddSingleton<IDistributedLockProvider>(sp =>
{
//var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!);
return new SqlDistributedSynchronizationProvider(configuration.GetSection("ConnectionStrings:RemoteNew").Value);
});
}
}
}
@@ -1,59 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
namespace IRaCIS.Core.SCP
{
public static class NewtonsoftJsonSetup
{
public static void AddNewtonsoftJsonSetup(this IMvcBuilder builder, IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddScoped<IOSSService,OSSService>();
builder.AddNewtonsoftJson(options =>
{
//options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
// 忽略循环引用
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
//options.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
//处理返回给前端 可空类型 给出默认值 比如in? 为null 设置 默认值0
options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver(); //new DefaultContractResolver();// new NullToEmptyStringResolver();
// 设置时间格式
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
//options.SerializerSettings.Converters.Add(new JSONCustomDateConverter()) ;
//options.SerializerSettings.Converters.Add(services.BuildServiceProvider().GetService<JSONTimeZoneConverter>());
})
.AddControllersAsServices()//动态webApi属性注入需要
.ConfigureApiBehaviorOptions(o =>
{
o.SuppressModelStateInvalidFilter = true; //自己写验证
});
Newtonsoft.Json.JsonSerializerSettings setting = new Newtonsoft.Json.JsonSerializerSettings();
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
setting.DateFormatString = "yyyy-MM-dd HH:mm:ss";
setting.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
return setting;
});
}
}
}
@@ -1,36 +0,0 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
namespace IRaCIS.Core.SCP
{
public class NullToEmptyStringResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
var list= type.GetProperties()
.Select(p =>
{
var jp = base.CreateProperty(p, memberSerialization);
jp.ValueProvider = new NullToEmptyStringValueProvider(p);
return jp;
}).ToList();
var uu = list.Select(t => t.PropertyName).ToList();
//获取复杂对象属性
properties = properties.TakeWhile(t => !uu.Contains(t.PropertyName)).ToList();
list.AddRange(properties);
return list;
}
}
}
@@ -1,42 +0,0 @@
using System;
using System.Reflection;
using Newtonsoft.Json.Serialization;
namespace IRaCIS.Core.SCP
{
public class NullToEmptyStringValueProvider : IValueProvider
{
PropertyInfo _MemberInfo;
public NullToEmptyStringValueProvider(PropertyInfo memberInfo)
{
_MemberInfo = memberInfo;
}
public object GetValue(object target)
{
object result = _MemberInfo.GetValue(target);
if (_MemberInfo.PropertyType == typeof(string) && result == null) result = "";
else if (_MemberInfo.PropertyType == typeof(String[]) && result == null) result = new string[] { };
//else if (_MemberInfo.PropertyType == typeof(Nullable<Int32>) && result == null) result = 0;
else if (_MemberInfo.PropertyType == typeof(Nullable<Decimal>) && result == null) result = 0.00M;
return result;
}
public void SetValue(object target, object value)
{
if(_MemberInfo.PropertyType == typeof(string))
{
//去掉前后空格
_MemberInfo.SetValue(target, value==null?string.Empty: value.ToString()==string.Empty? value:value.ToString().Trim());
}
else
{
_MemberInfo.SetValue(target, value);
}
}
}
}
-36
View File
@@ -1,36 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
<PackageReference Include="DistributedLock.Core" Version="1.0.7" />
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.5" />
<PackageReference Include="fo-dicom" Version="5.1.3" />
<PackageReference Include="fo-dicom.Codecs" Version="5.14.5" />
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.8" />
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Minio" Version="6.0.3" />
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.1.1" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\IRaCIS.Core.Domain\IRaCIS.Core.Domain.csproj" />
<ProjectReference Include="..\IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj" />
</ItemGroup>
</Project>
-214
View File
@@ -1,214 +0,0 @@
using Autofac;
using Autofac.Extensions.DependencyInjection;
using AutoMapper.EquivalencyExpression;
using FellowOakDicom;
using FellowOakDicom.Imaging;
using FellowOakDicom.Imaging.NativeCodec;
using FellowOakDicom.Network;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.SCP;
using IRaCIS.Core.SCP.Filter;
using IRaCIS.Core.SCP.Service;
using MassTransit;
using MassTransit.NewIdProviders;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection;
using Panda.DynamicWebApi;
using Serilog;
using Serilog.Events;
using System.Runtime.InteropServices;
//以配置文件为准,否则 从url中取环境值(服务以命令行传递参数启动,配置文件配置了就不需要传递环境参数)
var config = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build();
var enviromentName = config["ASPNETCORE_ENVIRONMENT"];
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
EnvironmentName = enviromentName
});
#region windows
int urlsIndex = Array.FindIndex(args, arg => arg != null && arg.StartsWith("--port"));
if (urlsIndex > -1)
{
var port = args[urlsIndex].Substring("--port=".Length);
Console.WriteLine(port);
builder.WebHost.UseUrls($"http://0.0.0.0:{port}");
}
#endregion
#region
NewId.SetProcessIdProvider(new CurrentProcessIdProvider());
builder.Configuration.AddJsonFile("appsettings.json", false, true)
.AddJsonFile($"appsettings.{enviromentName}.json", false, true);
builder.Host
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
containerBuilder.RegisterModule<AutofacModuleSetup>();
})
.UseSerilog();
#endregion
#region
var _configuration = builder.Configuration;
//健康检查
builder.Services.AddHealthChecks();
//本地化
builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resources");
// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
builder.Services.AddControllers(options =>
{
options.Filters.Add<ModelActionFilter>();
options.Filters.Add<ProjectExceptionFilter>();
options.Filters.Add<UnitOfWorkFilter>();
})
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
builder.Services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
builder.Services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
builder.Services.AddOptions().Configure<DicomSCPServiceOption>(_configuration.GetSection("DicomSCPServiceConfig"));
//动态WebApi + UnifiedApiResultFilter 省掉控制器代码
//动态webApi 目前存在的唯一小坑是生成api上服务上的动态代理AOP失效 间接掉用不影响
builder.Services
.AddDynamicWebApi(dynamicWebApiOption =>
{
//默认是 api
dynamicWebApiOption.DefaultApiPrefix = "";
//首字母小写
dynamicWebApiOption.GetRestFulActionName = (actionName) => char.ToLower(actionName[0]) + actionName.Substring(1);
//删除 Service后缀
dynamicWebApiOption.RemoveControllerPostfixes.Add("Service");
});
//AutoMapper
builder.Services.AddAutoMapper(automapper =>
{
automapper.AddCollectionMappers();
}, typeof(BaseService).Assembly);
//EF ORM QueryWithNoLock
builder.Services.AddEFSetup(_configuration);
//转发头设置 获取真实IP
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
//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.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
//if (app.Environment.IsDevelopment())
//{
app.UseSwagger();
app.UseSwaggerUI();
//}
app.UseAuthorization();
app.MapControllers();
#region
//Log.Logger = new LoggerConfiguration()
// .MinimumLevel.Information()
// .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
// // Filter out ASP.NET Core infrastructre logs that are Information and below 日志太多了 一个请求 记录好几条
// .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
// .MinimumLevel.Override("Hangfire", LogEventLevel.Warning)
// .MinimumLevel.Override("System.Net.Http.HttpClient.HttpReports", LogEventLevel.Warning)
// .Enrich.WithClientIp()
// .Enrich.FromLogContext()
// //控制台 方便调试 问题 我们显示记录日志 时 获取上下文的ip 和用户名 用户类型
// .WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Warning,
// outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext:l} || {Message} || {Exception} ||end {NewLine}")
// .WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day,
// outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext:l} || {Message} || {Exception} ||end {NewLine}")
// .CreateLogger();
Log.Logger = new LoggerConfiguration()
//.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.WriteTo.Console()
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day)
.CreateLogger();
#endregion
#region
Log.Logger.Warning($"当前环境:{enviromentName}");
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Log.Logger.Warning($"当前部署平台环境:windows");
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Log.Logger.Warning($"当前部署平台环境:linux");
}
else
{
Log.Logger.Warning($"当前部署平台环境:OSX or FreeBSD");
}
#endregion
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();
@@ -1,25 +0,0 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"Test_IRC_SCP": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:6200",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Test_IRC_SCP"
}
},
"Uat_IRC_SCP": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:6200",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Uat_IRC_SCP"
}
}
}
}
-111
View File
@@ -1,111 +0,0 @@
using AutoMapper;
using IRaCIS.Application.Services.BusinessFilter;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Localization;
using Panda.DynamicWebApi;
using Panda.DynamicWebApi.Attributes;
using System.Diagnostics.CodeAnalysis;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure.Extention;
using IRaCIS.Core.Domain.Models;
namespace IRaCIS.Core.SCP.Service
{
#pragma warning disable CS8618
#region
[Authorize, DynamicWebApi, UnifiedApiResultFilter]
public class BaseService : IBaseService, IDynamicWebApi
{
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
public IStringLocalizer _localizer { get; set; }
public IWebHostEnvironment _hostEnvironment { get; set; }
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
{
return new ResponseOutput<string>()
.NotOk($"The query object {typeof(TEntity).Name} does not exist , or was deleted by someone else, or an incorrect parameter query caused", code: ApiResponseCodeEnum.DataNotExist);
}
}
public interface IBaseService
{
[MemberNotNull(nameof(_mapper))]
public IMapper _mapper { get; set; }
[MemberNotNull(nameof(_userInfo))]
public IUserInfo _userInfo { get; set; }
[MemberNotNull(nameof(_localizer))]
public IStringLocalizer _localizer { get; set; }
[MemberNotNull(nameof(_hostEnvironment))]
public IWebHostEnvironment _hostEnvironment { get; set; }
}
#endregion
#region
public interface IBaseServiceTest<T> where T : Entity
{
[MemberNotNull(nameof(_mapper))]
public IMapper _mapper { get; set; }
[MemberNotNull(nameof(_userInfo))]
public IUserInfo _userInfo { get; set; }
[MemberNotNull(nameof(_localizer))]
public IStringLocalizer _localizer { get; set; }
}
[Authorize, DynamicWebApi, UnifiedApiResultFilter]
public class BaseServiceTest<T> : IBaseServiceTest<T>, IDynamicWebApi where T : Entity
{
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
public IStringLocalizer _localizer { get; set; }
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
{
return new ResponseOutput<string>()
.NotOk($"The query object {typeof(TEntity).Name} does not exist , or was deleted by someone else, or an incorrect parameter query caused", code: ApiResponseCodeEnum.DataNotExist);
}
}
#endregion
}
-370
View File
@@ -1,370 +0,0 @@
using FellowOakDicom.Network;
using FellowOakDicom;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using IRaCIS.Core.SCP.Service;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infra.EFCore;
using Medallion.Threading;
using IRaCIS.Core.Domain.Share;
using Serilog;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
using Microsoft.Extensions.Options;
using System.Data;
using FellowOakDicom.Imaging;
using SharpCompress.Common;
using SixLabors.ImageSharp.Formats.Jpeg;
using IRaCIS.Core.Infrastructure;
namespace IRaCIS.Core.SCP.Service
{
public class DicomSCPServiceOption
{
public List<string> CalledAEList { get; set; }
public string ServerPort { get; set; }
}
public class CStoreSCPService : DicomService, IDicomServiceProvider, IDicomCStoreProvider, IDicomCEchoProvider
{
private IServiceProvider _serviceProvider { get; set; }
private List<Guid> _SCPStudyIdList { get; set; } = new List<Guid>();
private SCPImageUpload _upload { get; set; }
private Guid _trialId { get; set; }
private Guid _trialSiteId { get; set; }
private static readonly DicomTransferSyntax[] _acceptedTransferSyntaxes = new DicomTransferSyntax[]
{
DicomTransferSyntax.ExplicitVRLittleEndian,
DicomTransferSyntax.ExplicitVRBigEndian,
DicomTransferSyntax.ImplicitVRLittleEndian
};
private static readonly DicomTransferSyntax[] _acceptedImageTransferSyntaxes = new DicomTransferSyntax[]
{
// Lossless
DicomTransferSyntax.JPEGLSLossless, //1.2.840.10008.1.2.4.80
DicomTransferSyntax.JPEG2000Lossless, //1.2.840.10008.1.2.4.90
DicomTransferSyntax.JPEGProcess14SV1, //1.2.840.10008.1.2.4.70
DicomTransferSyntax.JPEGProcess14, //1.2.840.10008.1.2.4.57 JPEG Lossless, Non-Hierarchical (Process 14)
DicomTransferSyntax.RLELossless, //1.2.840.10008.1.2.5
// Lossy
DicomTransferSyntax.JPEGLSNearLossless,//1.2.840.10008.1.2.4.81"
DicomTransferSyntax.JPEG2000Lossy, //1.2.840.10008.1.2.4.91
DicomTransferSyntax.JPEGProcess1, //1.2.840.10008.1.2.4.50
DicomTransferSyntax.JPEGProcess2_4, //1.2.840.10008.1.2.4.51
// Uncompressed
DicomTransferSyntax.ExplicitVRLittleEndian, //1.2.840.10008.1.2.1
DicomTransferSyntax.ExplicitVRBigEndian, //1.2.840.10008.1.2.2
DicomTransferSyntax.ImplicitVRLittleEndian //1.2.840.10008.1.2
};
public CStoreSCPService(INetworkStream stream, Encoding fallbackEncoding, Microsoft.Extensions.Logging.ILogger log, DicomServiceDependencies dependencies)
: base(stream, fallbackEncoding, log, dependencies)
{
}
public Task OnReceiveAssociationRequestAsync(DicomAssociation association)
{
_upload = new SCPImageUpload() { StartTime = DateTime.Now, CallingAE = association.CallingAE, CalledAE = association.CalledAE, CallingAEIP = association.RemoteHost };
Log.Logger.Warning($"接收到来自{association.CallingAE}的连接");
_serviceProvider = (IServiceProvider)this.UserState;
var _trialDicomAERepository = _serviceProvider.GetService<IRepository<TrialDicomAE>>();
var trialDicomAEList = _trialDicomAERepository.Select(t => new { t.CalledAE, t.TrialId }).ToList();
var trialCalledAEList = trialDicomAEList.Select(t => t.CalledAE).ToList();
Log.Logger.Information("当前系统配置:", string.Join('|', trialDicomAEList));
var findCalledAE = trialDicomAEList.Where(t => t.CalledAE == association.CalledAE).FirstOrDefault();
var isCanReceiveIamge = false;
if (findCalledAE != null)
{
_trialId = findCalledAE.TrialId;
var _trialSiteDicomAERepository = _serviceProvider.GetService<IRepository<TrialSiteDicomAE>>();
var findTrialSiteAE = _trialSiteDicomAERepository.Where(t => t.CallingAE == association.CallingAE && t.TrialId==_trialId).FirstOrDefault();
if (findTrialSiteAE != null)
{
_trialSiteId = findTrialSiteAE.TrialSiteId;
isCanReceiveIamge = true;
}
}
if (association.CallingAE == "test-callingAE")
{
isCanReceiveIamge = true;
}
if (!trialCalledAEList.Contains(association.CalledAE) || isCanReceiveIamge == false)
{
Log.Logger.Warning($"拒绝CallingAE:{association.CallingAE} CalledAE:{association.CalledAE}的连接");
return SendAssociationRejectAsync(
DicomRejectResult.Permanent,
DicomRejectSource.ServiceUser,
DicomRejectReason.CalledAENotRecognized);
}
foreach (var pc in association.PresentationContexts)
{
if (pc.AbstractSyntax == DicomUID.Verification)
{
pc.AcceptTransferSyntaxes(_acceptedTransferSyntaxes);
}
else if (pc.AbstractSyntax.StorageCategory != DicomStorageCategory.None)
{
pc.AcceptTransferSyntaxes(_acceptedImageTransferSyntaxes);
}
}
return SendAssociationAcceptAsync(association);
}
public async Task OnReceiveAssociationReleaseRequestAsync()
{
await DataMaintenanceAsaync();
//记录监控
var _SCPImageUploadRepository = _serviceProvider.GetService<IRepository<SCPImageUpload>>();
_upload.EndTime = DateTime.Now;
_upload.StudyCount = _SCPStudyIdList.Count;
_upload.TrialId = _trialId;
_upload.TrialSiteId = _trialSiteId;
await _SCPImageUploadRepository.AddAsync(_upload, true);
await SendAssociationReleaseResponseAsync();
}
private async Task DataMaintenanceAsaync()
{
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}传输结束:开始维护数据,处理检查Modality");
//处理检查Modality
var _dictionaryRepository = _serviceProvider.GetService<IRepository<Dictionary>>();
var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
var dicModalityList = _dictionaryRepository.Where(t => t.Code == "Modality").SelectMany(t => t.ChildList.Select(c => c.Value)).ToList();
var seriesModalityList = _seriesRepository.Where(t => _SCPStudyIdList.Contains(t.StudyId)).Select(t => new { SCPStudyId = t.StudyId, t.Modality }).ToList();
foreach (var g in seriesModalityList.GroupBy(t => t.SCPStudyId))
{
var modality = string.Join('、', g.Select(t => t.Modality).Distinct().ToList());
//特殊逻辑
var modalityForEdit = dicModalityList.Contains(modality) ? modality : String.Empty;
if (modality == "MR")
{
modalityForEdit = "MRI";
}
if (modality == "PT")
{
modalityForEdit = "PET";
}
if (modality == "PT、CT" || modality == "CT、PT")
{
modalityForEdit = "PET-CT";
}
await _studyRepository.BatchUpdateNoTrackingAsync(t => t.Id == g.Key, u => new SCPStudy() { Modalities = modality, ModalityForEdit = modalityForEdit });
}
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}维护数据结束");
}
public void OnReceiveAbort(DicomAbortSource source, DicomAbortReason reason)
{
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}接收中断,中断原因:{source.ToString() + reason.ToString()}");
/* nothing to do here */
}
public async void OnConnectionClosed(Exception exception)
{
/* nothing to do here */
//奇怪的bug 上传的时候,用王捷修改的影像,会关闭,重新连接,导致检查id 丢失,然后状态不一致
if (exception == null)
{
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
//将检查设置为传输结束
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
}
Log.Logger.Warning($"连接关闭 {exception?.Message} {exception?.InnerException?.Message}");
}
public async Task<DicomCStoreResponse> OnCStoreRequestAsync(DicomCStoreRequest request)
{
string studyInstanceUid = request.Dataset.GetString(DicomTag.StudyInstanceUID);
string seriesInstanceUid = request.Dataset.GetString(DicomTag.SeriesInstanceUID);
string sopInstanceUid = request.Dataset.GetString(DicomTag.SOPInstanceUID);
//Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid, trialId.ToString());
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, _trialId.ToString());
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, _trialId.ToString());
var ossService = _serviceProvider.GetService<IOSSService>();
var dicomArchiveService = _serviceProvider.GetService<IDicomArchiveService>();
var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();
var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();
var storeRelativePath = string.Empty;
var ossFolderPath = $"{_trialId}/Image/PACS/{_trialSiteId}{studyInstanceUid}";
long fileSize = 0;
try
{
using (MemoryStream ms = new MemoryStream())
{
await request.File.SaveAsync(ms);
//irc 从路径最后一截取Guid
storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false);
fileSize = ms.Length;
}
Log.Logger.Information($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} {request.SOPInstanceUID} 上传完成 ");
}
catch (Exception ec)
{
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 上传异常 {ec.Message}");
}
var @lock = _distributedLockProvider.CreateLock($"{studyInstanceUid}");
using (await @lock.AcquireAsync())
{
try
{
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.Dataset, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE,fileSize);
if (!_SCPStudyIdList.Contains(scpStudyId))
{
_SCPStudyIdList.Add(scpStudyId);
}
var series = await _seriesRepository.FindAsync(seriesId);
//没有缩略图
if (series != null && string.IsNullOrEmpty(series.ImageResizePath))
{
// 生成缩略图
using (var memoryStream = new MemoryStream())
{
DicomImage image = new DicomImage(request.Dataset);
var sharpimage = image.RenderImage().AsSharpImage();
sharpimage.Save(memoryStream, new JpegEncoder());
// 上传缩略图到 OSS
var seriesPath = await ossService.UploadToOSSAsync(memoryStream, ossFolderPath, seriesId.ToString() + ".preview.jpg", false);
Console.WriteLine(seriesPath + " Id: " + seriesId);
series.ImageResizePath = seriesPath;
}
}
await _seriesRepository.SaveChangesAsync();
}
catch (Exception ex)
{
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 传输处理异常:{ex.ToString()}");
}
}
//监控信息设置
_upload.FileCount++;
_upload.FileSize = _upload.FileSize + fileSize;
return new DicomCStoreResponse(request, DicomStatus.Success);
}
public Task OnCStoreRequestExceptionAsync(string tempFileName, Exception e)
{
// let library handle logging and error response
return Task.CompletedTask;
}
public Task<DicomCEchoResponse> OnCEchoRequestAsync(DicomCEchoRequest request)
{
return Task.FromResult(new DicomCEchoResponse(request, DicomStatus.Success));
}
}
}
-356
View File
@@ -1,356 +0,0 @@
using IRaCIS.Core.Domain.Share;
using System.Text;
using Microsoft.AspNetCore.Hosting;
using IRaCIS.Core.Infrastructure;
using Medallion.Threading;
using FellowOakDicom;
using FellowOakDicom.Imaging.Codec;
using System.Data;
using IRaCIS.Core.Domain.Models;
using FellowOakDicom.Network;
using IRaCIS.Core.SCP.Service;
using IRaCIS.Core.Infra.EFCore;
using MassTransit;
using System.Runtime.Intrinsics.X86;
using Serilog.Sinks.File;
namespace IRaCIS.Core.SCP.Service
{
public class DicomArchiveService : BaseService, IDicomArchiveService
{
private readonly IRepository<SCPPatient> _patientRepository;
private readonly IRepository<SCPStudy> _studyRepository;
private readonly IRepository<SCPSeries> _seriesRepository;
private readonly IRepository<SCPInstance> _instanceRepository;
private readonly IRepository<Dictionary> _dictionaryRepository;
private readonly IDistributedLockProvider _distributedLockProvider;
private List<Guid> _instanceIdList = new List<Guid>();
public DicomArchiveService(IRepository<SCPPatient> patientRepository, IRepository<SCPStudy> studyRepository,
IRepository<SCPSeries> seriesRepository,
IRepository<SCPInstance> instanceRepository,
IRepository<Dictionary> dictionaryRepository,
IDistributedLockProvider distributedLockProvider)
{
_distributedLockProvider = distributedLockProvider;
_studyRepository = studyRepository;
_patientRepository = patientRepository;
_seriesRepository = seriesRepository;
_instanceRepository = instanceRepository;
_dictionaryRepository = dictionaryRepository;
}
/// <summary>
/// 单个文件接收 归档
/// </summary>
/// <param name="dataset"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<Guid> ArchiveDicomFileAsync(DicomDataset dataset, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize)
{
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID,string.Empty);
//Guid patientId= IdentifierHelper.CreateGuid(patientIdStr);
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid,trialId.ToString());
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, trialId.ToString());
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, trialId.ToString());
var isStudyNeedAdd = false;
var isSeriesNeedAdd = false;
var isInstanceNeedAdd = false;
var isPatientNeedAdd = false;
//var @lock = _distributedLockProvider.CreateLock($"{studyInstanceUid}");
//using (@lock.Acquire())
{
var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr && t.TrialSiteId==trialSiteId );
var findStudy = await _studyRepository.FindAsync(studyId);
var findSerice = await _seriesRepository.FindAsync(seriesId);
var findInstance = await _instanceRepository.FindAsync(instanceId);
DateTime? studyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.StudyTime).TimeOfDay);
//先传输了修改了患者编号的,又传输了没有修改患者编号的,导致后传输的没有修改患者编号的下面的检查为0
if (findPatient == null && findStudy==null)
{
isPatientNeedAdd = true;
findPatient = new SCPPatient()
{
Id = NewId.NextSequentialGuid(),
TrialId=trialId,
TrialSiteId=trialSiteId,
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
EarliestStudyTime = studyTime,
LatestStudyTime = studyTime,
LatestPushTime = DateTime.Now,
};
if (findPatient.PatientBirthDate.Length == 8)
{
var birthDateStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}-{findPatient.PatientBirthDate[4]}{findPatient.PatientBirthDate[5]}-{findPatient.PatientBirthDate[6]}{findPatient.PatientBirthDate[7]}";
var yearStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}";
int year = 0;
var canParse = int.TryParse(yearStr, out year);
if (canParse && year > 1900)
{
findPatient.PatientBirthDate = birthDateStr;
DateTime birthDate;
if (findPatient.PatientAge == string.Empty && studyTime.HasValue && DateTime.TryParse(findPatient.PatientBirthDate,out birthDate))
{
var patientAge = studyTime.Value.Year - birthDate.Year;
// 如果生日还未到,年龄减去一岁
if (studyTime.Value < birthDate.AddYears(patientAge))
{
patientAge--;
}
findPatient.PatientAge = patientAge.ToString();
}
}
else
{
findPatient.PatientBirthDate = string.Empty;
}
}
}
else
{
if (studyTime < findPatient.EarliestStudyTime)
{
findPatient.EarliestStudyTime = studyTime;
}
if (studyTime > findPatient.LatestStudyTime)
{
findPatient.LatestStudyTime = studyTime;
}
findPatient.LatestPushTime = DateTime.Now;
}
if (findStudy == null)
{
isStudyNeedAdd = true;
findStudy = new SCPStudy
{
CalledAE = calledAE,
CallingAE = callingAE,
PatientId = findPatient.Id,
Id = studyId,
TrialId = trialId,
TrialSiteId = trialSiteId,
StudyInstanceUid = studyInstanceUid,
StudyTime = studyTime,
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
//ModalityForEdit = modalityForEdit,
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
InstitutionName = dataset.GetSingleValueOrDefault(DicomTag.InstitutionName, string.Empty),
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),
//需要特殊处理
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
//IsDoubleReview = addtionalInfo.IsDoubleReview,
SeriesCount = 0,
InstanceCount = 0
};
if (findStudy.PatientBirthDate.Length == 8)
{
findStudy.PatientBirthDate = $"{findStudy.PatientBirthDate[0]}{findStudy.PatientBirthDate[1]}{findStudy.PatientBirthDate[2]}{findStudy.PatientBirthDate[3]}-{findStudy.PatientBirthDate[4]}{findStudy.PatientBirthDate[5]}-{findStudy.PatientBirthDate[6]}{findStudy.PatientBirthDate[7]}";
}
}
if (findSerice == null)
{
isSeriesNeedAdd = true;
findSerice = new SCPSeries
{
Id = seriesId,
StudyId = findStudy.Id,
StudyInstanceUid = findStudy.StudyInstanceUid,
SeriesInstanceUid = seriesInstanceUid,
SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
//SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay),
//SeriesTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.SeriesDate) + dataset.GetSingleValue<string>(DicomTag.SeriesTime), out DateTime dt) ? dt : null,
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay),
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
ImagePositionPatient = dataset.GetSingleValueOrDefault(DicomTag.ImagePositionPatient, string.Empty),
ImageOrientationPatient = dataset.GetSingleValueOrDefault(DicomTag.ImageOrientationPatient, string.Empty),
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
SequenceName = dataset.GetSingleValueOrDefault(DicomTag.SequenceName, string.Empty),
ProtocolName = dataset.GetSingleValueOrDefault(DicomTag.ProtocolName, string.Empty),
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
InstanceCount = 0
};
++findStudy.SeriesCount;
}
if (findInstance == null)
{
isInstanceNeedAdd = true;
findInstance = new SCPInstance
{
Id = instanceId,
StudyId = findStudy.Id,
SeriesId = findSerice.Id,
StudyInstanceUid = findStudy.StudyInstanceUid,
SeriesInstanceUid = findSerice.SeriesInstanceUid,
SopInstanceUid = sopInstanceUid,
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.ContentDate).Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.ContentTime).TimeOfDay),
//InstanceTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.ContentDate) + dataset.GetSingleValue<string>(DicomTag.ContentTime), out DateTime dt) ? dt : null,
//InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate,(DateTime?)null)?.Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, TimeSpan.Zero)),
//dataset.GetSingleValueOrDefault(DicomTag.ContentDate,DateTime.Now);//, DicomTag.ContentTime)
CPIStatus = false,
ImageRows = dataset.GetSingleValueOrDefault(DicomTag.Rows, 0),
ImageColumns = dataset.GetSingleValueOrDefault(DicomTag.Columns, 0),
SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0),
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 0),
PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty),
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty),
WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty),
WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty),
Path = fileRelativePath,
FileSize= fileSize,
};
++findStudy.InstanceCount;
++findSerice.InstanceCount;
}
if (isPatientNeedAdd)
{
var ss = await _patientRepository.AddAsync(findPatient);
}
if (isStudyNeedAdd)
{
var dd = await _studyRepository.AddAsync(findStudy);
}
else
{
await _studyRepository.BatchUpdateNoTrackingAsync(t => t.Id == findStudy.Id, t => new SCPStudy() { IsUploadFinished = false });
}
if (isSeriesNeedAdd)
{
await _seriesRepository.AddAsync(findSerice);
}
if (isInstanceNeedAdd)
{
await _instanceRepository.AddAsync(findInstance);
}
else
{
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath,FileSize=fileSize });
}
//await _studyRepository.SaveChangesAsync();
return findStudy.Id;
}
}
// 从DICOM文件中获取使用的字符集
private string GetEncodingVaulueFromDicomFile(DicomDataset dataset, DicomTag dicomTag)
{
// 获取DICOM文件的特定元素,通常用于指示使用的字符集
var charset = dataset.GetSingleValueOrDefault(DicomTag.SpecificCharacterSet, string.Empty);
var dicomEncoding = DicomEncoding.GetEncoding(charset);
var dicomStringElement = dataset.GetDicomItem<DicomStringElement>(dicomTag);
var bytes = dicomStringElement.Buffer.Data;
return dicomEncoding.GetString(bytes);
//// 从DICOM文件中获取使用的字符集
//string filePath = "C:\\Users\\hang\\Documents\\WeChat Files\\wxid_r2imdzb7j3q922\\FileStorage\\File\\2024-05\\1.2.840.113619.2.80.169103990.5390.1271401378.4.dcm";
//DicomFile dicomFile = DicomFile.Open(filePath);
//// 获取DICOM文件的特定元素,通常用于指示使用的字符集
//var charset = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.SpecificCharacterSet, string.Empty);
//var dicomEncoding = DicomEncoding.GetEncoding(charset);
//var value = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
//var dicomStringElement = dicomFile.Dataset.GetDicomItem<DicomStringElement>(DicomTag.PatientName);
//var bytes = dicomStringElement.Buffer.Data;
//var aa= dicomEncoding.GetString(bytes);
}
}
}
@@ -1,11 +0,0 @@
using FellowOakDicom;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
namespace IRaCIS.Core.SCP.Service
{
public interface IDicomArchiveService
{
Task<Guid> ArchiveDicomFileAsync(DicomDataset dicomDataset,Guid trialId,Guid trialSiteId, string fileRelativePath,string callingAE,string calledAE,long fileSize);
}
}
-442
View File
@@ -1,442 +0,0 @@
using Aliyun.OSS;
using IRaCIS.Core.Infrastructure;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Minio.DataModel.Args;
using Minio;
using SharpCompress.Common;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace IRaCIS.Core.SCP
{
public class MinIOOptions : AWSOptions
{
public int port { get; set; }
}
public class AWSOptions
{
public string endPoint { get; set; }
public bool useSSL { get; set; }
public string accessKey { get; set; }
public string secretKey { get; set; }
public string bucketName { get; set; }
public string viewEndpoint { get; set; }
}
public class AliyunOSSOptions
{
public string regionId { get; set; }
public string accessKeyId { get; set; }
public string accessKeySecret { get; set; }
public string internalEndpoint { get; set; }
public string endPoint { get; set; }
public string bucketName { get; set; }
public string roleArn { get; set; }
public string region { get; set; }
public string viewEndpoint { get; set; }
}
public class ObjectStoreServiceOptions
{
public string ObjectStoreUse { get; set; }
public AliyunOSSOptions AliyunOSS { get; set; }
public MinIOOptions MinIO { get; set; }
public AWSOptions AWS { get; set; }
}
public class ObjectStoreDTO
{
public string ObjectStoreUse { get; set; }
public AliyunOSSOptions AliyunOSS { get; set; }
public MinIOOptions MinIO { get; set; }
public AWSOptions AWS { get; set; }
}
public class AliyunOSSTempToken
{
public string AccessKeyId { get; set; }
public string AccessKeySecret { get; set; }
public string SecurityToken { get; set; }
public string Expiration { get; set; }
public string Region { get; set; }
public string BucketName { get; set; }
public string ViewEndpoint { get; set; }
}
public enum ObjectStoreUse
{
AliyunOSS = 0,
MinIO = 1,
AWS = 2,
}
public interface IOSSService
{
public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true);
public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true);
public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
public Task<string> GetSignedUrl(string ossRelativePath);
}
public class OSSService : IOSSService
{
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
public OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options)
{
ObjectStoreServiceOptions = options.CurrentValue;
}
/// <summary>
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
/// </summary>
/// <param name="fileStream"></param>
/// <param name="oosFolderPath"></param>
/// <param name="fileRealName"></param>
/// <param name="isFileNameAddGuid"></param>
/// <returns></returns>
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
{
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
//var ossRelativePath = $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}";
//var ossRelativePath = oosFolderPath + "/" + fileRealName;
try
{
using (var memoryStream = new MemoryStream())
{
fileStream.Seek(0, SeekOrigin.Begin);
fileStream.CopyTo(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
{
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
// 上传文件
var result = _ossClient.PutObject(aliConfig.bucketName, ossRelativePath, memoryStream);
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
{
var minIOConfig = ObjectStoreServiceOptions.MinIO;
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
.Build();
var putObjectArgs = new PutObjectArgs()
.WithBucket(minIOConfig.bucketName)
.WithObject(ossRelativePath)
.WithStreamData(memoryStream)
.WithObjectSize(memoryStream.Length);
await minioClient.PutObjectAsync(putObjectArgs);
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
{
var minIOConfig = ObjectStoreServiceOptions.AWS;
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
.Build();
var putObjectArgs = new PutObjectArgs()
.WithBucket(minIOConfig.bucketName)
.WithObject(ossRelativePath)
.WithStreamData(memoryStream)
.WithObjectSize(memoryStream.Length);
await minioClient.PutObjectAsync(putObjectArgs);
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
}
catch (Exception ex)
{
throw new BusinessValidationFailedException($"上传发生异常:{ex.Message}");
}
return "/" + ossRelativePath;
}
/// <summary>
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
/// </summary>
/// <param name="localFilePath"></param>
/// <param name="oosFolderPath"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
{
var localFileName = Path.GetFileName(localFilePath);
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}" : $"{oosFolderPath}/{localFileName}";
//var ossRelativePath = oosFolderPath + "/" + localFileName;
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
{
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
// 上传文件
var result = _ossClient.PutObject(aliConfig.bucketName, ossRelativePath, localFilePath);
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
{
var minIOConfig = ObjectStoreServiceOptions.MinIO;
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
.Build();
var putObjectArgs = new PutObjectArgs()
.WithBucket(minIOConfig.bucketName)
.WithObject(ossRelativePath)
.WithFileName(localFilePath);
await minioClient.PutObjectAsync(putObjectArgs);
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
{
var minIOConfig = ObjectStoreServiceOptions.AWS;
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
.Build();
var putObjectArgs = new PutObjectArgs()
.WithBucket(minIOConfig.bucketName)
.WithObject(ossRelativePath)
.WithFileName(localFilePath);
await minioClient.PutObjectAsync(putObjectArgs);
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
return "/" + ossRelativePath;
}
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
{
ossRelativePath = ossRelativePath.TrimStart('/');
try
{
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
{
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
// 上传文件
var result = _ossClient.GetObject(aliConfig.bucketName, ossRelativePath);
// 将下载的文件流保存到本地文件
using (var fs = File.OpenWrite(localFilePath))
{
result.Content.CopyTo(fs);
fs.Close();
}
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
{
var minIOConfig = ObjectStoreServiceOptions.MinIO;
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
.Build();
var getObjectArgs = new GetObjectArgs()
.WithBucket(minIOConfig.bucketName)
.WithObject(ossRelativePath)
.WithFile(localFilePath);
await minioClient.GetObjectAsync(getObjectArgs);
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
{
var minIOConfig = ObjectStoreServiceOptions.AWS;
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
.Build();
var getObjectArgs = new GetObjectArgs()
.WithBucket(minIOConfig.bucketName)
.WithObject(ossRelativePath)
.WithFile(localFilePath);
await minioClient.GetObjectAsync(getObjectArgs);
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
catch (Exception ex)
{
throw new BusinessValidationFailedException("oss下载失败!" + ex.Message);
}
}
public async Task<string> GetSignedUrl(string ossRelativePath)
{
ossRelativePath = ossRelativePath.TrimStart('/');
try
{
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
{
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
// 生成签名URL。
var req = new GeneratePresignedUriRequest(aliConfig.bucketName, ossRelativePath, SignHttpMethod.Get)
{
// 设置签名URL过期时间,默认值为3600秒。
Expiration = DateTime.Now.AddHours(1),
};
var uri = _ossClient.GeneratePresignedUri(req);
return uri.PathAndQuery;
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
{
var minIOConfig = ObjectStoreServiceOptions.MinIO;
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
.Build();
var args = new PresignedGetObjectArgs()
.WithBucket(minIOConfig.bucketName)
.WithObject(ossRelativePath)
.WithExpiry(3600)
/*.WithHeaders(reqParams)*/;
var presignedUrl = await minioClient.PresignedGetObjectAsync(args);
Uri uri = new Uri(presignedUrl);
string relativePath = uri.PathAndQuery;
return relativePath;
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
{
var minIOConfig = ObjectStoreServiceOptions.AWS;
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
.Build();
var args = new PresignedGetObjectArgs()
.WithBucket(minIOConfig.bucketName)
.WithObject(ossRelativePath)
.WithExpiry(3600);
var presignedUrl = await minioClient.PresignedGetObjectAsync(args);
Uri uri = new Uri(presignedUrl);
string relativePath = uri.PathAndQuery;
return relativePath;
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
catch (Exception ex)
{
throw new BusinessValidationFailedException("oss授权url失败!" + ex.Message);
}
}
}
}
@@ -1,44 +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": "LTAI5tKvzs7ed3UfSpNk3xwQ",
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
"bucketName": "zy-irc-store",
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
"viewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
"region": "oss-cn-shanghai"
},
"MinIO": {
"endpoint": "http://192.168.3.68",
"port": "8001",
"useSSL": false,
"accessKey": "IDFkwEpWej0b4DtiuThL",
"secretKey": "Lhuu83yMhVwu7c1SnjvGY6lq74jzpYqifK6Qtj4h",
"bucketName": "test"
}
},
"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
}
}
-9
View File
@@ -1,9 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
-6
View File
@@ -17,8 +17,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infra.EFCore",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infrastructure", "IRaCIS.Core.Infrastructure\IRaCIS.Core.Infrastructure.csproj", "{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IRC.Core.SCP", "IRC.Core.SCP\IRC.Core.SCP.csproj", "{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -53,10 +51,6 @@ Global
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|Any CPU.Build.0 = Release|Any CPU
{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
-99
View File
@@ -1,99 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Microsoft.EntityFrameworkCore;
namespace EFSaving.Concurrency
{
public class Sample
{
public static void Run()
{
// Ensure database is created and has a person in it
using (var setupContext = new PersonContext())
{
setupContext.Database.EnsureDeleted();
setupContext.Database.EnsureCreated();
setupContext.People.Add(new Person { FirstName = "John", LastName = "Doe" });
setupContext.SaveChanges();
}
#region ConcurrencyHandlingCode
using var context = new PersonContext();
// Fetch a person from database and change phone number
var person = context.People.Single(p => p.PersonId == 1);
person.PhoneNumber = "555-555-5555";
// Change the person's name in the database to simulate a concurrency conflict
context.Database.ExecuteSqlRaw(
"UPDATE dbo.People SET FirstName = 'Jane' WHERE PersonId = 1");
var saved = false;
while (!saved)
{
try
{
// Attempt to save changes to the database
context.SaveChanges();
saved = true;
}
catch (DbUpdateConcurrencyException ex)
{
foreach (var entry in ex.Entries)
{
if (entry.Entity is Person)
{
var proposedValues = entry.CurrentValues;
var databaseValues = entry.GetDatabaseValues();
foreach (var property in proposedValues.Properties)
{
var proposedValue = proposedValues[property];
var databaseValue = databaseValues[property];
// TODO: decide which value should be written to database
// proposedValues[property] = <value to be saved>;
}
// Refresh original values to bypass next concurrency check
entry.OriginalValues.SetValues(databaseValues);
}
else
{
throw new NotSupportedException(
"Don't know how to handle concurrency conflicts for "
+ entry.Metadata.Name);
}
}
}
}
#endregion
}
public class PersonContext : DbContext
{
public DbSet<Person> People { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// Requires NuGet package Microsoft.EntityFrameworkCore.SqlServer
optionsBuilder.UseSqlServer(
@"Server=(localdb)\mssqllocaldb;Database=EFSaving.Concurrency;Trusted_Connection=True");
}
}
public class Person
{
public int PersonId { get; set; }
[ConcurrencyCheck]
public string FirstName { get; set; }
[ConcurrencyCheck]
public string LastName { get; set; }
public string PhoneNumber { get; set; }
}
}
}
+231
View File
@@ -0,0 +1,231 @@
//using Autofac;
//using Autofac.Extensions.DependencyInjection;
//using IRaCIS.Core.API;
//using IRaCIS.Core.Application.Filter;
//using IRaCIS.Core.Application.MediatR.Handlers;
//using LogDashboard;
//using MassTransit;
//using MassTransit.NewIdProviders;
//using MediatR;
//using Microsoft.AspNetCore.Builder;
//using Microsoft.AspNetCore.Http.Features;
//using Microsoft.AspNetCore.HttpOverrides;
//using Microsoft.AspNetCore.SignalR;
//using Microsoft.Extensions.Configuration;
//using Microsoft.Extensions.DependencyInjection;
//using Microsoft.Extensions.Hosting;
//using Serilog;
//using System;
//var builder = WebApplication.CreateBuilder(args);
// //以配置文件为准,否则 从url中取环境值(服务以命令行传递参数启动,配置文件配置了就不需要传递环境参数)
// var config = new ConfigurationBuilder()
// .AddEnvironmentVariables()
// .Build();
// var enviromentName = config["ASPNETCORE_ENVIRONMENT"];
// if (string.IsNullOrWhiteSpace(enviromentName))
// {
// var index = Array.IndexOf(args, "--env");
// enviromentName = index > -1
// ? args[index + 1]
// : "Development";
// }
// NewId.SetProcessIdProvider(new CurrentProcessIdProvider());
//builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
// .ConfigureContainer<ContainerBuilder>(containerBuilder =>
// {
// containerBuilder.RegisterModule<AutofacModuleSetup>();
// })
// .UseWindowsService().UseSerilog();
//// Add services to the container.
////本地化
//builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resources");
//// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
//builder.Services.AddControllers(options =>
//{
// //options.Filters.Add<LogActionFilter>();
// options.Filters.Add<ModelActionFilter>();
// options.Filters.Add<ProjectExceptionFilter>();
// //options.Filters.Add<UnitOfWorkFilter>();
// //if (_configuration.GetSection("BasicSystemConfig").GetValue<bool>("OpenLoginLimit"))
// //{
// // options.Filters.Add<LimitUserRequestAuthorization>();
// //}
//}).AddNewtonsoftJsonSetup(); // NewtonsoftJson 序列化 处理
////动态WebApi + UnifiedApiResultFilter 省掉控制器代码
//builder.Services.AddDynamicWebApiSetup();
////AutoMapper
//builder.Services.AddAutoMapperSetup();
////EF ORM QueryWithNoLock
//builder.Services.AddEFSetup(builder.Configuration);
////Http 响应压缩
//builder.Services.AddResponseCompressionSetup();
////Swagger Api 文档
//builder.Services.AddSwaggerSetup();
////JWT Token 验证
//builder.Services.AddJWTAuthSetup(builder.Configuration);
//// MediatR 进程内消息 事件解耦 从程序集中 注册命令和handler对应关系
//builder.Services.AddMediatR(typeof(ConsistencyVerificationHandler).Assembly);
//// EasyCaching 缓存
//builder.Services.AddEasyCachingSetup();
////services.AddDistributedMemoryCache();
////// hangfire 定时任务框架 有界面,更友好~
//builder.Services.AddhangfireSetup(builder.Configuration);
////// QuartZ 定时任务框架 使用了hangfire 暂时不用,后续需要可以打开,已经配好
////builder.Services.AddQuartZSetup(_configuration);
//// 保护上传文件
////services.AddStaticFileAuthorizationSetup();
//////HttpReports 暂时废弃
////services.AddHttpReports().AddHttpTransport();
////Serilog 日志可视化 LogDashboard日志
//builder.Services.AddLogDashboardSetup();
////上传限制 配置
//builder.Services.Configure<FormOptions>(options =>
//{
// options.MultipartBodyLengthLimit = int.MaxValue;
// options.ValueCountLimit = int.MaxValue;
// options.ValueLengthLimit = int.MaxValue;
//});
////IP 限流 可设置白名单 或者黑名单
////services.AddIpPolicyRateLimitSetup(_configuration);
////用户类型 策略授权
//builder.Services.AddAuthorizationPolicySetup(builder.Configuration);
//builder.Services.AddJsonConfigSetup(builder.Configuration);
////转发头设置 获取真实IP
//builder.Services.Configure<ForwardedHeadersOptions>(options =>
//{
// options.ForwardedHeaders =
// ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
//});
////Dicom影像渲染图片 跨平台
//builder.Services.AddDicomSetup();
//// 实时应用
//builder.Services.AddSignalR();
//builder.Services.AddSingleton<IUserIdProvider, IRaCISUserIdProvider>();
//builder.Services.AddControllers();
//// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
////builder.Services.AddEndpointsApiExplorer();
////builder.Services.AddSwaggerGen();
////SerilogExtension.AddSerilogSetup(enviromentName, builder.Host.confi);
//var app = builder.Build();
//// Configure the HTTP request pipeline.
////本地化
//app.UseLocalization();
//app.UseForwardedHeaders();
////不需要 token 访问的静态文件 wwwroot css, JavaScript, and images don't require authentication.
//app.UseStaticFiles();
//app.UseIRacisHostStaticFileStore(app.Environment);
////LogDashboard
//app.UseLogDashboard("/LogDashboard");
////hangfire
////app.UseHangfireConfig(app.Environment);
//////暂时废弃
////app.UseHttpReports();
//////限流 中间件
////app.UseIpRateLimiting();
////响应压缩
//app.UseResponseCompression();
//if (app.Environment.IsDevelopment())
//{
// app.UseDeveloperExceptionPage();
//}
//else
//{
// //app.UseHsts();
//}
//SwaggerSetup.Configure(app, app.Environment);
//Console.WriteLine("当前环境: " + builder.Environment.EnvironmentName);
////app.UseMiddleware<AuthMiddleware>();
//// 特殊异常处理 比如 404
//app.UseStatusCodePagesWithReExecute("/Error/{0}");
//////serilog 记录请求的用户信息
//app.UseSerilogConfig(app.Environment);
//app.UseRouting();
//app.UseCors(t => t.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
//app.UseAuthentication();
////app.UseJwtBearerQueryString();
//app.UseAuthorization();
//////文件伺服 必须带Token 访问
//////app.UseIRacisHostStaticFileStore(env);
////app.UseEndpoints(endpoints =>
////{
//// endpoints.MapControllers();
//// endpoints.MapHub<UploadHub>("/UploadHub")/*.RequireCors(t=>t.WithOrigins(new string[] {"null"}).AllowAnyMethod().AllowAnyHeader().AllowCredentials())*/;
////});
//app.MapControllers();
//app.MapHub<UploadHub>("/UploadHub")/*.RequireCors(t=>t.WithOrigins(new string[] {"null"}).AllowAnyMethod().AllowAnyHeader().AllowCredentials())*/;
//app.Run();
//测试同步
+106
View File
@@ -0,0 +1,106 @@
{
"needAnonymizeTag": [
{ //PatientsName
"Group": "0010",
"Element": "0010",
"ReplaceValue": "",
"Enable": true
},
{ // PatientID
"Group": "0010",
"Element": "0020",
"ReplaceValue": "",
"Enable": true
},
{ // IssuerOfPatientID
"Group": "0010",
"Element": "0021",
"ReplaceValue": "",
"Enable": true
},
{ // PatientsBirthDate
"Group": "0010",
"Element": "0030",
"ReplaceValue": "",
"Enable": true
},
{ // PatientsBirthTime
"Group": "0010",
"Element": "0032",
"ReplaceValue": "",
"Enable": false
},
{ // PatientsSex
"Group": "0010",
"Element": "0040",
"ReplaceValue": "",
"Enable": false
},
{ // OtherPatientIDs
"Group": "0010",
"Element": "1000",
"ReplaceValue": "",
"Enable": false
},
{ // OtherPatientNames
"Group": "0010",
"Element": "1001",
"ReplaceValue": "",
"Enable": false
},
{ // OtherPatientNames
"Group": "0010",
"Element": "1005",
"ReplaceValue": "",
"Enable": true
},
{ // PatientBirthName
"Group": "0010",
"Element": "1005",
"ReplaceValue": "",
"Enable": true
},
{ // PatientsAge
"Group": "0010",
"Element": "1010",
"ReplaceValue": "",
"Enable": true
},
{ // PatientsAddress
"Group": "0010",
"Element": "1040",
"ReplaceValue": "",
"Enable": true
},
{ // PatientsMothersBirthName
"Group": "0010",
"Element": "1060",
"ReplaceValue": "",
"Enable": true
},
{
"Group": "0010",
"Element": "2150",
"ReplaceValue": "",
"Enable": true
},
{
"Group": "0010",
"Element": "2152",
"ReplaceValue": "",
"Enable": true
},
{
"Group": "0010",
"Element": "2154",
"ReplaceValue": "",
"Enable": true
},
{
"Group": "0012",
"Element": "0040",
"ReplaceValue": "XXX",
"Enable": true
}
]
}
+171 -386
View File
@@ -1,5 +1,6 @@
using System;
using System.Net.Http;
using EasyCaching.Core;
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Auth;
@@ -20,23 +21,13 @@ using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infrastructure;
using System.Linq;
using Microsoft.Extensions.Logging;
using MassTransit;
using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.Sts.Model.V20150401;
using Microsoft.AspNetCore.Hosting;
using MassTransit;
using IRaCIS.Core.Application.Helper;
using Microsoft.Extensions.Options;
using IRaCIS.Core.Application.Contracts;
using LoginReturnDTO = IRaCIS.Application.Contracts.LoginReturnDTO;
using DocumentFormat.OpenXml.Spreadsheet;
using AutoMapper.QueryableExtensions;
using NetTopologySuite.Algorithm;
using ZiggyCreatures.Caching.Fusion;
using AlibabaCloud.SDK.Sts20150401;
using AlibabaCloud.SDK.Sts20150401.Models;
using Org.BouncyCastle.Tls;
using Amazon.SecurityToken.Model;
using Amazon.SecurityToken;
using Amazon;
using AssumeRoleRequest = Amazon.SecurityToken.Model.AssumeRoleRequest;
namespace IRaCIS.Api.Controllers
{
@@ -48,231 +39,203 @@ namespace IRaCIS.Api.Controllers
{
/// <summary>
/// 获取医生详情
/// </summary>
/// <param name="attachmentService"></param>
/// <param name="_doctorService"></param>
/// <param name="_educationService"></param>
/// <param name="_trialExperienceService"></param>
/// <param name="_researchPublicationService"></param>
/// <param name="_vacationService"></param>
/// <param name="doctorId"></param>
/// <returns></returns>
[HttpGet, Route("doctor/getDetail/{doctorId:guid}")]
public async Task<IResponseOutput<DoctorDetailDTO>> GetDoctorDetail([FromServices] IAttachmentService attachmentService, [FromServices] IDoctorService _doctorService,
[FromServices] IEducationService _educationService, [FromServices] ITrialExperienceService _trialExperienceService,
[FromServices] IResearchPublicationService _researchPublicationService, [FromServices] IVacationService _vacationService, Guid doctorId)
{
var education = await _educationService.GetEducation(doctorId);
var sowList = _doctorService.GetDoctorSowList(doctorId);
var ackSowList = _doctorService.GetDoctorAckSowList(doctorId);
var doctorDetail = new DoctorDetailDTO
{
AuditView = await _doctorService.GetAuditState(doctorId),
BasicInfoView = await _doctorService.GetBasicInfo(doctorId),
EmploymentView = await _doctorService.GetEmploymentInfo(doctorId),
AttachmentList = await attachmentService.GetAttachments(doctorId),
EducationList = education.EducationList,
PostgraduateList = education.PostgraduateList,
TrialExperienceView = await _trialExperienceService.GetTrialExperience(doctorId),
ResearchPublicationView = await _researchPublicationService.GetResearchPublication(doctorId),
SpecialtyView = await _doctorService.GetSpecialtyInfo(doctorId),
InHoliday = (await _vacationService.OnVacation(doctorId)).IsSuccess,
IntoGroupInfo = _doctorService.GetDoctorIntoGroupInfo(doctorId),
SowList = sowList,
AckSowList = ackSowList
};
return ResponseOutput.Ok(doctorDetail);
}
/// <summary> 系统用户登录接口[New] </summary>
[HttpPost, Route("user/login")]
[AllowAnonymous]
public async Task<IResponseOutput> Login(UserLoginDTO loginUser,
[FromServices] IFusionCache _fusionCache,
[FromServices] IUserService _userService,
[FromServices] ITokenService _tokenService,
[FromServices] IReadingImageTaskService readingImageTaskService,
[FromServices] IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig,
[FromServices] IMailVerificationService _mailVerificationService)
public async Task<IResponseOutput<LoginReturnDTO>> Login(UserLoginDTO loginUser, [FromServices] IEasyCachingProvider provider, [FromServices] IUserService _userService,
[FromServices] ITokenService _tokenService, [FromServices] IConfiguration configuration)
{
//MFA 邮箱验证 前端传递用户Id 和MFACode
if (loginUser.UserId != null && _verifyConfig.CurrentValue.OpenLoginMFA)
var returnModel = await _userService.Login(loginUser.UserName, loginUser.Password);
if (returnModel.IsSuccess)
{
Guid userId = (Guid)loginUser.UserId;
#region GRPC IIS问题 http/2 使
//验证MFA 编码是否有问题 ,前端要拆开,自己调用验证的逻辑
//await _userService.VerifyMFACodeAsync(userId, loginUser.MFACode);
////重试策略
//var defaultMethodConfig = new MethodConfig
//{
// Names = { MethodName.Default },
// RetryPolicy = new RetryPolicy
// {
// MaxAttempts = 3,
// InitialBackoff = TimeSpan.FromSeconds(1),
// MaxBackoff = TimeSpan.FromSeconds(5),
// BackoffMultiplier = 1.5,
// RetryableStatusCodes = { Grpc.Core.StatusCode.Unavailable }
// }
//};
//var loginUser = await _userRepository.Where(u => u.UserName.Equals(userName) && u.Password == password).ProjectTo<UserBasicInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
//#region unable to trust the certificate then the gRPC client can be configured to ignore the invalid certificate
var basicInfo = await _userService.GetUserBasicInfo(userId, loginUser.Password);
//var httpHandler = new HttpClientHandler();
//// Return `true` to allow certificates that are untrusted/invalid
//httpHandler.ServerCertificateCustomValidationCallback =
// HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var loginReturn = new LoginReturnDTO() { BasicInfo = basicInfo };
loginReturn.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(loginReturn.BasicInfo));
//////这一句是让grpc支持本地 http 如果本地访问部署在服务器上,那么是访问不成功的
//AppContext.SetSwitch(
// "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
//#endregion
//var grpcAdress = configuration.GetValue<string>("GrpcAddress");
////var grpcAdress = "http://localhost:7200";
//var channel = GrpcChannel.ForAddress(grpcAdress, new GrpcChannelOptions
//{
// HttpHandler = httpHandler,
// ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
//});
////var channel = GrpcChannel.ForAddress(grpcAdress);
//var grpcClient = new TokenGrpcService.TokenGrpcServiceClient(channel);
//var userInfo = returnModel.Data.BasicInfo;
//var tokenResponse = grpcClient.GetUserToken(new GetTokenReuqest()
//{
// Id = userInfo.Id.ToString(),
// ReviewerCode = userInfo.ReviewerCode,
// IsAdmin = userInfo.IsAdmin,
// RealName = userInfo.RealName,
// UserTypeEnumInt = (int)userInfo.UserTypeEnum,
// UserTypeShortName = userInfo.UserTypeShortName,
// UserName = userInfo.UserName
//});
//returnModel.Data.JWTStr = tokenResponse.Token;
#endregion
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 属性
Expires = DateTime.Now.AddMonths(1),
HttpOnly = true, // 确保 cookie 只能通过 HTTP 访问
SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Unspecified, // 设置 SameSite 属性
Secure = false // 确保 cookie 只能通过 HTTPS 访问
};
HttpContext.Response.Cookies.Append("access_token", loginReturn.JWTStr, option);
HttpContext.Response.Cookies.Append("access_token", returnModel.Data.JWTStr, option);
// 验证阅片休息时间
await readingImageTaskService.ResetReadingRestTime(userId);
}
await _fusionCache.SetAsync(userId.ToString(), loginReturn.JWTStr, TimeSpan.FromDays(7));
var userId = returnModel.Data.BasicInfo.Id.ToString();
//provider.Set(userId, userId, TimeSpan.FromMinutes(AppSettings.LoginExpiredTimeSpan));
await _fusionCache.SetAsync($"{userId.ToString()}_Online", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(_verifyConfig.CurrentValue.AutoLoginOutMinutes));
await provider.SetAsync(userId.ToString(), returnModel.Data.JWTStr, TimeSpan.FromDays(7));
return returnModel;
}
return ResponseOutput.Ok(loginReturn);
[HttpGet("user/GetObjectStoreToken")]
public IResponseOutput GetObjectStoreToken([FromServices] IOptionsMonitor<ObjectStoreServiceOptions> options)
{
var serviceOption = options.CurrentValue;
if (Enum.TryParse<ObjectStoreUse>(serviceOption.ObjectStoreUse, out var parsedEnum) && parsedEnum == ObjectStoreUse.AliyunOSS)
{
var ossOptions = serviceOption.AliyunOSS;
return ResponseOutput.Ok(new ObjectStoreDTO() { ObjectStoreUse = serviceOption.ObjectStoreUse, MinIO = serviceOption.MinIO, AliyunOSS = serviceOption.AliyunOSS, AWS = serviceOption.AWS });
#region token
//IClientProfile profile = DefaultProfile.GetProfile(ossOptions.RegionId, ossOptions.AccessKeyId, ossOptions.AccessKeySecret);
//DefaultAcsClient client = new DefaultAcsClient(profile);
//// 创建一个STS请求
//AssumeRoleRequest request = new AssumeRoleRequest
//{
// RoleArn = ossOptions.RoleArn, // 角色ARN,需要替换为你的角色ARN
// RoleSessionName = $"session-name-{NewId.NextGuid()}", // 角色会话名称,可自定义
// DurationSeconds = 900, // 令牌有效期(单位:秒),这里设置为1小时
//};
//AssumeRoleResponse response = client.GetAcsResponse(request);
//// 返回STS令牌信息给前端
//var stsToken = new ObjectStoreDTO()
//{
// ObjectStoreUse = serviceOption.ObjectStoreUse,
// AliyunOSS = new AliyunOSSTempToken()
// {
// AccessKeyId = response.Credentials.AccessKeyId,
// AccessKeySecret = response.Credentials.AccessKeySecret,
// SecurityToken = response.Credentials.SecurityToken,
// Expiration = response.Credentials.Expiration,
// Region = ossOptions.Region,
// BucketName = ossOptions.BucketName,
// ViewEndpoint = ossOptions.ViewEndpoint,
// },
// MinIO = serviceOption.MinIO
//};
//return ResponseOutput.Ok(stsToken);
#endregion
}
else if (Enum.TryParse<ObjectStoreUse>(serviceOption.ObjectStoreUse, out var parsedValue) && parsedValue == ObjectStoreUse.MinIO)
{
return ResponseOutput.Ok(new ObjectStoreDTO() { ObjectStoreUse = serviceOption.ObjectStoreUse, MinIO = serviceOption.MinIO, AWS = serviceOption.AWS });
}
else
{
var returnModel = await _userService.Login(loginUser.UserName, loginUser.Password);
if (returnModel.IsSuccess)
{
#region GRPC IIS问题 http/2 使
////重试策略
//var defaultMethodConfig = new MethodConfig
//{
// Names = { MethodName.Default },
// RetryPolicy = new RetryPolicy
// {
// MaxAttempts = 3,
// InitialBackoff = TimeSpan.FromSeconds(1),
// MaxBackoff = TimeSpan.FromSeconds(5),
// BackoffMultiplier = 1.5,
// RetryableStatusCodes = { Grpc.Core.StatusCode.Unavailable }
// }
//};
//#region unable to trust the certificate then the gRPC client can be configured to ignore the invalid certificate
//var httpHandler = new HttpClientHandler();
//// Return `true` to allow certificates that are untrusted/invalid
//httpHandler.ServerCertificateCustomValidationCallback =
// HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
//////这一句是让grpc支持本地 http 如果本地访问部署在服务器上,那么是访问不成功的
//AppContext.SetSwitch(
// "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
//#endregion
//var grpcAdress = configuration.GetValue<string>("GrpcAddress");
////var grpcAdress = "http://localhost:7200";
//var channel = GrpcChannel.ForAddress(grpcAdress, new GrpcChannelOptions
//{
// HttpHandler = httpHandler,
// ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
//});
////var channel = GrpcChannel.ForAddress(grpcAdress);
//var grpcClient = new TokenGrpcService.TokenGrpcServiceClient(channel);
//var userInfo = returnModel.Data.BasicInfo;
//var tokenResponse = grpcClient.GetUserToken(new GetTokenReuqest()
//{
// Id = userInfo.Id.ToString(),
// ReviewerCode = userInfo.ReviewerCode,
// IsAdmin = userInfo.IsAdmin,
// RealName = userInfo.RealName,
// UserTypeEnumInt = (int)userInfo.UserTypeEnum,
// UserTypeShortName = userInfo.UserTypeShortName,
// UserName = userInfo.UserName
//});
//returnModel.Data.JWTStr = tokenResponse.Token;
#endregion
var userId = returnModel.Data.BasicInfo.Id;
if (_verifyConfig.CurrentValue.OpenLoginMFA)
{
//发版屏蔽
//returnModel.Data.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(returnModel.Data.BasicInfo));
//MFA 发送邮件
returnModel.Data.IsMFA = true;
var email = returnModel.Data.BasicInfo.EMail;
var hiddenEmail = EmailMaskHelper.MaskEmail(email);
returnModel.Data.BasicInfo.EMail = hiddenEmail;
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));
}
}
return returnModel;
return ResponseOutput.Ok(new ObjectStoreDTO() { ObjectStoreUse = serviceOption.ObjectStoreUse, MinIO = serviceOption.MinIO, AWS = serviceOption.AWS });
}
}
[HttpGet("user/GenerateSTS")]
public IResponseOutput GenerateSTS([FromServices] IOptionsMonitor<AliyunOSSOptions> options)
{
var ossOptions = options.CurrentValue;
IClientProfile profile = DefaultProfile.GetProfile(ossOptions.regionId, ossOptions.accessKeyId, ossOptions.accessKeySecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
// 创建一个STS请求
AssumeRoleRequest request = new AssumeRoleRequest
{
RoleArn = ossOptions.roleArn, // 角色ARN,需要替换为你的角色ARN
RoleSessionName = $"session-name-{NewId.NextGuid()}", // 角色会话名称,可自定义
DurationSeconds = 900, // 令牌有效期(单位:秒),这里设置为1小时
};
AssumeRoleResponse response = client.GetAcsResponse(request);
// 返回STS令牌信息给前端
var stsToken = new
{
AccessKeyId = response.Credentials.AccessKeyId,
AccessKeySecret = response.Credentials.AccessKeySecret,
SecurityToken = response.Credentials.SecurityToken,
Expiration = response.Credentials.Expiration,
Region = ossOptions.region ,
BucketName = ossOptions.bucketName ,
ViewEndpoint = ossOptions.viewEndpoint ,
};
return ResponseOutput.Ok(stsToken);
}
@@ -296,184 +259,6 @@ namespace IRaCIS.Api.Controllers
return ResponseOutput.Ok("/showdicom?studyId=f7b67793-8155-0223-2f15-118f2642efb8&type=Share&token=" + token);
}
[HttpGet("user/GetObjectStoreToken")]
public async Task<IResponseOutput> GetObjectStoreTokenAsync([FromServices] IOptionsMonitor<ObjectStoreServiceOptions> options)
{
var serviceOption = options.CurrentValue;
if (Enum.TryParse<ObjectStoreUse>(serviceOption.ObjectStoreUse, out var parsedEnum) && parsedEnum == ObjectStoreUse.AliyunOSS)
{
var ossOptions = serviceOption.AliyunOSS;
var client = new Client(new AlibabaCloud.OpenApiClient.Models.Config()
{
AccessKeyId = ossOptions.AccessKeyId,
AccessKeySecret = ossOptions.AccessKeySecret,
//AccessKeyId = "LTAI5tJV76pYX5yPg1N9QVE8",
//AccessKeySecret = "roRNLa9YG1of4pYruJGCNKBXEWTAWa",
Endpoint = "sts.cn-hangzhou.aliyuncs.com"
});
var assumeRoleRequest = new AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleRequest();
// 将<YOUR_ROLE_SESSION_NAME>设置为自定义的会话名称,例如oss-role-session。
assumeRoleRequest.RoleSessionName = $"session-name-{NewId.NextGuid()}";
// 将<YOUR_ROLE_ARN>替换为拥有上传文件到指定OSS Bucket权限的RAM角色的ARN。
assumeRoleRequest.RoleArn = ossOptions.RoleArn;
//assumeRoleRequest.RoleArn = "acs:ram::1899121822495495:role/webdirect";
assumeRoleRequest.DurationSeconds = ossOptions.DurationSeconds;
var runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
var response = client.AssumeRoleWithOptions(assumeRoleRequest, runtime);
var credentials = response.Body.Credentials;
var tempToken = new AliyunOSSTempToken()
{
AccessKeyId = credentials.AccessKeyId,
AccessKeySecret = credentials.AccessKeySecret,
Expiration = credentials.Expiration,
SecurityToken = credentials.SecurityToken,
Region = ossOptions.Region,
BucketName = ossOptions.BucketName,
EndPoint = ossOptions.EndPoint,
ViewEndpoint = ossOptions.ViewEndpoint,
};
var awstempToken = await GetAWSTemToken(serviceOption);
return ResponseOutput.Ok(new ObjectStoreDTO() { ObjectStoreUse = serviceOption.ObjectStoreUse, AliyunOSS = tempToken,AWS= awstempToken });
}
else if (Enum.TryParse<ObjectStoreUse>(serviceOption.ObjectStoreUse, out var parsedValue) && parsedValue == ObjectStoreUse.MinIO)
{
return ResponseOutput.Ok(new ObjectStoreDTO() { ObjectStoreUse = serviceOption.ObjectStoreUse, MinIO = serviceOption.MinIO});
}
else
{
var awsOptions = serviceOption.AWS;
//aws 临时凭证
// 创建 STS 客户端
var stsClient = new AmazonSecurityTokenServiceClient(awsOptions.AccessKeyId, awsOptions.SecretAccessKey);
// 使用 AssumeRole 请求临时凭证
var assumeRoleRequest = new AssumeRoleRequest
{
RoleArn = awsOptions.RoleArn, // 角色 ARN
RoleSessionName = $"session-name-{NewId.NextGuid()}",
DurationSeconds = awsOptions.DurationSeconds // 临时凭证有效期
};
var assumeRoleResponse = await stsClient.AssumeRoleAsync(assumeRoleRequest);
var credentials = assumeRoleResponse.Credentials;
var tempToken = new AWSTempToken()
{
AccessKeyId = credentials.AccessKeyId,
SecretAccessKey = credentials.SecretAccessKey,
SessionToken= credentials.SessionToken,
Expiration=credentials.Expiration,
Region=awsOptions.Region,
BucketName = awsOptions.BucketName,
EndPoint = awsOptions.EndPoint,
ViewEndpoint = awsOptions.ViewEndpoint,
};
return ResponseOutput.Ok(new ObjectStoreDTO() { ObjectStoreUse = serviceOption.ObjectStoreUse, MinIO = serviceOption.MinIO, AWS = tempToken });
}
}
private async Task<AWSTempToken> GetAWSTemToken(ObjectStoreServiceOptions serviceOption)
{
var awsOptions = serviceOption.AWS;
//aws 临时凭证
// 创建 STS 客户端
var stsClient = new AmazonSecurityTokenServiceClient(awsOptions.AccessKeyId, awsOptions.SecretAccessKey);
// 使用 AssumeRole 请求临时凭证
var assumeRoleRequest = new AssumeRoleRequest
{
RoleArn = awsOptions.RoleArn, // 角色 ARN
RoleSessionName = $"session-name-{NewId.NextGuid()}",
DurationSeconds = awsOptions.DurationSeconds // 临时凭证有效期
};
var assumeRoleResponse = await stsClient.AssumeRoleAsync(assumeRoleRequest);
var credentials = assumeRoleResponse.Credentials;
var tempToken = new AWSTempToken()
{
AccessKeyId = credentials.AccessKeyId,
SecretAccessKey = credentials.SecretAccessKey,
SessionToken = credentials.SessionToken,
Expiration = credentials.Expiration,
Region = awsOptions.Region,
BucketName = awsOptions.BucketName,
EndPoint = awsOptions.EndPoint,
ViewEndpoint = awsOptions.ViewEndpoint,
};
return tempToken;
}
#region aliyun-net-sdk-sts
//[HttpGet("user/GenerateSTS")]
//public IResponseOutput GenerateSTS([FromServices] IOptionsMonitor<AliyunOSSOptions> options)
//{
// var ossOptions = options.CurrentValue;
// IClientProfile profile = DefaultProfile.GetProfile(ossOptions.regionId, ossOptions.accessKeyId, ossOptions.accessKeySecret);
// DefaultAcsClient client = new DefaultAcsClient(profile);
// // 创建一个STS请求
// AssumeRoleRequest request = new AssumeRoleRequest
// {
// RoleArn = ossOptions.roleArn, // 角色ARN,需要替换为你的角色ARN
// RoleSessionName = $"session-name-{NewId.NextGuid()}", // 角色会话名称,可自定义
// DurationSeconds = 900, // 令牌有效期(单位:秒),这里设置为1小时
// };
// AssumeRoleResponse response = client.GetAcsResponse(request);
// // 返回STS令牌信息给前端
// var stsToken = new
// {
// AccessKeyId = response.Credentials.AccessKeyId,
// AccessKeySecret = response.Credentials.AccessKeySecret,
// SecurityToken = response.Credentials.SecurityToken,
// Expiration = response.Credentials.Expiration,
// Region = ossOptions.region,
// BucketName = ossOptions.bucketName,
// ViewEndpoint = ossOptions.viewEndpoint,
// };
// return ResponseOutput.Ok(stsToken);
//}
#endregion
@@ -510,7 +295,7 @@ namespace IRaCIS.Api.Controllers
[HttpGet, Route("ip")]
[AllowAnonymous]
public IResponseOutput Get([FromServices] IHttpContextAccessor _context)
public IResponseOutput Get([FromServices] IHttpContextAccessor _context/*, [FromServices] IUserService _userService*/)
{
StringBuilder sb = new StringBuilder();
@@ -531,7 +316,7 @@ namespace IRaCIS.Api.Controllers
[HttpGet, Route("ip2")]
[AllowAnonymous]
public IResponseOutput Get2([FromServices] IHttpContextAccessor _context)
public IResponseOutput Get2([FromServices] IHttpContextAccessor _context, [FromServices] IRepository _userService)
{
StringBuilder sb = new StringBuilder();
@@ -19,12 +19,18 @@ namespace IRaCIS.Core.API.Controllers.Special
//谨慎修改 涉及到财务模块
[ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")]
public class FinancialChangeController(
ITrialService _trialService,
ICalculateService _calculateService,
IStringLocalizer _localizer) : ControllerBase
public class FinancialChangeController : ControllerBase
{
private readonly ITrialService _trialService;
private IStringLocalizer _localizer { get; set; }
public FinancialChangeController(ITrialService trialService, IStringLocalizer localizer
)
{
_localizer = localizer;
_trialService = trialService;
}
//[TrialAudit(AuditType.TrialAudit, AuditOptType.AddOrUpdateTrial)]
@@ -54,268 +60,28 @@ namespace IRaCIS.Core.API.Controllers.Special
var userId = Guid.Parse(User.FindFirst("id").Value);
var result = await _trialService.AddOrUpdateTrial(param);
if (_trialService.TrialExpeditedChange)
{
var needCalReviewerIds = await _trialService.GetTrialEnrollmentReviewerIds(param.Id.Value);
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
calcList.ForEach(t =>
{
if (needCalReviewerIds.Contains(t.DoctorId))
{
_calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
{
NeedCalculateReviewers = new List<Guid>()
{
t.DoctorId
},
CalculateMonth = DateTime.Parse(t.YearMonth)
}, User.FindFirst("id").Value);
}
});
}
return result;
}
/// <summary>
/// 添加或更新工作量[AUTH]
/// </summary>
/// <param name="_trialWorkloadService"></param>
/// <param name="workLoadAddOrUpdateModel"></param>
/// <returns></returns>
[HttpPost, Route("doctorWorkload/workLoadAddOrUpdate")]
[TypeFilter(typeof(TrialResourceFilter),Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task<IResponseOutput> WorkLoadAddOrUpdate([FromServices] IDoctorWorkloadService _trialWorkloadService, WorkloadCommand workLoadAddOrUpdateModel)
{
var userId = Guid.Parse(User.FindFirst("id").Value);
var result = await _trialWorkloadService.AddOrUpdateWorkload(workLoadAddOrUpdateModel, userId);
if (result.IsSuccess && workLoadAddOrUpdateModel.DataFrom == 2)
{
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
{
NeedCalculateReviewers = new List<Guid>()
{
workLoadAddOrUpdateModel.DoctorId
},
CalculateMonth = workLoadAddOrUpdateModel.WorkTime
}, User.FindFirst("id").Value);
}
return result;
}
[HttpDelete, Route("doctorWorkload/deleteWorkLoad/{id:guid}/{trialId:guid}")]
[TypeFilter(typeof(TrialResourceFilter),Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task<IResponseOutput> DeleteWorkLoad([FromServices] IDoctorWorkloadService _trialWorkloadService, Guid id)
{
//先判断该工作量的费用是否被锁定,如果被锁定,则不能删除
var workload = await _trialWorkloadService.GetWorkloadDetailById(id);
var yearMonth = workload.WorkTime.ToString("yyyy-MM");
var isLock = await _calculateService.IsLock(workload.DoctorId, yearMonth);
if (isLock)
{
//---Expenses have been settled and workload can not be reset.
return ResponseOutput.NotOk(_localizer["Financial_ChargeSettled"]);
}
var deleteResult = await _trialWorkloadService.DeleteWorkload(id);
if (workload.DataFrom == (int)Domain.Share.WorkLoadFromStatus.FinalConfirm)
{
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
{
NeedCalculateReviewers = new List<Guid>()
{
workload.DoctorId
},
CalculateMonth = workload.WorkTime
}, User.FindFirst("id").Value);
}
return deleteResult;
}
/// <summary>
/// 添加或更新汇率(会触发没有对锁定的费用计算)
/// </summary>
[HttpPost, Route("exchangeRate/addOrUpdateExchangeRate")]
public async Task<IResponseOutput> AddOrUpdateExchangeRate([FromServices] IExchangeRateService _exchangeRateService, [FromServices] IPaymentAdjustmentService _costAdjustmentService, ExchangeRateCommand addOrUpdateModel)
{
var result = await _exchangeRateService.AddOrUpdateExchangeRate(addOrUpdateModel);
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, addOrUpdateModel.YearMonth);
foreach (var item in calcList)
{
if (item != null)
{
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
{
NeedCalculateReviewers = new List<Guid>()
{
item.DoctorId
},
CalculateMonth = DateTime.Parse(item.YearMonth)
}, User.FindFirst("id").Value);
}
}
await _costAdjustmentService.CalculateCNY(addOrUpdateModel.YearMonth, addOrUpdateModel.Rate);
return result;
}
/// <summary>
/// 添加或更新 职称单价[AUTH]
/// </summary>
[HttpPost, Route("rankPrice/addOrUpdateRankPrice")]
public async Task<IResponseOutput> AddOrUpdateRankPrice([FromServices] IReviewerPayInfoService _reviewerPayInfoService, [FromServices] IRankPriceService _rankPriceService, RankPriceCommand addOrUpdateModel)
{
if (addOrUpdateModel.Id != Guid.Empty && addOrUpdateModel.Id != null)
{
var needCalReviewerIds =await _reviewerPayInfoService.GetReviewerIdByRankId(Guid.Parse(addOrUpdateModel.Id.ToString()));
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
foreach (var item in calcList)
{
if (item != null && needCalReviewerIds.Contains(item.DoctorId))
{
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
{
NeedCalculateReviewers = new List<Guid>()
{
item.DoctorId
},
CalculateMonth = DateTime.Parse(item.YearMonth)
}, User.FindFirst("id").Value);
}
}
}
var userId = Guid.Parse(User.FindFirst("id").Value);
return await _rankPriceService.AddOrUpdateRankPrice(addOrUpdateModel, userId);
}
/// <summary>
/// 添加或更新(替换)医生支付展信息[AUTH]
/// </summary>
[HttpPost, Route("reviewerPayInfo/addOrUpdateReviewerPayInfo")]
public async Task<IResponseOutput> AddOrUpdateReviewerPayInfo([FromServices] IReviewerPayInfoService _doctorPayInfoService, ReviewerPayInfoCommand addOrUpdateModel)
{
var userId = Guid.Parse(User.FindFirst("id").Value);
var result =await _doctorPayInfoService.AddOrUpdateReviewerPayInfo(addOrUpdateModel, userId);
var calcList = await _calculateService.GetNeedCalculateReviewerList(addOrUpdateModel.DoctorId, string.Empty);
foreach (var item in calcList)
{
if (item != null)
{
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
{
NeedCalculateReviewers = new List<Guid>()
{
item.DoctorId
},
CalculateMonth = DateTime.Parse(item.YearMonth)
}, User.FindFirst("id").Value);
}
}
return result;
}
/// <summary>
/// 保存(替换)项目支付价格信息(会触发没有被锁定的费用计算)[AUTH]
/// </summary>
[HttpPost, Route("trialPaymentPrice/addOrUpdateTrialPaymentPrice")]
public async Task<IResponseOutput> AddOrUpdateTrialPaymentPrice([FromServices] ITrialPaymentPriceService _trialPaymentPriceService, TrialPaymentPriceCommand addOrUpdateModel)
{
var userId = Guid.Parse(User.FindFirst("id").Value);
var result =await _trialPaymentPriceService.AddOrUpdateTrialPaymentPrice(addOrUpdateModel);
var needCalReviewerIds = await _trialService.GetTrialEnrollmentReviewerIds(addOrUpdateModel.TrialId);
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
foreach (var item in calcList)
{
if (item != null && needCalReviewerIds.Contains(item.DoctorId))
{
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
{
NeedCalculateReviewers = new List<Guid>()
{
item.DoctorId
},
CalculateMonth = DateTime.Parse(item.YearMonth)
}, User.FindFirst("id").Value);
}
}
return result;
}
/// <summary>
/// 批量更新奖励费用[AUTH]
/// </summary>
[HttpPost, Route("volumeReward/addOrUpdatevolumeRewardPriceList")]
public async Task<IResponseOutput> AddOrUpdateAwardPriceList([FromServices] IVolumeRewardService _volumeRewardService, IEnumerable<AwardPriceCommand> addOrUpdateModel)
{
var result =await _volumeRewardService.AddOrUpdateVolumeRewardPriceList(addOrUpdateModel);
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
foreach (var item in calcList)
{
if (item != null)
{
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
{
NeedCalculateReviewers = new List<Guid>()
{
item.DoctorId
},
CalculateMonth = DateTime.Parse(item.YearMonth)
}, User.FindFirst("id").Value);
}
}
return result;
}
/// <summary>
/// 计算医生月度费用,并将计算的结果存入费用表
/// </summary>
[HttpPost, Route("financial/calculateMonthlyPayment")]
public async Task<IResponseOutput> CalculateMonthlyPayment(CalculateDoctorAndMonthDTO param)
{
if (!ModelState.IsValid)
{
//---Invalid parameter.
return ResponseOutput.NotOk(_localizer["Financial_InvalidParameter"]);
}
return await _calculateService.CalculateMonthlyPayment(param, User.FindFirst("id").Value);
}
/// <summary>
/// Financials /Monthly Payment 列表查询接口
/// </summary>
[HttpPost, Route("financial/getMonthlyPaymentList")]
public async Task<IResponseOutput<PaymentDTO>> GetMonthlyPaymentList([FromServices] IPaymentService _paymentService, [FromServices] IExchangeRateService _exchangeRateService, MonthlyPaymentQueryDTO queryParam)
{
return ResponseOutput.Ok(new PaymentDTO
{
CostList = await _paymentService.GetMonthlyPaymentList(queryParam),
ExchangeRate = await _exchangeRateService.GetExchangeRateByMonth(queryParam.StatisticsDate.ToString("yyyy-MM"))
});
}
}
}
@@ -26,19 +26,78 @@ namespace IRaCIS.Core.API.Controllers
[ApiController, ApiExplorerSettings(GroupName = "Reviewer")]
[UnitOfWork]
public class InspectionController(
ITrialDocumentService _trialDocumentService,
IReadingImageTaskService _iReadingImageTaskService,
ITrialConfigService _trialConfigService,
IClinicalAnswerService _clinicalAnswerService,
IReadingClinicalDataService _readingClinicalDataService,
IQCOperationService _qCOperationService,
IInspectionService _inspectionService,
IReadingMedicalReviewService _readingMedicalReviewService,
IReadingMedicineQuestionService _readingMedicineQuestionService
) : ControllerBase
public class InspectionController : ControllerBase
{
private readonly IRepository _repository;
private readonly IMapper _mapper;
private readonly IUserInfo _userInfo;
private readonly ITrialDocumentService _trialDocumentService;
private readonly IQCListService _qCListService;
private readonly IReadingImageTaskService _iReadingImageTaskService;
private readonly IHttpContextAccessor _httpContext;
private readonly ITrialConfigService _trialConfigService;
private readonly INoneDicomStudyService _noneDicomStudyService;
private readonly IClinicalAnswerService _clinicalAnswerService;
private readonly ISubjectService _subjectService;
private readonly IReadingClinicalDataService _readingClinicalDataService;
private readonly ISubjectVisitService _subjectVisitService;
private readonly IQCOperationService _qCOperationService;
private readonly IClinicalDataService _clinicalDataService;
private readonly IVisitPlanService _visitPlanService;
private readonly IInspectionService _inspectionService;
private readonly IReadingMedicalReviewService _readingMedicalReviewService;
private readonly IReadingMedicineQuestionService _readingMedicineQuestionService;
private readonly IRepository<DataInspection> _dataInspectionRepository;
private delegate Task<IResponseOutput> executionFun(dynamic data);
public InspectionController(IRepository repository,
IRepository<DataInspection> _repositoryDataInspection,
IMapper mapper, IUserInfo userInfo,
ITrialDocumentService trialDocumentService,
IRepository<DataInspection> dataInspectionRepository,
IQCListService _qCListService,
IReadingImageTaskService _iReadingImageTaskService,
IHttpContextAccessor httpContext,
IInspectionService sinspectionService,
IReadingMedicalReviewService readingMedicalReviewService,
IReadingMedicineQuestionService readingMedicineQuestionService,
ITrialConfigService _trialConfigService,
INoneDicomStudyService noneDicomStudyService,
IClinicalAnswerService clinicalAnswerService,
ISubjectService _subjectService,
IReadingClinicalDataService _readingClinicalDataService,
ISubjectVisitService subjectVisitService,
IQCOperationService qCOperationService,
IClinicalDataService clinicalDataService,
IVisitPlanService visitPlanService
)
{
this._repository = repository;
this._mapper = mapper;
this._userInfo = userInfo;
this._inspectionService = sinspectionService;
this._readingMedicalReviewService = readingMedicalReviewService;
this._readingMedicineQuestionService = readingMedicineQuestionService;
this._trialDocumentService = trialDocumentService;
this._qCListService = _qCListService;
this._iReadingImageTaskService = _iReadingImageTaskService;
this._httpContext = httpContext;
this._trialConfigService = _trialConfigService;
this._noneDicomStudyService = noneDicomStudyService;
this._clinicalAnswerService = clinicalAnswerService;
this._subjectService = _subjectService;
this._readingClinicalDataService = _readingClinicalDataService;
this._subjectVisitService = subjectVisitService;
this._qCOperationService = qCOperationService;
this._clinicalDataService = clinicalDataService;
this._visitPlanService = visitPlanService;
this._dataInspectionRepository = dataInspectionRepository;
}
#region
/// <summary>
/// 获取稽查数据
@@ -249,28 +308,11 @@ namespace IRaCIS.Core.API.Controllers
}
/// <summary>
/// PM签名一致性分析临床数据
/// </summary>
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingClinicalData/SignConsistencyAnalysisReadingClinicalData")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
[UnitOfWork]
public async Task<IResponseOutput> SignConsistencyAnalysisReadingClinicalData(DataInspectionDto<SignConsistencyAnalysisReadingClinicalDataInDto> opt)
{
var singid = await _inspectionService.RecordSing(opt.SignInfo);
var result = await _readingClinicalDataService.SignConsistencyAnalysisReadingClinicalData(opt.Data);
await _inspectionService.CompletedSign(singid, result);
return result;
}
/// <summary>
/// 提交结构化录入并签名
/// </summary>
/// <param name="opt"></param>
/// <returns></returns>
/// <summary>
/// 提交结构化录入并签名
/// </summary>
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ClinicalAnswer/SubmitClinicalFormAndSign")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
@@ -360,19 +402,6 @@ namespace IRaCIS.Core.API.Controllers
return result;
}
[HttpPost, Route("Inspection/configTrialBasicInfo/ConfigTrialPACSInfoConfirm")]
[UnitOfWork]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt" })]
public async Task<IResponseOutput> ConfigTrialPACSInfoConfirm(DataInspectionDto<TrialPACSConfig> opt)
{
opt.Data.IsTrialPACSConfirmed = true;
var singid = await _inspectionService.RecordSing(opt.SignInfo);
var result = await _trialConfigService.ConfigTrialPACSInfo(opt.Data);
await _inspectionService.CompletedSign(singid, result);
return result;
}
/// <summary>
/// 签名确认
/// </summary>
@@ -390,30 +419,13 @@ namespace IRaCIS.Core.API.Controllers
}
/// <summary>
/// 重置并同步项目阅片标准
/// </summary>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingCriterion/ResetAndAsyncCriterion")]
[UnitOfWork]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task<IResponseOutput> ResetAndAsyncCriterion(DataInspectionDto<ResetAndAsyncCriterionInDto> opt)
{
var singid = await _inspectionService.RecordSing(opt.SignInfo);
var result = await _trialConfigService.ResetAndAsyncCriterion(opt.Data);
await _inspectionService.CompletedSign(singid, result);
return result;
}
/// <summary>
/// CRC RequestToQC 批量提交
/// </summary>
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/QCOperation/CRCRequestToQC")]
/// <summary>
/// CRC RequestToQC 批量提交
/// </summary>
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/QCOperation/CRCRequestToQC")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
[UnitOfWork]
public async Task<IResponseOutput> CRCRequestToQC(DataInspectionDto<CRCRequestToQCCommand> opt)
@@ -1,5 +1,6 @@
using AutoMapper;
using DocumentFormat.OpenXml.Drawing;
using EasyCaching.Core;
using ExcelDataReader;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Interfaces;
@@ -9,7 +10,8 @@ using IRaCIS.Core.Application.Contracts.Dicom;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.MassTransit.Command;
using IRaCIS.Core.Application.MediatR.CommandAndQueries;
using IRaCIS.Core.Application.MediatR.Handlers;
using IRaCIS.Core.Application.Service;
using IRaCIS.Core.Application.Service.ImageAndDoc;
using IRaCIS.Core.Application.Service.Reading.Dto;
@@ -18,8 +20,9 @@ using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using Magicodes.ExporterAndImporter.Excel;
using MassTransit;
using MassTransit.Mediator;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.Hosting;
@@ -30,12 +33,12 @@ using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using MiniExcelLibs;
using Newtonsoft.Json;
using SharpCompress.Archives;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Data;
@@ -44,7 +47,6 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ZiggyCreatures.Caching.Fusion;
using Path = System.IO.Path;
namespace IRaCIS.Core.API.Controllers
@@ -227,15 +229,31 @@ namespace IRaCIS.Core.API.Controllers
[ApiExplorerSettings(GroupName = "Image")]
[ApiController]
public class StudyController(
IMediator _mediator,
QCCommon _qCCommon,
IUserInfo _userInfo,
IRepository<SubjectVisit> _subjectVisitRepository,
IStringLocalizer _localizer) : UploadBaseController
public class StudyController : UploadBaseController
{
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
private readonly IMediator _mediator;
private readonly IWebHostEnvironment _hostEnvironment;
private readonly IRepository _repository;
private readonly IEasyCachingProvider _provider;
private readonly QCCommon _qCCommon;
public StudyController(IMapper mapper, IUserInfo userInfo, IWebHostEnvironment hostEnvironment, IMediator mediator, IEasyCachingProvider provider,
QCCommon qCCommon,
IRepository repository)
{
_qCCommon = qCCommon;
_provider = provider;
_hostEnvironment = hostEnvironment;
_mediator = mediator;
_mapper = mapper;
_userInfo = userInfo;
_repository = repository;
}
[HttpPost, Route("Study/PreArchiveStudy")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
@@ -244,11 +262,17 @@ namespace IRaCIS.Core.API.Controllers
[FromServices] IRepository<StudyMonitor> _studyMonitorRepository)
{
if (_provider.Get<List<SystemAnonymization>>(StaticData.Anonymize.Anonymize_AddFixedFiled).Value == null)
{
await _mediator.Send(new AnonymizeCacheRequest());
}
var savedInfo = _studyService.GetSaveToDicomInfo(preArchiveStudyCommand.SubjectVisitId);
var studyMonitor = new StudyMonitor()
{
TrialId = savedInfo.TrialId,
SiteId = savedInfo.SiteId,
SubjectId = savedInfo.SubjectId,
SubjectVisitId = savedInfo.SubjectVisitId,
@@ -271,8 +295,9 @@ namespace IRaCIS.Core.API.Controllers
[DisableFormValueModelBinding]
[DisableRequestSizeLimit]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task<IResponseOutput> ArchiveStudyNew( Guid trialId, Guid subjectVisitId, string studyInstanceUid, Guid? abandonStudyId, Guid studyMonitorId,
public async Task<IResponseOutput> ArchiveStudyNew(/*[FromForm] ArchiveStudyCommand archiveStudyCommand,*/ Guid trialId, Guid subjectVisitId, string studyInstanceUid, Guid? abandonStudyId, Guid studyMonitorId,
[FromServices] ILogger<UploadDownLoadController> _logger,
[FromServices] IEasyCachingProvider _provider,
[FromServices] IStudyService _studyService,
[FromServices] IHubContext<UploadHub, IUploadClient> _uploadHub,
[FromServices] IDicomArchiveService _dicomArchiveService,
@@ -287,7 +312,7 @@ namespace IRaCIS.Core.API.Controllers
string.IsNullOrEmpty(mediaTypeHeader.Boundary.Value))
{
//---不支持的MediaType
return ResponseOutput.NotOk(_localizer["UploadDownLoad_UnsupportedMedia"]);
return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_UnsupportedMedia"));
}
var archiveStudyCommand = new ArchiveStudyCommand() { AbandonStudyId = abandonStudyId, StudyInstanceUid = studyInstanceUid, SubjectVisitId = subjectVisitId };
@@ -297,6 +322,22 @@ namespace IRaCIS.Core.API.Controllers
var startTime = DateTime.Now;
if (_provider.Exists($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}") && _provider.Get<Guid>($"StudyUid_{trialId}_{studyInstanceUid}").Value == _userInfo.Id)
{
_provider.Set($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}", _userInfo.Id, TimeSpan.FromMinutes(30));
}
//if (_provider.Exists($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}"))
//{
// //---当前已有人正在上传和归档该检查!
// return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_ArchiveInProgress"));
//}
//else
//{
// _provider.Set($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}", _userInfo.Id, TimeSpan.FromMinutes(30));
//}
//到了接口,代表上传结束了
@@ -360,14 +401,15 @@ namespace IRaCIS.Core.API.Controllers
}
catch (Exception)
catch (Exception ex)
{
_provider.Remove($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}");
//---请求异常,请重试!
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_RequestError"]);
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_RequestError"));
}
studyMonitor.FileSize = (long)HttpContext.Request.ContentLength;
studyMonitor.FileSize = (decimal)HttpContext.Request.ContentLength;
studyMonitor.FileCount = archiveResult.ReceivedFileCount;
studyMonitor.FailedFileCount = archiveResult.ErrorFiles.Count;
studyMonitor.IsDicomReUpload = archiveStudyCommand.AbandonStudyId != null;
@@ -400,6 +442,7 @@ namespace IRaCIS.Core.API.Controllers
}
finally
{
_provider.Remove($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}");
studyMonitor.StudyId = archiveResult.ArchivedDicomStudies.FirstOrDefault()?.Id ?? Guid.Empty;
studyMonitor.StudyCode = archiveResult.ArchivedDicomStudies.FirstOrDefault()?.StudyCode;
@@ -417,6 +460,248 @@ namespace IRaCIS.Core.API.Controllers
}
#region
///// <summary>
///// 上传临床数据 多文件
///// </summary>
///// <param name="subjectVisitId"></param>
///// <returns></returns>
//[HttpPost("ClinicalData/UploadVisitClinicalData/{trialId:guid}/{subjectVisitId:guid}")]
//[DisableRequestSizeLimit]
////[Authorize(Policy = IRaCISPolicy.CRC)]
//[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
//public async Task<IResponseOutput> UploadVisitClinicalData(Guid subjectVisitId)
//{
// await _qCCommon.VerifyIsCRCSubmmitAsync(_repository, _userInfo, subjectVisitId);
// var sv = _repository.Where<SubjectVisit>(t => t.Id == subjectVisitId).Select(t => new { t.TrialId, t.SiteId, t.SubjectId }).FirstOrDefault().IfNullThrowException();
// await FileUploadAsync(async (fileName) =>
// {
// var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetClinicalDataPath(_hostEnvironment, fileName, sv.TrialId, sv.SiteId, sv.SubjectId, subjectVisitId);
// //插入临床pdf 路径
// await _repository.AddAsync(new PreviousPDF()
// {
// SubjectVisitId = subjectVisitId,
// IsVisist = true,
// DataType = ClinicalDataType.MedicalHistory,
// UploadType = ClinicalUploadType.PDF,
// SubjectId = sv.SubjectId,
// TrialId = sv.TrialId,
// ClinicalLevel = ClinicalLevel.Subject,
// Path = relativePath,
// FileName = fileRealName
// });
// return serverFilePath;
// });
// await _repository.SaveChangesAsync();
// return ResponseOutput.Ok();
//}
///// <summary>
///// 上传临床数据模板
///// </summary>
///// <param name="trialId"></param>
///// <returns></returns>
//[HttpPost("ClinicalData/UploadClinicalTemplate")]
//[DisableRequestSizeLimit]
//[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt", "AfterStopCannNotOpt" })]
//public async Task<IResponseOutput<List<FileDto>>> UploadClinicalTemplate(Guid? trialId)
//{
// if (trialId == null)
// trialId = default(Guid);
// var filerelativePath = string.Empty;
// List<FileDto> fileDtos = new List<FileDto>();
// await FileUploadAsync(async (fileName) =>
// {
// var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetClinicalTemplatePath(_hostEnvironment, fileName, trialId.Value);
// //插入临床pdf 路径
// filerelativePath = relativePath;
// fileDtos.Add(new FileDto()
// {
// FileName = fileName,
// Path = relativePath
// });
// await Task.CompletedTask;
// return serverFilePath;
// });
// return ResponseOutput.Ok(fileDtos);
//}
///// <summary>
///// 上传阅片临床数据
///// </summary>
///// <param name="trialId"></param>
///// <param name="subjectId"></param>
///// <param name="readingId"></param>
///// <returns></returns>
//[HttpPost("ClinicalData/UploadClinicalData/{trialId:guid}/{subjectId:guid}/{readingId:guid}")]
//[DisableRequestSizeLimit]
//[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
//public async Task<IResponseOutput<List<FileDto>>> UploadReadClinicalData(Guid trialId, Guid subjectId, Guid readingId)
//{
// var filerelativePath = string.Empty;
// List<FileDto> fileDtos = new List<FileDto>();
// var siteid = await _repository.Where<Subject>(x => x.Id == subjectId).Select(x => x.SiteId).FirstOrDefaultAsync();
// await FileUploadAsync(async (fileName) =>
// {
// var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetReadClinicalDataPath(_hostEnvironment, fileName, trialId, siteid, subjectId, readingId);
// //插入临床pdf 路径
// filerelativePath = relativePath;
// fileDtos.Add(new FileDto()
// {
// FileName = fileName,
// Path = relativePath
// });
// await Task.CompletedTask;
// return serverFilePath;
// });
// return ResponseOutput.Ok(fileDtos);
//}
///// <summary>
///// 上传截图
///// </summary>
///// <param name="subjectId"></param>
///// <returns></returns>
//[HttpPost("Printscreen/UploadPrintscreen/{subjectId:guid}")]
//[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
//public async Task<IResponseOutput<FileDto>> UploadPrintscreen(Guid subjectId)
//{
// var subjectInfo = await this._repository.Where<Subject>(x => x.Id == subjectId).FirstNotNullAsync();
// FileDto fileDto = new FileDto();
// await FileUploadAsync(async (fileName) =>
// {
// var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetUploadPrintscreenFilePath(_hostEnvironment, fileName, subjectInfo.TrialId, subjectInfo.SiteId, subjectInfo.Id);
// fileDto.Path = relativePath;
// fileDto.FileName = fileName;
// await Task.CompletedTask;
// return serverFilePath;
// });
// return ResponseOutput.Ok(fileDto);
//}
///// <summary>
///// 上传Reading问题的图像
///// </summary>
///// <param name="trialId"></param>
///// <param name="visitTaskId"></param>
///// <returns></returns>
//[HttpPost("VisitTask/UploadReadingAnswerImage/{trialId:guid}/{visitTaskId:guid}")]
//[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
//public async Task<IResponseOutput<FileDto>> UploadReadingAnswerImage(Guid trialId, Guid visitTaskId)
//{
// FileDto fileDto = new FileDto();
// await FileUploadAsync(async (fileName) =>
// {
// var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetFilePath(_hostEnvironment, fileName, trialId, visitTaskId, StaticData.Folder.JudgeTask);
// fileDto.Path = relativePath;
// fileDto.FileName = fileName;
// await Task.CompletedTask;
// return serverFilePath;
// });
// return ResponseOutput.Ok(fileDto);
//}
///// <summary>
///// 上传裁判任务的图像
///// </summary>
///// <param name="trialId"></param>
///// <param name="visitTaskId"></param>
///// <returns></returns>
//[HttpPost("VisitTask/UploadJudgeTaskImage/{trialId:guid}/{visitTaskId:guid}")]
//[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
//public async Task<IResponseOutput<FileDto>> UploadJudgeTaskImage(Guid trialId, Guid visitTaskId)
//{
// FileDto fileDto = new FileDto();
// await FileUploadAsync(async (fileName) =>
// {
// var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetFilePath(_hostEnvironment, fileName, trialId, visitTaskId, StaticData.Folder.JudgeTask);
// fileDto.Path = relativePath;
// fileDto.FileName = fileName;
// await Task.CompletedTask;
// return serverFilePath;
// });
// return ResponseOutput.Ok(fileDto);
//}
///// <summary>
///// 上传医学审核图片
///// </summary>
///// <param name="trialId"></param>
///// <param name="taskMedicalReviewId"></param>
///// <returns></returns>
//[HttpPost("TaskMedicalReview/UploadMedicalReviewImage/{trialId:guid}/{taskMedicalReviewId:guid}")]
//[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
//public async Task<IResponseOutput<FileDto>> UploadMedicalReviewImage(Guid trialId, Guid taskMedicalReviewId)
//{
// string path = string.Empty;
// FileDto fileDto = new FileDto();
// await FileUploadAsync(async (fileName) =>
// {
// var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetMedicalReviewImage(_hostEnvironment, fileName, trialId, taskMedicalReviewId);
// //await _repository.UpdatePartialFromQueryAsync<TaskMedicalReview>(x => x.Id == taskMedicalReviewId, x => new TaskMedicalReview()
// //{
// // ImagePath = relativePath,
// // FileName = fileName,
// //});
// path = relativePath;
// fileDto.Path = relativePath;
// fileDto.FileName = fileName;
// return serverFilePath;
// });
// await _repository.SaveChangesAsync();
// return ResponseOutput.Ok(fileDto);
//}
#endregion
public class UploadNoneDicomFileCommand
{
public Guid TrialId { get; set; }
@@ -433,26 +718,20 @@ namespace IRaCIS.Core.API.Controllers
public string FilePath { get; set; }
public string FileName { get; set; }
public int FileFize { get; set; }
public string FileType { get; set; }
}
}
/// <summary>
/// 上传非Dicom 文件 支持压缩包 多文件上传
/// </summary>
/// <param name="incommand"></param>
/// <param name="_noneDicomStudyRepository"></param>
/// <param name="_studyMonitorRepository"></param>
/// <param name="_noneDicomStudyFileRepository"></param>
/// <returns></returns>
//[DisableRequestSizeLimit]
[HttpPost("NoneDicomStudy/UploadNoneDicomFile")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
//[Authorize(Policy = IRaCISPolicy.CRC)]
public async Task<IResponseOutput> UploadNoneDicomFile(UploadNoneDicomFileCommand incommand,
[FromServices] IRepository<NoneDicomStudy> _noneDicomStudyRepository,
[FromServices] IRepository<StudyMonitor> _studyMonitorRepository,
[FromServices] IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository)
[FromServices] IRepository<NoneDicomStudy> _noneDicomStudyRepository, [FromServices] IRepository<StudyMonitor> _studyMonitorRepository)
{
var subjectVisitId = incommand.SubjectVisitId;
@@ -460,9 +739,9 @@ namespace IRaCIS.Core.API.Controllers
var noneDicomStudyId = incommand.NoneDicomStudyId;
await _qCCommon.VerifyIsCRCSubmmitAsync(_subjectVisitRepository, _userInfo, subjectVisitId);
await _qCCommon.VerifyIsCRCSubmmitAsync(_repository, _userInfo, subjectVisitId);
var sv = (await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => new { t.TrialId, t.TrialSiteId, t.SubjectId }).FirstOrDefaultAsync()).IfNullThrowConvertException();
var sv = (await _repository.Where<SubjectVisit>(t => t.Id == subjectVisitId).Select(t => new { t.TrialId, t.SiteId, t.SubjectId }).FirstOrDefaultAsync()).IfNullThrowConvertException();
var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == studyMonitorId);
@@ -470,7 +749,7 @@ namespace IRaCIS.Core.API.Controllers
foreach (var item in incommand.UploadedFileList)
{
await _noneDicomStudyFileRepository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, NoneDicomStudyId = noneDicomStudyId,FileType=item.FileType,FileSize=item.FileFize });
await _repository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, NoneDicomStudyId = noneDicomStudyId });
}
var uploadFinishedTime = DateTime.Now;
@@ -487,29 +766,21 @@ namespace IRaCIS.Core.API.Controllers
studyMonitor.StudyCode = noneDicomStudy.StudyCode;
studyMonitor.ArchiveFinishedTime = DateTime.Now;
studyMonitor.IP = _userInfo.IP;
studyMonitor.IsSuccess = true;
await _noneDicomStudyRepository.SaveChangesAsync();
await _repository.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// 一致性核查 excel上传 支持三种格式
/// </summary>
/// <param name="trialId"></param>
/// <param name="oSSService"></param>
/// <param name="_inspectionFileRepository"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[HttpPost("QCOperation/UploadVisitCheckExcel/{trialId:guid}")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task<IResponseOutput> UploadVisitCheckExcel(Guid trialId, [FromServices] IOSSService oSSService, [FromServices] IRepository<InspectionFile> _inspectionFileRepository)
//[Authorize(Policy = IRaCISPolicy.PM_APM)]
public async Task<IResponseOutput> UploadVisitCheckExcel(Guid trialId, [FromServices] IOSSService oSSService)
{
var fileName = string.Empty;
@@ -519,19 +790,19 @@ namespace IRaCIS.Core.API.Controllers
{
fileName = realFileName;
if (!fileName.EndsWith(".xlsx") && !fileName.EndsWith(".xls"))
if (!fileName.EndsWith(".xlsx") && !fileName.EndsWith(".csv") && !fileName.EndsWith(".xls"))
{
//---支持.xlsx、.xls格式的文件上传。
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_SupportedFormats"]);
//---支持.xlsx、.xls、.csv格式的文件上传。
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_SupportedFormats"));
}
fileStream.CopyTo(templateFileStream);
templateFileStream.Seek(0, SeekOrigin.Begin);
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/Check", realFileName);
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/Check", realFileName);
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId });
await _repository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId });
return ossRelativePath;
@@ -543,22 +814,9 @@ namespace IRaCIS.Core.API.Controllers
var etcCheckList = new List<CheckViewModel>();
#region MiniExcel
if (fileName.EndsWith(".xlsx"))
{
etcCheckList = MiniExcel.Query<CheckViewModel>(templateFileStream, excelType: ExcelType.XLSX).ToList();
}
else if (fileName.EndsWith(".csv"))
{
//因为csv 需要加配置文件 不然都是null
etcCheckList = MiniExcel.Query<CheckViewModel>(templateFileStream, null, configuration: new MiniExcelLibs.Csv.CsvConfiguration()
{
StreamReaderFunc = (stream) => new StreamReader(stream, Encoding.GetEncoding("gb2312"))
}).ToList();
}
//if (fileName.EndsWith(".csv"))
//{
// //因为csv 需要加配置文件 不然都是null
@@ -574,72 +832,67 @@ namespace IRaCIS.Core.API.Controllers
#endregion
#region net8
//Magicodes 支持自定义特性验证
// if (fileName.EndsWith(".xlsx"))
//{
// var Importer = new ExcelImporter();
if (fileName.EndsWith(".xlsx"))
{
var Importer = new ExcelImporter();
// var import = await Importer.Import<CheckViewModel>(templateFileStream);
var import = await Importer.Import<CheckViewModel>(templateFileStream);
// if (import.Exception != null) return ResponseOutput.NotOk(import.Exception.ToString());
if (import.Exception != null) return ResponseOutput.NotOk(import.Exception.ToString());
// //if (import.RowErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.RowErrors));
//if (import.RowErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.RowErrors));
// if (import.TemplateErrors.Count > 0) return ResponseOutput.NotOk(_localizer["UploadDownLoad_TemplateErrors"]);
if (import.TemplateErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.TemplateErrors));
// etcCheckList = import.Data.ToList();
//}
//else if (fileName.EndsWith(".csv"))
//{
// #region 临时方案 MiniExcel读取 然后保存为xlsx 再用 Magicodes验证数据
etcCheckList = import.Data.ToList();
}
else if (fileName.EndsWith(".csv"))
{
#region MiniExcel读取 xlsx Magicodes验证数据
// //因为csv 需要加配置文件 不然都是null
// etcCheckList = MiniExcel.Query<CheckViewModel>(templateFileStream, null, configuration: new MiniExcelLibs.Csv.CsvConfiguration()
// {
// StreamReaderFunc = (stream) => new StreamReader(stream, Encoding.GetEncoding("gb2312"))
// }).ToList();
//因为csv 需要加配置文件 不然都是null
etcCheckList = MiniExcel.Query<CheckViewModel>(templateFileStream, null, configuration: new MiniExcelLibs.Csv.CsvConfiguration()
{
StreamReaderFunc = (stream) => new StreamReader(stream, Encoding.GetEncoding("gb2312"))
}).ToList();
// var (csVToXlsxPath, csVToXlsxRelativePath) = FileStoreHelper.GetTrialCheckFilePath(_hostEnvironment, Path.GetFileNameWithoutExtension(fileName) + ".xlsx", trialId);
var (csVToXlsxPath, csVToXlsxRelativePath) = FileStoreHelper.GetTrialCheckFilePath(_hostEnvironment, Path.GetFileNameWithoutExtension(fileName) + ".xlsx", trialId);
// await MiniExcel.SaveAsAsync(csVToXlsxPath, etcCheckList, excelType: ExcelType.XLSX);
await MiniExcel.SaveAsAsync(csVToXlsxPath, etcCheckList, excelType: ExcelType.XLSX);
// var Importer = new ExcelImporter();
var Importer = new ExcelImporter();
// var import = await Importer.Import<CheckViewModel>(System.IO.File.OpenRead(csVToXlsxPath));
var import = await Importer.Import<CheckViewModel>(System.IO.File.OpenRead(csVToXlsxPath));
// if (import.Exception != null) return ResponseOutput.NotOk(import.Exception.ToString());
if (import.Exception != null) return ResponseOutput.NotOk(import.Exception.ToString());
// //if (import.RowErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.RowErrors));
//if (import.RowErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.RowErrors));
// if (import.TemplateErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.TemplateErrors));
if (import.TemplateErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.TemplateErrors));
// etcCheckList = import.Data.ToList();
etcCheckList = import.Data.ToList();
// #endregion
#endregion
// #region 导入组件有问题 excel编码格式
// //var Importer = new CsvImporter();
#region excel编码格式
//var Importer = new CsvImporter();
// //var import = await Importer.Import<CheckViewModel>(File.OpenRead(filePath));
//var import = await Importer.Import<CheckViewModel>(File.OpenRead(filePath));
// //if (import.Exception != null) return ResponseOutput.NotOk(import.Exception.ToString());
//if (import.Exception != null) return ResponseOutput.NotOk(import.Exception.ToString());
// //if (import.RowErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.RowErrors));
//if (import.RowErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.RowErrors));
// //if (import.TemplateErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.TemplateErrors));
//if (import.TemplateErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.TemplateErrors));
// //etcCheckList = import.Data.ToList();
// #endregion
//etcCheckList = import.Data.ToList();
#endregion
//}
#endregion
}
//ExcelReaderFactory 需要自己验证数据 并且从固定列取数据
else
{
@@ -678,7 +931,7 @@ namespace IRaCIS.Core.API.Controllers
if (etcCheckList == null || etcCheckList.Count == 0)
{
//---请保证上传数据符合模板文件中的样式,且存在有效数据。
return ResponseOutput.NotOk(_localizer["UploadDownLoad_InvalidData"]);
return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_InvalidData"));
}
else
{
@@ -699,18 +952,13 @@ namespace IRaCIS.Core.API.Controllers
if (etcCheckList.Count == 0)
{
//---请保证上传数据符合模板文件中的样式,且存在有效数据。
return ResponseOutput.NotOk(_localizer["UploadDownLoad_InvalidData"]);
return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_InvalidData"));
}
}
// 适合获取结果的
//var client = _mediator.CreateRequestClient<ConsistenCheckCommand>();
//await client.GetResponse<ConsistenCheckResult>(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
//不获取结果,不用定义返回类型
await _mediator.Send(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
await _mediator.Send(new ConsistencyVerificationRequest() { ETCList = etcCheckList, TrialId = trialId });
return ResponseOutput.Ok();
@@ -720,140 +968,8 @@ namespace IRaCIS.Core.API.Controllers
#endregion
#region
#region DTO
public class DoctorDownloadInfo
{
public Guid Id { get; set; }
public string Name { get; set; }
public string ReviewerCode { get; set; }
public List<DownloadFileInfo> FileList { get; set; }
}
public class DownloadFileInfo
{
public string FileName { get; set; }
public string Path { get; set; }
}
public class GetDoctorPathCommand
{
public int Language { get; set; }
public List<Guid> DoctorIdList { get; set; }
}
public class GetDoctoreAttachPathCommand
{
public Guid DoctorId { get; set; }
public List<Guid> AttachmentIdList { get; set; }
}
#endregion
/// <summary>医生文件上传下载</summary>
[ApiExplorerSettings(GroupName = "Common")]
[ApiController]
public class FileController : UploadBaseController
{
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
private readonly IWebHostEnvironment _hostEnvironment;
private readonly IFileService _fileService;
public FileController(IMapper mapper, IUserInfo userInfo, IWebHostEnvironment hostEnvironment, IFileService fileService)
{
_fileService = fileService;
_hostEnvironment = hostEnvironment;
_mapper = mapper;
_userInfo = userInfo;
}
/// <summary>
/// New 医生首页 多选 获取多个医生信息+文件路径列表 医生压缩包名称 doctorCode + "_" + doctorName _(时间戳或者随机的Guid)
/// </summary>
/// <returns></returns>
[HttpPost, Route("file/GetOfficialResume")]
public async Task<IResponseOutput<List<DoctorDownloadInfo>>> GetOfficialResume(GetDoctorPathCommand command,
[FromServices] IRepository<Attachment> _attachmentrepository)
{
var list = await _attachmentrepository.Where(t => command.DoctorIdList.Contains(t.DoctorId) && command.Language == t.Language).GroupBy(t => new { Name = t.Doctor.FirstName + "_" + t.Doctor.LastName, ReviewerCode = t.Doctor.ReviewerCode, t.DoctorId })
.Select(g => new DoctorDownloadInfo()
{
Id = g.Key.DoctorId,
Name = g.Key.Name,
ReviewerCode = g.Key.ReviewerCode,
FileList = g.Select(t => new DownloadFileInfo() { FileName = t.FileName, Path = t.Path }).ToList()
}).ToListAsync();
return ResponseOutput.Ok(list);
}
/// <summary>
/// New 项目入组 勾选获取简历路径
/// </summary>
/// <param name="command"></param>
/// <param name="_doctorService"></param>
/// <param name="_attachmentrepository"></param>
/// <returns></returns>
[HttpPost, Route("file/GetTrialDoctorOfficialResume")]
public async Task<IResponseOutput<List<DoctorDownloadInfo>>> GetTrialDoctorOfficialResume(GetDoctorPathCommand command,
[FromServices] IDoctorService _doctorService,
[FromServices] IRepository<Attachment> _attachmentrepository)
{
var list = await _attachmentrepository.Where(t => command.DoctorIdList.Contains(t.DoctorId) && command.Language == t.Language && t.IsOfficial && t.Type.Equals("Resume")).GroupBy(t => new { Name = t.Doctor.FirstName + "_" + t.Doctor.LastName, ReviewerCode = t.Doctor.ReviewerCode, t.DoctorId })
.Select(g => new DoctorDownloadInfo()
{
Id = g.Key.DoctorId,
Name = g.Key.Name,
ReviewerCode = g.Key.ReviewerCode,
FileList = g.Select(t => new DownloadFileInfo() { FileName = t.FileName, Path = t.Path }).ToList()
}).ToListAsync();
return ResponseOutput.Ok(list);
}
/// <summary>
/// new 医生详情 勾选或者下载文件路径
/// </summary>
/// <param name="command"></param>
/// <param name="_doctorService"></param>
/// <param name="_attachmentrepository"></param>
/// <returns></returns>
[HttpPost, Route("file/GetDoctorAttachment")]
public async Task<IResponseOutput<DoctorDownloadInfo>> GetDoctorAttachment(GetDoctoreAttachPathCommand command,
[FromServices] IDoctorService _doctorService,
[FromServices] IRepository<Attachment> _attachmentrepository)
{
var find = await _attachmentrepository.Where(t => command.DoctorId == t.DoctorId && command.AttachmentIdList.Contains(t.Id)).GroupBy(t => new { Name = t.Doctor.FirstName + "_" + t.Doctor.LastName, ReviewerCode = t.Doctor.ReviewerCode, t.DoctorId })
.Select(g => new DoctorDownloadInfo()
{
Id = g.Key.DoctorId,
Name = g.Key.Name,
ReviewerCode = g.Key.ReviewerCode,
FileList = g.Select(t => new DownloadFileInfo() { FileName = t.FileName, Path = t.Path }).ToList()
}).FirstOrDefaultAsync();
return ResponseOutput.Ok(find);
}
}
#endregion
#region
@@ -865,18 +981,25 @@ namespace IRaCIS.Core.API.Controllers
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
private readonly IMediator _mediator;
public IStringLocalizer _localizer { get; set; }
private readonly IWebHostEnvironment _hostEnvironment;
public UploadDownLoadController(IMapper mapper, IUserInfo userInfo, IStringLocalizer localizer, IMediator mediator, IWebHostEnvironment hostEnvironment)
public UploadDownLoadController(IMapper mapper, IUserInfo userInfo, IMediator mediator, IWebHostEnvironment hostEnvironment)
{
_hostEnvironment = hostEnvironment;
_localizer = localizer;
_mediator = mediator;
_mapper = mapper;
_userInfo = userInfo;
}
[HttpPost, Route("TrialSiteSurvey/TestOOS")]
public string TestUploadFileToOOS(string path)
{
return FileStoreHelper.UploadOOS(path, "testc/test", true);
}
[HttpPost, Route("TrialSiteSurvey/UploadTrialSiteSurveyUser")]
[DisableFormValueModelBinding]
[UnitOfWork]
@@ -898,28 +1021,28 @@ namespace IRaCIS.Core.API.Controllers
if (!realFileName.EndsWith(".xlsx", StringComparison.OrdinalIgnoreCase))
{
// 请用提供格式的模板excel上传需要处理的数据
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_TemplateUploadData"]);
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_TemplateUploadData"));
}
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/SiteSurvey", realFileName);
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/SiteSurvey", realFileName);
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId });
return ossRelativePath;
});
//去掉空白行
var excelList = MiniExcel.Query<SiteSurveyUserImportDto>(templateFileStream, excelType: ExcelType.XLSX).ToList()
var excelList = MiniExcel.Query<SiteSurveyUserImportDto>(templateFileStream,excelType:ExcelType.XLSX).ToList()
.Where(t => !(string.IsNullOrWhiteSpace(t.TrialSiteCode) && string.IsNullOrWhiteSpace(t.FirstName) && string.IsNullOrWhiteSpace(t.LastName) && string.IsNullOrWhiteSpace(t.Email)
&& string.IsNullOrWhiteSpace(t.Phone) && string.IsNullOrWhiteSpace(t.UserTypeStr) && string.IsNullOrWhiteSpace(t.OrganizationName))).ToList();
if (excelList.Any(t => string.IsNullOrWhiteSpace(t.TrialSiteCode) || string.IsNullOrWhiteSpace(t.FirstName) || string.IsNullOrWhiteSpace(t.LastName) || string.IsNullOrWhiteSpace(t.Email) || string.IsNullOrWhiteSpace(t.UserTypeStr)))
{
//请确保Excel中 每一行的 中心编号,姓名,邮箱,用户类型数据记录完整再进行上传
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_EnsureCompleteData"]);
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_EnsureCompleteData"));
}
var siteCodeList = excelList.Select(t => t.TrialSiteCode.Trim().ToUpper()).Distinct().ToList();
@@ -927,35 +1050,35 @@ namespace IRaCIS.Core.API.Controllers
if (_trialSiteRepository.Where(t => t.TrialId == trialId && siteCodeList.Contains(t.TrialSiteCode.ToUpper())).Count() != siteCodeList.Count)
{
//在项目中未找到该Excel中部分或全部中心
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_InvalidCenters"]);
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_InvalidCenters"));
}
if (excelList.GroupBy(t => new { t.TrialSiteCode, t.UserTypeStr, t.Email }).Any(g => g.Count() > 1))
if (excelList.GroupBy(t => new {t.TrialSiteCode, t.UserTypeStr, t.Email }).Any(g => g.Count() > 1))
{
// 同一邮箱,同一用户类型,只能生成一个账户,请核查Excel数据
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_CheckDuplicateAccounts"]);
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_CheckDuplicateAccounts"));
}
if (excelList.Any(t => !t.Email.Contains("@")))
{
//有邮箱不符合邮箱格式,请核查Excel数据
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_InvalidEmail"]);
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_InvalidEmail"));
}
var generateUserTypeList = new List<string>() { "CRC", "CRA" };
var generateUserTypeList = new List<string>() { "CRC", "CRA","SR" };
//if (excelList.Any(t => !generateUserTypeList.Contains(t.UserTypeStr.ToUpper())))
//{
// //用户类型仅能为 CRC,SR,CRA 请核查Excel数据
// throw new BusinessValidationFailedException(_localizer["UploadDownLoad_InvalidUserType"]);
//}
if (excelList.Any(t => !generateUserTypeList.Contains(t.UserTypeStr.ToUpper())))
{
//用户类型仅能为 CRC,SR,CRA 请核查Excel数据
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_InvalidUserType"));
}
if (excelList.Count == 0)
{
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_NoValiddata"]);
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_NoValiddata"));
}
//处理好 用户类型 和用户类型枚举
var sysUserTypeList = _usertypeRepository.Where(t => t.UserTypeEnum == UserTypeEnum.CRA || t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Select(t => new { UserTypeId = t.Id, t.UserTypeEnum }).ToList();
var siteList = _trialSiteRepository.Where(t => t.TrialId == trialId && siteCodeList.Contains(t.TrialSiteCode)).Select(t => new { t.TrialSiteCode, TrialSiteId= t.Id }).ToList();
var sysUserTypeList = _usertypeRepository.Where(t => t.UserTypeEnum == UserTypeEnum.CRA || t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator || t.UserTypeEnum == UserTypeEnum.SR).Select(t => new { UserTypeId = t.Id, t.UserTypeEnum }).ToList();
var siteList = _trialSiteRepository.Where(t => t.TrialId == trialId && siteCodeList.Contains(t.TrialSiteCode)).Select(t => new { t.TrialSiteCode, t.SiteId }).ToList();
foreach (var item in excelList)
{
@@ -972,11 +1095,14 @@ namespace IRaCIS.Core.API.Controllers
item.UserTypeEnum = UserTypeEnum.CRA;
break;
case "SR":
item.UserTypeId = sysUserTypeList.FirstOrDefault(t => t.UserTypeEnum == UserTypeEnum.SR).UserTypeId;
item.UserTypeEnum = UserTypeEnum.SR;
break;
}
item.TrialSiteId = siteList.FirstOrDefault(t => t.TrialSiteCode.ToUpper() == item.TrialSiteCode.ToUpper()).TrialSiteId;
item.SiteId = siteList.FirstOrDefault(t => t.TrialSiteCode.ToUpper() == item.TrialSiteCode.ToUpper()).SiteId;
}
@@ -1011,12 +1137,12 @@ namespace IRaCIS.Core.API.Controllers
[DisableFormValueModelBinding]
public async Task<IResponseOutput> UploadCommonDoc()
{
return await SingleFileUploadAsync((fileName) => FileStoreHelper.GetCommonDocPath(_hostEnvironment, fileName));
}
public enum UploadFileType
{
DataUpload = 1,
@@ -1070,6 +1196,8 @@ namespace IRaCIS.Core.API.Controllers
}
}
#endregion
+41 -18
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<SignAssembly>false</SignAssembly>
<UserSecretsId>354572d4-9e15-4099-807c-63a2d29ff9f2</UserSecretsId>
<LangVersion>default</LangVersion>
@@ -14,7 +14,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile>.\IRaCIS.Core.API.xml</DocumentationFile>
<NoWarn>1701;1702;1591;1570;</NoWarn>
<NoWarn>1701;1702;1591;</NoWarn>
<OutputPath>..\bin\</OutputPath>
</PropertyGroup>
@@ -24,7 +24,12 @@
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Remove="wwwroot\**" />
<EmbeddedResource Remove="UploadFile\**" />
<EmbeddedResource Remove="wwwroot\**" />
</ItemGroup>
<ItemGroup>
<Content Remove="web.config" />
@@ -61,23 +66,28 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.4" />
<PackageReference Include="aliyun-net-sdk-sts" Version="3.1.2" />
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.400.13" />
<PackageReference Include="ConfigMapFileProvider" Version="2.0.1" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.14" />
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
<PackageReference Include="Hangfire.InMemory" Version="0.10.3" />
<PackageReference Include="Hangfire.SqlServer" Version="1.8.14" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="EasyCaching.Interceptor.Castle" Version="1.9.1" />
<PackageReference Include="EasyCaching.Serialization.MessagePack" Version="1.9.1" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageReference Include="EasyCaching.InMemory" Version="1.9.1" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.5" />
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
<PackageReference Include="Hangfire.SqlServer" Version="1.8.5" />
<PackageReference Include="Invio.Extensions.Authentication.JwtBearer" Version="2.0.1" />
<PackageReference Include="LogDashboard" Version="1.4.8" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.8" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.2" />
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.1.1" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.7.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.23" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.1" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.2" />
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.7.0" />
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.7.0" />
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.0.1" />
<PackageReference Include="Serilog.Sinks.Email" Version="2.4.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.5.0" />
</ItemGroup>
<ItemGroup>
@@ -90,6 +100,11 @@
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.Uat_Study.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="wwwroot\EmailTemplate\AdminAddUser_US.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
@@ -150,7 +165,15 @@
<Folder Include="Properties\PublishProfiles\" />
</ItemGroup>
<ProjectExtensions><VisualStudio><UserProperties properties_4launchsettings_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>
<ProjectExtensions><VisualStudio><UserProperties anonymizetagsetting_1json__JsonSchema="http://json.schemastore.org/jovo-language-model" properties_4launchsettings_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>
<ItemGroup>
<None Remove="..\.dockerignore" />
</ItemGroup>
<ItemGroup>
<None Remove="..\.dockerignore" />
</ItemGroup>
</Project>
+10 -120
View File
@@ -16,20 +16,7 @@
医生基本信息 、工作信息 专业信息、审核状态
</summary>
</member>
<member name="M:IRaCIS.Api.Controllers.ExtraController.GetDoctorDetail(IRaCIS.Application.Interfaces.IAttachmentService,IRaCIS.Application.Interfaces.IDoctorService,IRaCIS.Application.Interfaces.IEducationService,IRaCIS.Application.Interfaces.ITrialExperienceService,IRaCIS.Application.Interfaces.IResearchPublicationService,IRaCIS.Application.Interfaces.IVacationService,System.Guid)">
<summary>
获取医生详情
</summary>
<param name="attachmentService"></param>
<param name="_doctorService"></param>
<param name="_educationService"></param>
<param name="_trialExperienceService"></param>
<param name="_researchPublicationService"></param>
<param name="_vacationService"></param>
<param name="doctorId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Api.Controllers.ExtraController.Login(IRaCIS.Application.Contracts.UserLoginDTO,ZiggyCreatures.Caching.Fusion.IFusionCache,IRaCIS.Application.Services.IUserService,IRaCIS.Core.Application.Auth.ITokenService,IRaCIS.Core.Application.Contracts.IReadingImageTaskService,Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.ServiceVerifyConfigOption},IRaCIS.Application.Services.IMailVerificationService)">
<member name="M:IRaCIS.Api.Controllers.ExtraController.Login(IRaCIS.Application.Contracts.UserLoginDTO,EasyCaching.Core.IEasyCachingProvider,IRaCIS.Application.Services.IUserService,IRaCIS.Core.Application.Auth.ITokenService,Microsoft.Extensions.Configuration.IConfiguration)">
<summary> 系统用户登录接口[New] </summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateTrialInspection(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Application.Contracts.TrialCommand})">
@@ -41,49 +28,6 @@
<param name="param"></param>
<returns>新记录Id</returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.WorkLoadAddOrUpdate(IRaCIS.Application.Services.IDoctorWorkloadService,IRaCIS.Application.Contracts.WorkloadCommand)">
<summary>
添加或更新工作量[AUTH]
</summary>
<param name="_trialWorkloadService"></param>
<param name="workLoadAddOrUpdateModel"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateExchangeRate(IRaCIS.Application.Interfaces.IExchangeRateService,IRaCIS.Application.Interfaces.IPaymentAdjustmentService,IRaCIS.Application.Contracts.ExchangeRateCommand)">
<summary>
添加或更新汇率(会触发没有对锁定的费用计算)
</summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateRankPrice(IRaCIS.Application.Interfaces.IReviewerPayInfoService,IRaCIS.Application.Interfaces.IRankPriceService,IRaCIS.Application.Contracts.RankPriceCommand)">
<summary>
添加或更新 职称单价[AUTH]
</summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateReviewerPayInfo(IRaCIS.Application.Interfaces.IReviewerPayInfoService,IRaCIS.Application.Contracts.ReviewerPayInfoCommand)">
<summary>
添加或更新(替换)医生支付展信息[AUTH]
</summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateTrialPaymentPrice(IRaCIS.Application.Interfaces.ITrialPaymentPriceService,IRaCIS.Application.Contracts.TrialPaymentPriceCommand)">
<summary>
保存(替换)项目支付价格信息(会触发没有被锁定的费用计算)[AUTH]
</summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateAwardPriceList(IRaCIS.Application.Interfaces.IVolumeRewardService,System.Collections.Generic.IEnumerable{IRaCIS.Application.Interfaces.AwardPriceCommand})">
<summary>
批量更新奖励费用[AUTH]
</summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.CalculateMonthlyPayment(IRaCIS.Application.Contracts.CalculateDoctorAndMonthDTO)">
<summary>
计算医生月度费用,并将计算的结果存入费用表
</summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.GetMonthlyPaymentList(IRaCIS.Application.Interfaces.IPaymentService,IRaCIS.Application.Interfaces.IExchangeRateService,IRaCIS.Application.Contracts.MonthlyPaymentQueryDTO)">
<summary>
Financials /Monthly Payment 列表查询接口
</summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.GetInspectionList(IRaCIS.Core.Application.Service.Inspection.DTO.GetDataInspectionDto)">
<summary>
获取稽查数据
@@ -167,13 +111,6 @@
<param name="opt"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.SignConsistencyAnalysisReadingClinicalData(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Reading.Dto.SignConsistencyAnalysisReadingClinicalDataInDto})">
<summary>
PM签名一致性分析临床数据
</summary>
<param name="opt"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.SubmitClinicalFormAndSign(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Reading.Dto.SubmitClinicalFormInDto})">
<summary>
提交结构化录入并签名
@@ -215,12 +152,6 @@
</summary>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.ResetAndAsyncCriterion(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Reading.Dto.ResetAndAsyncCriterionInDto})">
<summary>
重置并同步项目阅片标准
</summary>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.CRCRequestToQC(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.CRCRequestToQCCommand})">
<summary>
CRC RequestToQC 批量提交
@@ -278,54 +209,21 @@
<member name="M:IRaCIS.Core.API.Controllers.UploadBaseController.DicomFileUploadAsync(System.Func{System.String,System.IO.Stream,System.Int32,System.Threading.Tasks.Task},System.String)">
<summary> 流式上传 Dicom上传 </summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.StudyController.ArchiveStudyNew(System.Guid,System.Guid,System.String,System.Nullable{System.Guid},System.Guid,Microsoft.Extensions.Logging.ILogger{IRaCIS.Core.API.Controllers.UploadDownLoadController},IRaCIS.Core.Application.Contracts.IStudyService,Microsoft.AspNetCore.SignalR.IHubContext{IRaCIS.Core.API.UploadHub,IRaCIS.Core.API.IUploadClient},IRaCIS.Core.Application.Contracts.Dicom.IDicomArchiveService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.StudyMonitor})">
<member name="M:IRaCIS.Core.API.Controllers.StudyController.ArchiveStudyNew(System.Guid,System.Guid,System.String,System.Nullable{System.Guid},System.Guid,Microsoft.Extensions.Logging.ILogger{IRaCIS.Core.API.Controllers.UploadDownLoadController},EasyCaching.Core.IEasyCachingProvider,IRaCIS.Core.Application.Contracts.IStudyService,Microsoft.AspNetCore.SignalR.IHubContext{IRaCIS.Core.API.UploadHub,IRaCIS.Core.API.IUploadClient},IRaCIS.Core.Application.Contracts.Dicom.IDicomArchiveService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.StudyMonitor})">
<summary>Dicom 归档</summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadNoneDicomFile(IRaCIS.Core.API.Controllers.StudyController.UploadNoneDicomFileCommand,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.StudyMonitor},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudyFile})">
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadNoneDicomFile(IRaCIS.Core.API.Controllers.StudyController.UploadNoneDicomFileCommand,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.StudyMonitor})">
<summary>
上传非Dicom 文件 支持压缩包 多文件上传
</summary>
<param name="incommand"></param>
<param name="_noneDicomStudyRepository"></param>
<param name="_studyMonitorRepository"></param>
<param name="_noneDicomStudyFileRepository"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadVisitCheckExcel(System.Guid,IRaCIS.Core.Application.Helper.IOSSService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.InspectionFile})">
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadVisitCheckExcel(System.Guid,IRaCIS.Core.Application.Helper.IOSSService)">
<summary>
一致性核查 excel上传 支持三种格式
</summary>
<param name="trialId"></param>
<param name="oSSService"></param>
<param name="_inspectionFileRepository"></param>
<returns></returns>
<exception cref="T:IRaCIS.Core.Infrastructure.BusinessValidationFailedException"></exception>
</member>
<member name="T:IRaCIS.Core.API.Controllers.FileController">
<summary>医生文件上传下载</summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.FileController.GetOfficialResume(IRaCIS.Core.API.Controllers.GetDoctorPathCommand,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Attachment})">
<summary>
New 医生首页 多选 获取多个医生信息+文件路径列表 医生压缩包名称 doctorCode + "_" + doctorName _(时间戳或者随机的Guid)
</summary>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.FileController.GetTrialDoctorOfficialResume(IRaCIS.Core.API.Controllers.GetDoctorPathCommand,IRaCIS.Application.Interfaces.IDoctorService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Attachment})">
<summary>
New 项目入组 勾选获取简历路径
</summary>
<param name="command"></param>
<param name="_doctorService"></param>
<param name="_attachmentrepository"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.FileController.GetDoctorAttachment(IRaCIS.Core.API.Controllers.GetDoctoreAttachPathCommand,IRaCIS.Application.Interfaces.IDoctorService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Attachment})">
<summary>
new 医生详情 勾选或者下载文件路径
</summary>
<param name="command"></param>
<param name="_doctorService"></param>
<param name="_attachmentrepository"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.DownloadCommonFile(System.String,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.CommonDocument})">
@@ -348,16 +246,6 @@
IPLimit限流 启动服务
</summary>
</member>
<member name="T:IRaCIS.Core.API.JSONTimeZoneConverter">
<summary>
序列化,反序列化的时候,处理时间 时区转换
</summary>
</member>
<member name="M:IRaCIS.Core.API.JSONTimeZoneConverter.#ctor(Microsoft.AspNetCore.Http.IHttpContextAccessor)">
<summary>
序列化,反序列化的时候,处理时间 时区转换
</summary>
</member>
<member name="M:IRaCIS.Core.API.NullToEmptyStringResolver.CreateProperties(System.Type,Newtonsoft.Json.MemberSerialization)">
<summary>
创建属性
@@ -366,10 +254,12 @@
<param name="memberSerialization">序列化成员</param>
<returns></returns>
</member>
<member name="T:TimeZoneAdjustmentMiddleware">
<summary>
废弃,没用
</summary>
<member name="M:IRaCIS.WX.CoreApi.Auth.AuthMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext)">
<summary>
为了前端 一段时间无操作,需要重新登陆
</summary>
<param name="httpContext"></param>
<returns></returns>
</member>
<member name="T:ZhaoXi._001.NET5Demo.Practice.WebApi.Utility.Jwt.CustomHSJWTService">
<summary>
@@ -1,118 +0,0 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// 废弃,没用
/// </summary>
public class TimeZoneAdjustmentMiddleware
{
private readonly RequestDelegate _next;
public TimeZoneAdjustmentMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if (string.IsNullOrEmpty(context.Request.ContentType))
{
// 请求没有内容体,可能是一个没有请求体的请求,比如 GET 请求
await _next(context);
return;
}
var timeZoneId = "Asia/Shanghai"; // 客户端默认时区
var timeZoneIdHeaderValue = context.Request.Headers["TimeZoneId"];
if (!string.IsNullOrEmpty(timeZoneIdHeaderValue))
{
timeZoneId = timeZoneIdHeaderValue;
}
var timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
// 处理 JSON 请求体中的时间字段
if (context.Request.ContentType.StartsWith("application/json"))
{
var requestBody = await new StreamReader(context.Request.Body).ReadToEndAsync();
// 使用 JSON.NET 或 System.Text.Json 解析 JSON 请求体
// 假设请求体中有一个名为 "dateTime" 的时间字段
dynamic jsonData = JsonConvert.DeserializeObject(requestBody);
if (jsonData.dateTime != null)
{
if (DateTime.TryParse((string)jsonData.dateTime, out DateTime dateTime))
{
// 将 JSON 请求体中的时间字段转换为服务器时区的时间
var serverTime = TimeZoneInfo.ConvertTime(dateTime, timeZone);
jsonData.dateTime = serverTime;
}
}
// 将修改后的 JSON 请求体重新写入请求流中
var jsonBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jsonData));
context.Request.Body = new MemoryStream(jsonBytes);
context.Request.ContentLength = jsonBytes.Length;
}
// 处理 URL 表单参数
var modifiedQuery = new Dictionary<string, StringValues>();
foreach (var key in context.Request.Query.Keys)
{
if (DateTime.TryParse(context.Request.Query[key], out DateTime dateTime))
{
// 将 URL 表单参数中的时间转换为服务器时区的时间
var serverTime = TimeZoneInfo.ConvertTime(dateTime, timeZone);
modifiedQuery[key] = new StringValues(serverTime.ToString());
}
else
{
modifiedQuery[key] = context.Request.Query[key];
}
}
context.Request.Query = new QueryCollection(modifiedQuery);
// 处理Form请求体中的参数
if (context.Request.HasFormContentType)
{
var modifiedForm = new Dictionary<string, StringValues>();
foreach (var key in context.Request.Form.Keys)
{
if (DateTime.TryParse(context.Request.Form[key], out DateTime dateTime))
{
// 将请求体中的时间转换为服务器时区的时间
var serverTime = TimeZoneInfo.ConvertTime(dateTime, timeZone);
modifiedForm[key] = new StringValues(serverTime.ToString());
}
else
{
modifiedForm[key] = context.Request.Form[key];
}
}
var newFormCollection = new FormCollection(modifiedForm);
// 将新的表单集合设置回请求对象
context.Request.Form = newFormCollection;
}
await _next(context);
}
}
+32 -111
View File
@@ -4,6 +4,8 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
using Serilog;
using MediatR;
using IRaCIS.Core.Application.MediatR.Handlers;
using System.Threading.Tasks;
using MassTransit;
using MassTransit.NewIdProviders;
@@ -22,20 +24,12 @@ using IRaCIS.Core.Application.Filter;
using Microsoft.AspNetCore.HttpOverrides;
using IRaCIS.Application.Services.BackGroundJob;
using LogDashboard;
using FellowOakDicom.Network;
using IRaCIS.Core.Application.Service.ImageAndDoc;
using OfficeOpenXml.Utils;
using IP2Region.Net.Abstractions;
using IP2Region.Net.XDB;
using IRaCIS.Core.Application.BusinessFilter;
using Microsoft.AspNetCore.Http;
using IRaCIS.Core.Infrastructure.Extention;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Diagnostics;
using IRaCIS.Core.Application.MassTransit.Command;
using IRaCIS.Core.Application.MassTransit.Consumer;
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
#region
//以配置文件为准,否则 从url中取环境值(服务以命令行传递参数启动,配置文件配置了就不需要传递环境参数)
var config = new ConfigurationBuilder()
@@ -82,8 +76,8 @@ if (urlsIndex > -1)
NewId.SetProcessIdProvider(new CurrentProcessIdProvider());
builder.Configuration.AddJsonFile(ConfigMapFileProvider.FromRelativePath(""), "appsettings.json", false, true)
.AddJsonFile(ConfigMapFileProvider.FromRelativePath(""), $"appsettings.{enviromentName}.json", false, true);
builder.Configuration.AddJsonFile("appsettings.json", false, true)
.AddJsonFile($"appsettings.{enviromentName}.json", false, true);
builder.Host
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
@@ -110,19 +104,19 @@ builder.Services.AddControllers(options =>
options.Filters.Add<ModelActionFilter>();
options.Filters.Add<ProjectExceptionFilter>();
options.Filters.Add<UnitOfWorkFilter>();
options.Filters.Add<EncreptApiResultFilter>(10);
options.Filters.Add<LimitUserRequestAuthorization>();
if (_configuration.GetSection("BasicSystemConfig").GetValue<bool>("OpenLoginLimit"))
{
options.Filters.Add<LimitUserRequestAuthorization>();
}
})
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
.AddNewtonsoftJsonSetup(); // NewtonsoftJson 序列化 处理
builder.Services.AddOptions().Configure<SystemEmailSendConfig>(_configuration.GetSection("SystemEmailSendConfig"));
builder.Services.AddOptions().Configure<ServiceVerifyConfigOption>(_configuration.GetSection("BasicSystemConfig"));
builder.Services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
builder.Services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
builder.Services.AddOptions().Configure<EncreptResponseOption>(_configuration.GetSection("EncrypteResponseConfig"));
builder.Services.AddOptions().Configure<SystemPacsConfig>(_configuration.GetSection("SystemPacsConfig"));
//动态WebApi + UnifiedApiResultFilter 省掉控制器代码
@@ -130,7 +124,7 @@ builder.Services.AddDynamicWebApiSetup();
//AutoMapper
builder.Services.AddAutoMapperSetup();
//EF ORM QueryWithNoLock
builder.Services.AddEFSetup(_configuration,enviromentName);
builder.Services.AddEFSetup(_configuration);
//Http 响应压缩
builder.Services.AddResponseCompressionSetup();
//Swagger Api 文档
@@ -139,34 +133,15 @@ builder.Services.AddSwaggerSetup();
builder.Services.AddJWTAuthSetup(_configuration);
// MediatR 进程内消息 事件解耦 从程序集中 注册命令和handler对应关系
//builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<ConsistencyVerificationHandler>());
#region MassTransit
//masstransit组件 也支持MediatR 中介者模式,但是支持分布式,考虑后续,所以在次替代MediatR
builder.Services.AddMediator(cfg =>
{
cfg.AddConsumer<ConsistencyCheckConsumer>();
});
builder.Services.AddMassTransit(cfg =>
{
cfg.UsingInMemory();
});
#endregion
#region FusionCache
builder.Services.AddFusionCache();
#endregion
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<ConsistencyVerificationHandler>());
// EasyCaching 缓存
//builder.Services.AddEasyCachingSetup(_configuration);
builder.Services.AddEasyCachingSetup(_configuration);
// hangfire 定时任务框架 有界面,更友好~
builder.Services.AddhangfireSetup(_configuration);
//
builder.Services.AddQuartZSetup(_configuration);
//Serilog 日志可视化 LogDashboard日志
builder.Services.AddLogDashboardSetup();
@@ -187,14 +162,12 @@ builder.Services.AddSignalR();
builder.Services.AddSingleton<IUserIdProvider, IRaCISUserIdProvider>();
//builder.Services.AddMemoryCache();
builder.Services.AddSingleton<ISearcher>(new Searcher(CachePolicy.Content, Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources, "ip2region.xdb")));
//builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
//builder.Services.AddProblemDetails();
#region
//builder.Services.AddMemoryCache();
////上传限制 配置
//builder.Services.Configure<FormOptions>(options =>
//{
@@ -208,6 +181,7 @@ builder.Services.AddSingleton<ISearcher>(new Searcher(CachePolicy.Content, Path.
//services.AddAuthorizationPolicySetup(_configuration);
#endregion
builder.Services.AddSingleton<ISearcher>(new Searcher(CachePolicy.Content, Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources, "ip2region.xdb")));
#endregion
var app = builder.Build();
@@ -218,56 +192,6 @@ var env = app.Environment;
// Configure the HTTP request pipeline.
#region 400 -500
//app.UseStatusCodePagesWithReExecute("/Error/{0}");
app.UseStatusCodePages(async context =>
{
var code = context.HttpContext.Response.StatusCode;
context.HttpContext.Response.ContentType = "application/json";
if (code < 500)
{
await context.HttpContext.Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk($"Client error, actual request error status code({code})")));
}
else
{
//ResultFilter 里面的异常并不会到这里
await context.HttpContext.Response.WriteAsync(JsonConvert.SerializeObject((ResponseOutput.NotOk($"Server error , actual request error status code({code})"))));
}
});
//app.UseExceptionHandler(o => { });
//这里没生效,原因未知,官方文档也是这种写法,也用了GlobalExceptionHandler 尝试,还是不行,怀疑框架bug
//app.UseExceptionHandler(configure =>
//{
// configure.Run(async context =>
// {
// var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
//var ex = exceptionHandlerPathFeature?.Error;
//context.Response.ContentType = "application/json";
//if (ex != null)
//{
// var errorInfo = $"Exception: {ex.Message}[{ex.StackTrace}]" + (ex.InnerException != null ? $" InnerException: {ex.InnerException.Message}[{ex.InnerException.StackTrace}]" : "");
// await context.Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk($"{ex?.Message}")));
// Log.Logger.Error(errorInfo);
//}
// });
//});
#endregion
//本地化
app.UseLocalization();
@@ -276,11 +200,12 @@ app.UseForwardedHeaders();
//响应压缩
app.UseResponseCompression();
//app.UseCors(t => t.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
//不需要 token 访问的静态文件 wwwroot css, JavaScript, and images don't require authentication.
app.UseStaticFiles();
//app.UseMiddleware<MultiDiskStaticFilesMiddleware>();
//LogDashboard
app.UseLogDashboard("/LogDashboard");
@@ -288,24 +213,22 @@ app.UseLogDashboard("/LogDashboard");
//hangfire
app.UseHangfireConfig(env);
#region
//app.UseMiddleware<MultiDiskStaticFilesMiddleware>();
////限流 中间件
//app.UseIpRateLimiting();
//if (env.IsDevelopment())
//{
// app.UseDeveloperExceptionPage();
//}
//else
//{
// //app.UseHsts();
//}
#endregion
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
//app.UseHsts();
}
// 特殊异常处理 比如 404
app.UseStatusCodePagesWithReExecute("/Error/{0}");
SwaggerSetup.Configure(app, env);
@@ -338,7 +261,6 @@ var hangfireJobService = app.Services.GetRequiredService<IIRaCISHangfireJob>();
await hangfireJobService.InitHangfireJobTaskAsync();
#endregion
try
@@ -374,7 +296,6 @@ try
//Log.Logger.Warning($"ContentRootPath——GetParent{Directory.GetParent(env.ContentRootPath).Parent.FullName}");
//Log.Logger.Warning($"ContentRootPath——xx{Path.GetDirectoryName(Path.GetDirectoryName(env.ContentRootPath))}");
app.Run();
}
+4 -58
View File
@@ -1,75 +1,21 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:3305",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Test_IRC"
}
},
"IRaCIS.Test_IRC": {
"Test_Study": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Test_IRC"
"ASPNETCORE_ENVIRONMENT": "Test_Study"
},
"applicationUrl": "http://localhost:6100"
},
"IRaCIS.Test_IRC_PGSQL": {
"Uat_Study": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Test_IRC_PGSQL"
},
"applicationUrl": "http://localhost:6100"
},
"IRaCIS.Event_IRC": {
"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": "Uat_Study"
},
"applicationUrl": "http://localhost:6100"
}
}
}
+2 -1
View File
@@ -1,4 +1,5 @@
using IRaCIS.Core.Domain.Share;
using EasyCaching.Core;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.SignalR;
@@ -0,0 +1,66 @@
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Threading.Tasks;
using EasyCaching.Core;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
namespace IRaCIS.WX.CoreApi.Auth
{
public class AuthMiddleware
{
private readonly RequestDelegate _next;
private readonly IEasyCachingProvider _provider;
public AuthMiddleware(RequestDelegate next, IEasyCachingProvider provider)
{
_next = next;
_provider = provider;
}
/// <summary>
///为了前端 一段时间无操作,需要重新登陆
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
public async Task Invoke(HttpContext httpContext)
{
var isLogin = httpContext.Request.Path.ToString().ToLower().Contains("login");
var result = await httpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
if (!isLogin)
{
if (!result.Succeeded)
{
httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
await httpContext.Response.WriteAsync("Unauthorized");
}
else
{
var toekn = result.Properties.Items[".Token.access_token"];
var jwtHandler = new JwtSecurityTokenHandler();
JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(toekn);
object userId;
jwtToken.Payload.TryGetValue("id", out userId);
var cacheValueExist = await _provider.ExistsAsync(userId.ToString()); //Get<string>(userId.ToString()).ToString();
if (!cacheValueExist)
{
httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
await httpContext.Response.WriteAsync("Unauthorized");
}
else
{
await _provider.SetAsync(userId.ToString(), userId.ToString(), TimeSpan.FromMinutes(15));
httpContext.User = result.Principal;
await _next.Invoke(httpContext);
}
}
}
else await _next.Invoke(httpContext);
}
}
}
@@ -0,0 +1,39 @@
using Hangfire.Dashboard;
using System.IdentityModel.Tokens.Jwt;
using System;
using System.Linq;
using IRaCIS.Core.Domain.Share;
namespace IRaCIS.Core.API.Filter
{
//从cookie 中取值
public class hangfireAuthorizationFilter : IDashboardAuthorizationFilter
{
public bool Authorize(DashboardContext context)
{
var httpContext = context.GetHttpContext();
// Allow all authenticated users to see the Dashboard (potentially dangerous).
//return httpContext.User.Identity.IsAuthenticated;
var jwtToken = httpContext.Request.Cookies["access_token"]?.ToString();
var handler = new JwtSecurityTokenHandler();
if (handler.CanReadToken(jwtToken))
{
var jwtSecurityToken = handler.ReadJwtToken(jwtToken);
return jwtSecurityToken.Claims.Any(t => t.Type == JwtIRaCISClaimType.UserTypeEnum && (t.Value == UserTypeEnum.Admin.ToString()|| t.Value== UserTypeEnum.SuperAdmin.ToString()));
}
else
{
return false;
}
}
}
}
@@ -1,17 +0,0 @@
using Hangfire.Dashboard;
namespace IRaCIS.Core.API.Filter
{
public class hangfireAuthorizationFilter : IDashboardAuthorizationFilter
{
public bool Authorize(DashboardContext context)
{
var httpContext = context.GetHttpContext();
// Allow all authenticated users to see the Dashboard (potentially dangerous).
return httpContext.User.Identity.IsAuthenticated;
//return true;
}
}
}
@@ -1,11 +1,8 @@
using Azure;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.FileProviders.Physical;
@@ -14,7 +11,6 @@ using Microsoft.Extensions.Hosting.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.VisualBasic;
using Newtonsoft.Json;
using SharpCompress.Common;
using System.IO;
using System.Linq;
@@ -51,7 +47,7 @@ namespace IRaCIS.Core.API
var path = context.Request.Path.Value;
var isIRacisFile = path.StartsWith($"/{StaticData.Folder.IRaCISDataFolder}");
var isDicomFile = isIRacisFile && path.Contains($"{StaticData.Folder.DicomFolder}");
var isDicomFile = path.Contains($"{StaticData.Folder.DicomFolder}");
@@ -151,12 +147,6 @@ namespace IRaCIS.Core.API
return;
}
}
// 如果没有找到文件,返回404
context.Response.StatusCode = 404;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk("File not found")));
}
@@ -1,5 +1,4 @@
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Localization;
using System.Collections.Generic;
using System.Globalization;
@@ -13,9 +12,8 @@ namespace IRaCIS.Core.API
{
var supportedCultures = new List<CultureInfo>
{
new CultureInfo(StaticData.CultureInfo.en_US),
new CultureInfo(StaticData.CultureInfo.zh_CN)
new CultureInfo("en-US"),
new CultureInfo("zh-CN")
};
var options = new RequestLocalizationOptions
@@ -1,6 +1,4 @@
using Hangfire;
using Hangfire.Dashboard;
using IRaCIS.Core.API._PipelineExtensions.Serilog;
using IRaCIS.Core.API._PipelineExtensions.Serilog;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Serilog;
@@ -20,20 +20,18 @@ namespace IRaCIS.Core.API
// Set all the common properties available for every request
diagnosticContext.Set("Host", request.Host);
diagnosticContext.Set("Protocol", request.Protocol);
diagnosticContext.Set("Scheme", request.Scheme);
#region old
//这种获取的Ip不准 配置服务才行
//diagnosticContext.Set("RequestIP", httpContext.Connection.RemoteIpAddress.ToString());
diagnosticContext.Set("RequestIP", httpContext.Connection.RemoteIpAddress.ToString());
//这种方式可以,但是serilog提供了 就不用了
//diagnosticContext.Set("TestIP", httpContext.GetUserIp());
diagnosticContext.Set("Protocol", request.Protocol);
diagnosticContext.Set("Scheme", request.Scheme);
//这种方式不行 读取的body为空字符串 必须在中间件中读取
//diagnosticContext.Set("RequestBody", await ReadRequestBody(httpContext.Request));
//diagnosticContext.Set("RequestBody", RequestPayload);
#endregion
// Only set it if available. You're not sending sensitive data in a querystring right?!
if (request.QueryString.HasValue)
@@ -16,7 +16,7 @@ namespace IRaCIS.Core.API
public IStringLocalizer _localizer;
public ApiResponseHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
IStringLocalizer localizer,
ILoggerFactory logger, UrlEncoder encoder) : base(options, logger, encoder)
ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
_localizer = localizer;
@@ -1,86 +0,0 @@
using IRaCIS.Core.Application.Auth;
using IRaCIS.Core.Domain.Share;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace IRaCIS.Core.API
{
public static class AuthorizationPolicySetup
{
public static void AddAuthorizationPolicySetup(this IServiceCollection services, IConfiguration configuration)
{
services.AddAuthorization(options =>
{
//影像质控策略 只允许 CRC IQC进行操作
options.AddPolicy(IRaCISPolicy.CRC_IQC, policyBuilder =>
{
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ClinicalResearchCoordinator).ToString(), ((int)UserTypeEnum.IQC).ToString());
});
//一致性核查策略 只允许 CRC PM APM 进行操作
options.AddPolicy(IRaCISPolicy.PM_APM_CRC, policyBuilder =>
{
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString(), ((int)UserTypeEnum.ClinicalResearchCoordinator).ToString(), ((int)UserTypeEnum.APM).ToString());
});
options.AddPolicy(IRaCISPolicy.PM_APM, policyBuilder =>
{
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString(), ((int)UserTypeEnum.APM).ToString());
});
options.AddPolicy(IRaCISPolicy.PM_IQC, policyBuilder =>
{
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString(), ((int)UserTypeEnum.IQC).ToString());
});
options.AddPolicy(IRaCISPolicy.PM, policyBuilder =>
{
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString());
});
options.AddPolicy(IRaCISPolicy.IQC, policyBuilder =>
{
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.IQC).ToString());
});
options.AddPolicy(IRaCISPolicy.CRC, policyBuilder =>
{
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ClinicalResearchCoordinator).ToString());
});
options.AddPolicy(IRaCISPolicy.PM_APM_CRC_QC, policyBuilder =>
{
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString(),((int)UserTypeEnum.ClinicalResearchCoordinator).ToString(), ((int)UserTypeEnum.APM).ToString(), ((int)UserTypeEnum.IQC).ToString());
});
options.AddPolicy(IRaCISPolicy.SPM_CPM, policyBuilder =>
{
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.SPM).ToString(), ((int)UserTypeEnum.CPM).ToString());
});
options.AddPolicy(IRaCISPolicy.PM_APM_SPM_CPM, policyBuilder =>
{
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString(), ((int)UserTypeEnum.APM).ToString(),((int)UserTypeEnum.SPM).ToString(), ((int)UserTypeEnum.CPM).ToString());
});
options.AddPolicy(IRaCISPolicy.PM_APM_SPM_CPM_SMM_CMM, policyBuilder =>
{
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString(), ((int)UserTypeEnum.APM).ToString(), ((int)UserTypeEnum.SPM).ToString(),
((int)UserTypeEnum.CPM).ToString(), ((int)UserTypeEnum.SMM).ToString(), ((int)UserTypeEnum.CMM).ToString());
});
});
}
}
}
@@ -1,6 +1,5 @@
using AutoMapper.EquivalencyExpression;
using IRaCIS.Core.Application.Service;
using IRaCIS.Core.Domain.Models;
using Microsoft.Extensions.DependencyInjection;
namespace IRaCIS.Core.API
@@ -15,15 +14,11 @@ namespace IRaCIS.Core.API
//AutoMapper.Collection.EntityFrameworkCore
automapper.AddCollectionMappers();
// 全局忽略 DomainEvents 属性
automapper.AddGlobalIgnore(nameof(Entity.DomainEvents));
#region 使 IncludeMembers 使
//mapping an EntityFramework Core DbContext-object.
//automapper.UseEntityFrameworkCoreModel<IRaCISDBContext>(services);
//automapper.ForAllMaps((a, b) => b.ForAllMembers(opt => opt.Condition((src, dest, srcMember, desMenber) =>
//{
// //// Can test When Guid? -> Guid if source is null will change to Guid.Empty
@@ -32,7 +27,7 @@ namespace IRaCIS.Core.API
// // not want to map a null Guid? value to db Guid value
//})));
#endregion
}, typeof(QCConfig).Assembly);
@@ -1,4 +1,5 @@
using Autofac;
using Autofac.Extras.DynamicProxy;
using IRaCIS.Core.Application;
using IRaCIS.Core.Application.BackGroundJob;
using IRaCIS.Core.Infra.EFCore;
@@ -9,9 +10,11 @@ using System.Linq;
using System.Reflection;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using MediatR;
using IRaCIS.Application.Services;
using IRaCIS.Application.Interfaces;
using AutoMapper;
using Quartz;
namespace IRaCIS.Core.API
{
@@ -28,6 +31,10 @@ namespace IRaCIS.Core.API
containerBuilder.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
//containerBuilder.RegisterType<Mapper>().As<IMapper>().InstancePerLifetimeScope();
//containerBuilder.RegisterGeneric(typeof(EFUnitOfWork<>))
// .As(typeof(IEFUnitOfWork<>)).InstancePerLifetimeScope();//注册仓储
#endregion
@@ -43,21 +50,30 @@ namespace IRaCIS.Core.API
#endregion
//containerBuilder.RegisterType<BaseService>().As<IBaseService>().PropertiesAutowired().InstancePerLifetimeScope();
//containerBuilder.RegisterType<DictionaryService>().As<IDictionaryService>().InstancePerLifetimeScope();
Assembly application = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "IRaCIS.Core.Application.dll");
containerBuilder.RegisterAssemblyTypes(application).Where(t => t.FullName.Contains("Service"))
.PropertiesAutowired().AsImplementedInterfaces();
.PropertiesAutowired().AsImplementedInterfaces().EnableClassInterceptors();
//Assembly infrastructure = Assembly.Load("IRaCIS.Core.Infra.EFCore");
//containerBuilder.RegisterAssemblyTypes(infrastructure).AsImplementedInterfaces();
containerBuilder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
containerBuilder.RegisterType<UserInfo>().As<IUserInfo>().InstancePerLifetimeScope();
//containerBuilder.RegisterType<Dictionary>().InstancePerLifetimeScope();
//Autofac 注册拦截器 需要注意的是生成api上服务上的动态代理AOP失效 间接掉用不影响
//containerBuilder.RegisterType<TrialStatusAutofacAOP>();
//containerBuilder.RegisterType<UserAddAOP>();
//containerBuilder.RegisterType<QANoticeAOP>();
//containerBuilder.RegisterType<LogService>().As<ILogService>().SingleInstance();
//containerBuilder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
//containerBuilder.RegisterType<UserInfo>().As<IUserInfo>().InstancePerLifetimeScope();
//注册hangfire任务 依赖注入
//注册hangfire任务 依赖注入
containerBuilder.RegisterType<ObtainTaskAutoCancelJob>().As<IObtainTaskAutoCancelJob>().InstancePerDependency();
+7 -52
View File
@@ -1,65 +1,31 @@
using EntityFramework.Exceptions.SqlServer;
using Hangfire.SqlServer;
using Hangfire.SqlServer;
using IRaCIS.Core.Application.Triggers;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Infra.EFCore.Interceptor;
using Medallion.Threading;
using Medallion.Threading.SqlServer;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
namespace IRaCIS.Core.API
{
public static class EFSetup
{
public static void AddEFSetup( this IServiceCollection services, IConfiguration configuration,string envName)
public static void AddEFSetup( this IServiceCollection services, IConfiguration configuration)
{
services.AddHttpContextAccessor();
services.AddScoped<IUserInfo, UserInfo>();
services.AddScoped<ISaveChangesInterceptor, AuditEntityInterceptor>();
services.AddScoped<ISaveChangesInterceptor, DispatchDomainEventsInterceptor>();
// First, register a pooling context factory as a Singleton service, as usual:
//services.AddScoped<DbContext, IRaCISDBContext>();
//这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext
//Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点
services.AddDbContext<IRaCISDBContext>((sp, options) =>
services.AddDbContext<IRaCISDBContext>(options =>
{
// 在控制台
//public static readonly ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });
var logFactory = LoggerFactory.Create(builder => { builder.AddDebug(); });
var dbType = configuration.GetSection("ConnectionStrings:Db_Type").Value ;
if (!string.IsNullOrWhiteSpace(dbType) && dbType == "pgsql")
{
options.UseNpgsql(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
}
else
{
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
}
options.UseLoggerFactory(logFactory);
options.UseExceptionProcessor();
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value,
contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
options.EnableSensitiveDataLogging();
options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor());
options.AddInterceptors(sp.GetServices<ISaveChangesInterceptor>());
options.UseProjectables();
@@ -83,25 +49,14 @@ namespace IRaCIS.Core.API
triggerOptions.AddTrigger<TableQuestionRowTrigger>();
//triggerOptions.AddTrigger<AddlTrialUserTrigger>();
triggerOptions.AddTrigger<VisitTaskIsFrontTaskNeedSignButNotSignTrigger>();
triggerOptions.AddTrigger<VisitTaskIbeforeTrigger>();
triggerOptions.AddTrigger<VisitTaskIAfterSignTrigger>();
triggerOptions.AddTrigger<UserLogTrigger>();
});
});
// Register an additional context factory as a Scoped service, which gets a pooled context from the Singleton factory we registered above,
//services.AddScoped<IRaCISDBScopedFactory>();
//// Finally, arrange for a context to get injected from our Scoped factory:
//services.AddScoped(sp => sp.GetRequiredService<IRaCISDBScopedFactory>().CreateDbContext());
//注意区分 easy caching 也有 IDistributedLockProvider
services.AddSingleton<IDistributedLockProvider>(sp =>
{
@@ -1,24 +1,27 @@
using Microsoft.Extensions.Configuration;
using EasyCaching.Core;
using EasyCaching.Core.Configurations;
using EasyCaching.Interceptor.Castle;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace IRaCIS.Core.API
{
public static class EasyCachingSetup
public static class EasyCachingSetup
{
public static void AddEasyCachingSetup(this IServiceCollection services, IConfiguration configuration)
{
//services.AddEasyCaching(options =>
//{
// options.UseInMemory();
services.AddEasyCaching(options =>
{
options.UseInMemory();
// //options.UseRedis(configuration, EasyCachingConstValue.DefaultRedisName).WithMessagePack(EasyCachingConstValue.DefaultRedisName);
//options.UseRedis(configuration, EasyCachingConstValue.DefaultRedisName).WithMessagePack(EasyCachingConstValue.DefaultRedisName);
});
//});
//services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultRedisName);
////services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultRedisName);
//services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultInMemoryName);
services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultInMemoryName);
}
}
}
@@ -13,12 +13,14 @@ namespace IRaCIS.Core.API
services.AddLogDashboard(opt =>
{
//opt.PathMatch = "/api/LogDashboard";
opt.PathMatch = "/LogDashboard";
opt.PathMatch = "/back/logs";
//opt.AddAuthorizationFilter(new LogDashboardBasicAuthFilter("admin", "zhizhun2018"));
//opt.AddAuthorizationFilter(new LogDashBoardAuthFilter());
});
}
@@ -0,0 +1,81 @@
//using System;
//using Microsoft.Extensions.DependencyInjection;
//using StackExchange.Profiling.Storage;
//namespace IRaCIS.Core.API
//{
// public class MiniProfilerConfigure
// {
// public static void ConfigureMiniProfiler(IServiceCollection services)
// {
// services.AddMiniProfiler(options =>
// {
// // All of this is optional. You can simply call .AddMiniProfiler() for all defaults
// // (Optional) Path to use for profiler URLs, default is /mini-profiler-resources
// options.RouteBasePath = "/profiler";
// //// (Optional) Control storage
// //// (default is 30 minutes in MemoryCacheStorage)
// (options.Storage as MemoryCacheStorage).CacheDuration = TimeSpan.FromMinutes(10);
// //// (Optional) Control which SQL formatter to use, InlineFormatter is the default
// //options.SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter();
// //// (Optional) To control authorization, you can use the Func<HttpRequest, bool> options:
// //// (default is everyone can access profilers)
// //options.ResultsAuthorize = request => MyGetUserFunction(request).CanSeeMiniProfiler;
// //options.ResultsListAuthorize = request => MyGetUserFunction(request).CanSeeMiniProfiler;
// //// Or, there are async versions available:
// //options.ResultsAuthorizeAsync = async request => (await MyGetUserFunctionAsync(request)).CanSeeMiniProfiler;
// //options.ResultsAuthorizeListAsync = async request => (await MyGetUserFunctionAsync(request)).CanSeeMiniProfilerLists;
// //// (Optional) To control which requests are profiled, use the Func<HttpRequest, bool> option:
// //// (default is everything should be profiled)
// //options.ShouldProfile = request => MyShouldThisBeProfiledFunction(request);
// //// (Optional) Profiles are stored under a user ID, function to get it:
// //// (default is null, since above methods don't use it by default)
// //options.UserIdProvider = request => MyGetUserIdFunction(request);
// //// (Optional) Swap out the entire profiler provider, if you want
// //// (default handles async and works fine for almost all applications)
// //options.ProfilerProvider = new MyProfilerProvider();
// //// (Optional) You can disable "Connection Open()", "Connection Close()" (and async variant) tracking.
// //// (defaults to true, and connection opening/closing is tracked)
// //options.TrackConnectionOpenClose = true;
// //// (Optional) Use something other than the "light" color scheme.
// //// (defaults to "light")
// //options.ColorScheme = StackExchange.Profiling.ColorScheme.Auto;
// //// The below are newer options, available in .NET Core 3.0 and above:
// //// (Optional) You can disable MVC filter profiling
// //// (defaults to true, and filters are profiled)
// //options.EnableMvcFilterProfiling = true;
// //// ...or only save filters that take over a certain millisecond duration (including their children)
// //// (defaults to null, and all filters are profiled)
// //// options.MvcFilterMinimumSaveMs = 1.0m;
// //// (Optional) You can disable MVC view profiling
// //// (defaults to true, and views are profiled)
// //options.EnableMvcViewProfiling = true;
// //// ...or only save views that take over a certain millisecond duration (including their children)
// //// (defaults to null, and all views are profiled)
// //// options.MvcViewMinimumSaveMs = 1.0m;
// //// (Optional) listen to any errors that occur within MiniProfiler itself
// //// options.OnInternalError = e => MyExceptionLogger(e);
// //// (Optional - not recommended) You can enable a heavy debug mode with stacks and tooltips when using memory storage
// //// It has a lot of overhead vs. normal profiling and should only be used with that in mind
// //// (defaults to false, debug/heavy mode is off)
// ////options.EnableDebugMode = true;
// });
// //.AddEntityFramework();
// }
// }
//}
@@ -0,0 +1,46 @@
using IRaCIS.Core.Domain.Share;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
namespace IRaCIS.Core.API
{
public class JSONCustomDateConverter : DateTimeConverterBase
{
private TimeZoneInfo _timeZoneInfo;
private string _dateFormat;
private IUserInfo _userInfo;
public JSONCustomDateConverter(string dateFormat, TimeZoneInfo timeZoneInfo, IUserInfo userInfo)
{
_dateFormat = dateFormat;
_timeZoneInfo = timeZoneInfo;
_userInfo = userInfo;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var timeZoneId = _userInfo.TimeZoneId;
var needConvertUtcDateTime = Convert.ToDateTime(value);
var tz = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
var dateTimeOffset = new DateTimeOffset(needConvertUtcDateTime);
var time = TimeZoneInfo.ConvertTimeFromUtc(needConvertUtcDateTime, tz).ToString(_dateFormat);
writer.WriteValue(time);
writer.Flush();
}
}
}
@@ -1,126 +0,0 @@
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using StackExchange.Redis;
using System;
using System.Globalization;
namespace IRaCIS.Core.API
{
/// <summary>
/// 序列化,反序列化的时候,处理时间 时区转换
/// </summary>
public class JSONTimeZoneConverter(IHttpContextAccessor _httpContextAccessor) : DateTimeConverterBase
{
private TimeZoneInfo _clientTimeZone;
private string _dateFormat;
public override bool CanConvert(Type objectType)
{
#region
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
if (!isEn_US)
{
// Chinese date format
_dateFormat = "yyyy-MM-dd HH:mm:ss";
}
else
{
// Default or English date format
_dateFormat = "MM/dd/yyyy HH:mm:ss";
}
#endregion
#region
//var timeZoneId = "Etc/UTC";
var timeZoneId = "Asia/Shanghai";
var timeZoneIdHeader = _httpContextAccessor?.HttpContext?.Request?.Headers["TimeZoneId"];
if (timeZoneIdHeader is not null && !string.IsNullOrEmpty(timeZoneIdHeader.Value))
{
timeZoneId = timeZoneIdHeader.Value;
}
_clientTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
#endregion
// 仅支持 DateTime 类型的转换
return objectType == typeof(DateTime)|| objectType == typeof(DateTime?);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.Value == null)
{
return null;
}
DateTime dateTime;
if (reader.ValueType == typeof(DateTime) || reader.ValueType == typeof(DateTime?))
{
DateTime? nullableDateTime = reader.Value as DateTime?;
if (nullableDateTime != null && nullableDateTime.HasValue)
{
dateTime = nullableDateTime.Value;
}
else
{
return null;
}
}
else
{
if (DateTime.TryParse((string)reader.Value, out dateTime) == false)
{
return null;
}
}
// 将客户端时间转换为服务器时区的时间
var serverZoneTime = TimeZoneInfo.ConvertTime(dateTime, _clientTimeZone, TimeZoneInfo.Local);
return serverZoneTime;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
DateTime? nullableDateTime = value as DateTime?;
if (nullableDateTime != null && nullableDateTime.HasValue)
{
//第一个参数默认使用系统本地时区 也就是应用服务器的时区
DateTime clientZoneTime = TimeZoneInfo.ConvertTime(nullableDateTime.Value, _clientTimeZone);
//writer.WriteValue(clientZoneTime);
writer.WriteValue(clientZoneTime.ToString(_dateFormat));
}
else
{
writer.WriteNull();
}
}
}
}
@@ -1,99 +0,0 @@
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Globalization;
using System.Reflection;
namespace IRaCIS.Core.API
{
//public class CustomContractResolver : DefaultContractResolver
//{
// protected override JsonContract CreateContract(Type objectType)
// {
// var contract = base.CreateContract(objectType);
// // 检查类是否有 LowercaseJsonAttribute 标记
// if (objectType.GetCustomAttribute<LowerCamelCaseJsonAttribute>() != null)
// {
// contract.NamingStrategy = new IRCCamelCaseNamingStrategy();
// }
// return contract;
// }
//}
#region
public class MyDateTimeConverter : JsonConverter<DateTime>
{
public override DateTime ReadJson(JsonReader reader, Type objectType, DateTime existingValue, bool hasExistingValue, JsonSerializer serializer)
{
return reader.ReadAsDateTime().Value;
}
public override void WriteJson(JsonWriter writer, DateTime value, JsonSerializer serializer)
{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
string dateFormat;
if (!isEn_US)
{
// Chinese date format
dateFormat = "yyyy-MM-dd HH:mm:ss";
}
else
{
// Default or English date format
dateFormat = "MM/dd/yyyy HH:mm:ss";
}
writer.WriteValue(value.ToString(dateFormat));
}
}
public class MyNullableDateTimeConverter : JsonConverter<DateTime?>
{
public override DateTime? ReadJson(JsonReader reader, Type objectType, DateTime? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var val = reader.ReadAsDateTime();
return val;
}
public override void WriteJson(JsonWriter writer, DateTime? value, JsonSerializer serializer)
{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
string dateFormat;
if (!isEn_US)
{
// Chinese date format
dateFormat = "yyyy-MM-dd HH:mm:ss";
}
else
{
// Default or English date format
dateFormat = "MM/dd/yyyy HH:mm:ss";
}
if (value.HasValue)
{
writer.WriteValue(value.Value.ToString(dateFormat));
}
else
{
writer.WriteValue(default(DateTime?));
}
}
}
#endregion
}
@@ -1,60 +1,32 @@
using IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Globalization;
using System.Text.Json;
using Newtonsoft.Json.Serialization;
namespace IRaCIS.Core.API
{
public static class NewtonsoftJsonSetup
{
public static void AddNewtonsoftJsonSetup(this IMvcBuilder builder, IServiceCollection services)
public static void AddNewtonsoftJsonSetup(this IMvcBuilder builder)
{
services.AddHttpContextAccessor();
services.AddScoped<JSONTimeZoneConverter>();
services.AddScoped<ObjectStorePathConvert>();
services.AddScoped<IOSSService, OSSService>();
builder.AddNewtonsoftJson(options =>
{
//大驼峰
//options.SerializerSettings.ContractResolver = new DefaultContractResolver();
//小驼峰
//options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
//options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
// 忽略循环引用
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
//options.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
//处理返回给前端 可空类型 给出默认值 比如in? 为null 设置 默认值0
options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver();
options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver(); //new DefaultContractResolver();// new NullToEmptyStringResolver();
// 设置时间格式
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
// 设置时间格式 isEn_US? "MM/dd/yyyy HH:mm:ss" :
//options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
//二者只能取其一
//options.SerializerSettings.Converters.Add(new MyDateTimeConverter());
//options.SerializerSettings.Converters.Add(new MyNullableDateTimeConverter());
//必须放在后面
options.SerializerSettings.Converters.Add(services.BuildServiceProvider().GetService<JSONTimeZoneConverter>());
//options.SerializerSettings.Converters.Add(new JSONCustomDateConverter()) ;
//IsoDateTimeConverter
//options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
})
.AddControllersAsServices()//动态webApi属性注入需要
@@ -1,10 +1,8 @@
using IRaCIS.Core.Infrastructure.NewtonsoftJson;
using Newtonsoft.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace IRaCIS.Core.API
{
@@ -32,20 +30,8 @@ namespace IRaCIS.Core.API
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
// 检查类是否有 LowerCamelCaseJsonAttribute 标记 有的话,属性名小写
if (type.GetCustomAttribute<LowerCamelCaseJsonAttribute>() != null)
{
base.NamingStrategy= new LowerCamelCaseNamingStrategy();
}
else
{
base.NamingStrategy = null;
}
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
var list= type.GetProperties()
.Select(p =>
{
@@ -28,7 +28,7 @@ namespace IRaCIS.Core.API
if(_MemberInfo.PropertyType == typeof(string))
{
//去掉前后空格
_MemberInfo.SetValue(target, value==null?string.Empty: value.ToString()==string.Empty? value:value/*.ToString().Trim()*/);
_MemberInfo.SetValue(target, value==null?string.Empty: value.ToString()==string.Empty? value:value.ToString().Trim());
}
else
@@ -1,63 +0,0 @@
using IRaCIS.Core.Application.Helper;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson
{
public class ObjectStorePathConvert : JsonConverter<string>
{
private readonly IOSSService _oSSService;
// 构造函数
public ObjectStorePathConvert( IOSSService oSSService)
{
_oSSService = oSSService;
}
public override string ReadJson(JsonReader reader, Type objectType, string existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.String)
{
return (string)reader.Value;
}
return null;
}
public override void WriteJson(JsonWriter writer, string value, JsonSerializer serializer)
{
if (value != null)
{
// 在这里对字符串进行处理,例如转换大小写、去除空格等
// 这里只是一个示例,您可以根据实际需求进行更改
// 获取当前正在序列化的属性名
string propertyName = writer.Path.Split('.').Last();
Regex guidRegex = new Regex(@"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}");
if (propertyName.IndexOf("Path") > -1 && value.IndexOf('.')>-1 && guidRegex.IsMatch(value))
{
var tt= _oSSService.GetSignedUrl(value);
writer.WriteValue(tt);
}
else
{
// 将处理后的字符串写入到 JsonWriter 中
writer.WriteValue(value);
}
}
else
{
writer.WriteNull();
}
}
}
}
@@ -0,0 +1,49 @@
using IRaCIS.Application.Services.BackGroundJob;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Quartz;
namespace IRaCIS.Core.API
{
public static class QuartZSetup
{
public static void AddQuartZSetup(this IServiceCollection services, IConfiguration configuration)
{
services.AddTransient<CancelTaskQuartZJob>();
services.AddQuartz(q =>
{
// base quartz scheduler, job and trigger configuration
// as of 3.3.2 this also injects scoped services (like EF DbContext) without problems
q.UseMicrosoftDependencyInjectionJobFactory();
// 基本Quartz调度器、作业和触发器配置
//var jobKey = new JobKey("RegularTrialWork", "regularWorkGroup");
//q.AddJob<CacheTrialStatusQuartZJob>(jobKey, j => j
// .WithDescription("Trial regular work")
//);
//q.AddTrigger(t => t
// .WithIdentity("TrialStatusTrigger")
// .ForJob(jobKey)
// .WithCronSchedule("0 0 * * * ?")
// .WithDescription("My regular trial work trigger")
//);
});
// ASP.NET Core hosting
services.AddQuartzHostedService(options =>
{
// when shutting down we want jobs to complete gracefully
options.WaitForJobsToComplete = true;
});
}
}
}
@@ -1,30 +1,18 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.Extensions.DependencyInjection;
using System.IO.Compression;
namespace IRaCIS.Core.API
{
public static class ResponseCompressionSetup
public static class ResponseCompressionSetup
{
public static void AddResponseCompressionSetup(this IServiceCollection services)
{
services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add<BrotliCompressionProvider>();
options.Providers.Add<GzipCompressionProvider>();
});
services.Configure<BrotliCompressionProviderOptions>(options =>
{
options.Level = CompressionLevel.Optimal;
});
services.Configure<GzipCompressionProviderOptions>(options =>
{
options.Level = CompressionLevel.Optimal;
});
}
}
}
@@ -31,13 +31,13 @@ namespace IRaCIS.Core.API
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("LocalIP", httpContext.Connection.LocalIpAddress.MapToIPv4().ToString()));
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserRealName", httpContext?.User?.FindFirst(ClaimAttributes.RealName)?.Value));
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserType", httpContext?.User?.FindFirst(JwtIRaCISClaimType.UserTypeShortName)?.Value));
//这样读取没用
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestBody", await ReadRequestBody(httpContext.Request)));
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestIP", IPHelper.GetIP(httpContext.Request) ));
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserRealName", httpContext?.User?.FindFirst(ClaimAttributes.RealName)?.Value));
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserType", httpContext?.User?.FindFirst(JwtIRaCISClaimType.UserTypeShortName)?.Value));
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Referer", httpContext.Request.Headers["Referer"].ToString()));
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("request_path", httpContext.Request.Path));
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("request_method", httpContext.Request.Method));
@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Builder;
using Serilog;
using Serilog.Events;
//using Serilog.Sinks.Email;
using Serilog.Sinks.Email;
using System;
using System.Net;
@@ -19,11 +19,11 @@ namespace IRaCIS.Core.API
// Filter out ASP.NET Core infrastructre logs that are Information and below 日志太多了 一个请求 记录好几条
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
.MinimumLevel.Override("Hangfire", LogEventLevel.Warning)
.MinimumLevel.Override("System.Net.Http.HttpClient.HttpReports", LogEventLevel.Warning)
.MinimumLevel.Override("System.Net.Http.HttpClient.HttpReports", LogEventLevel.Warning)
.Enrich.WithClientIp()
.Enrich.FromLogContext()
.Filter.ByExcluding(logEvent =>logEvent.Properties.ContainsKey("RequestPath") && logEvent.Properties["RequestPath"].ToString().Contains("/health"))
.Enrich.FromLogContext()
//控制台 方便调试 问题 我们显示记录日志 时 获取上下文的ip 和用户名 用户类型
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Warning,
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext:l} || {Message} || {Exception} ||end {NewLine}")
@@ -3,7 +3,6 @@ using Hangfire.SqlServer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Runtime.InteropServices;
namespace IRaCIS.Core.API
{
@@ -15,29 +14,19 @@ namespace IRaCIS.Core.API
services.AddHangfire(hangFireConfig =>
{
//本地window 调试 使用内存,服务器部署使用数据库,防止服务器任务调度到本地
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
//hangFireConfig.UseInMemoryStorage();
//指定存储介质
hangFireConfig.UseSqlServerStorage(hangFireConnStr, new SqlServerStorageOptions()
{
hangFireConfig.UseInMemoryStorage();
}
else
{
//指定存储介质
hangFireConfig.UseSqlServerStorage(hangFireConnStr, new SqlServerStorageOptions()
{
SchemaName = "dbo",
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
DisableGlobalLocks = true
});
}
SchemaName = "dbo",
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
DisableGlobalLocks = true
});
//hangFireConfig.UseTagsWithSql(); //nuget引入Hangfire.Tags.SqlServer
//.UseHangfireHttpJob();
@@ -46,7 +35,7 @@ namespace IRaCIS.Core.API
services.AddHangfireServer(option =>
{
option.Queues = new[] { "immediately_once", "default", "sys_init", "not_immediately_once" };
option.Queues = new[] { "immediately_once","default","sys_init" , "not_immediately_once" };
});
}
-77
View File
@@ -1,77 +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": "LTAI5tKvzs7ed3UfSpNk3xwQ",
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
"bucketName": "zy-irc-store",
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
"viewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
"region": "oss-cn-shanghai"
},
"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": "展影医疗"
},
"SystemPacsConfig": {
"Port": "11113",
"IP": "101.132.193.237"
}
}
@@ -6,23 +6,19 @@
"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": "LTAI5tKvzs7ed3UfSpNk3xwQ",
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
"bucketName": "zy-irc-store",
"bucketName": "zy-sir-store",
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
"viewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
"viewEndpoint": "https://zy-sir-cache.oss-cn-shanghai.aliyuncs.com",
"region": "oss-cn-shanghai"
},
"MinIO": {
"endpoint": "http://192.168.3.68",
"port": "8001",
@@ -33,38 +29,35 @@
}
},
"ConnectionStrings": {
//"RemoteNew": "Server=47.117.165.18,1434;Database=Prod_Study;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
//"Hangfire": "Server=47.117.165.18,1434;Database=Prod_Study_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
"RemoteNew": "Server=prod_mssql_standard,1433;Database=Prod_Study;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
"Hangfire": "Server=prod_mssql_standard,1433;Database=Prod_Study_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
},
"BasicSystemConfig": {
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": true,
"OpenTrialRelationDelete": true,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 60,
"LoginFailLockMinutes": 30
"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": "展影医疗"
"FromEmail": "study@extimaging.com",
"FromName": "研究单位阅片系统",
"AuthorizationCode": "zhanying123",
"SiteUrl": "https://study.extimaging.com/login"
}
}
-98
View File
@@ -1,98 +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": "AliyunOSS",
"AliyunOSS": {
"RegionId": "cn-shanghai",
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
"AccessKeyId": "LTAI5tJV76pYX5yPg1N9QVE8",
"AccessKeySecret": "roRNLa9YG1of4pYruJGCNKBXEWTAWa",
"BucketName": "zy-irc-test-store",
"RoleArn": "acs:ram::1899121822495495:role/webdirect",
"ViewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
"Region": "oss-cn-shanghai",
"DurationSeconds": 7200
},
"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": {
"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": 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"
}
}
@@ -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"
}
}
@@ -10,24 +10,23 @@
"ObjectStoreUse": "AliyunOSS",
"AliyunOSS": {
"regionId": "cn-shanghai",
"internalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
"endPoint": "https://oss-cn-shanghai.aliyuncs.com",
"endpoint": "https://oss-cn-shanghai.aliyuncs.com",
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
"bucketName": "zy-irc-test-store",
"bucketName": "zy-sir-test-store",
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
"viewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
"viewEndpoint": "https://zy-sir-test-store.oss-cn-shanghai.aliyuncs.com",
"region": "oss-cn-shanghai"
},
"MinIO": {
"endPoint": "106.14.89.110",
"endPoint": "123.56.94.154",
"port": "9001",
"useSSL": false,
"useSSL": true,
"accessKey": "fbStsVYCIPKHQneeqMwD",
"secretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
"bucketName": "hir-test",
"viewEndpoint": "http://106.14.89.110:9001/hir-test/"
"bucketName": "study-test",
"viewEndpoint": "http://study.test.extimaging.com/oss/study-test"
},
"AWS": {
@@ -41,8 +40,8 @@
},
"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"
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_Study;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=106.14.89.110,1435;Database=Test_Study_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"BasicSystemConfig": {
@@ -67,14 +66,6 @@
"AuthorizationCode": "zhanying123",
"SiteUrl": "http://study.test.extimaging.com/login"
},
"DicomSCPServiceConfig": {
"CalledAEList": [
"STORESCP",
"Value1",
"Value2",
"Value3"
],
"ServerPort": 11112
}
}
@@ -1,88 +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",
"AliyunOSS": {
"regionId": "cn-shanghai",
"internalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
"endPoint": "https://oss-cn-shanghai.aliyuncs.com",
"accessKeyId": "",
"accessKeySecret": "",
"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": "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": {
"endPoint": "s3.us-east-1.amazonaws.com",
"useSSL": true,
"accessKey": "AKIAW3MEAFJX5P32P6NA",
"secretKey": "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",
"bucketName": "ei-med-s3-lili-store",
"viewEndpoint": "https://ei-med-s3-lili-store.s3.amazonaws.com/"
}
},
"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"
}
}
@@ -1,94 +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": "MinIO",
"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.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": {
"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": 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.test.elevateimaging.ai/login"
}
}
@@ -1,88 +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": {
"endPoint": "s3.us-east-1.amazonaws.com",
"useSSL": true,
"accessKey": "AKIAW3MEAFJXUO6XYFYN",
"secretKey": "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",
"bucketName": "ei-med-s3-lili-uat-store",
"viewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com/"
}
},
"BasicSystemConfig": {
"OpenUserComplexPassword": false,
"OpenSignDocumentBeforeWork": false,
"OpenTrialRelationDelete": true,
"OpenLoginLimit": false,
"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"
}
}
-85
View File
@@ -1,85 +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": "LTAI5tKvzs7ed3UfSpNk3xwQ",
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
"bucketName": "zy-irc-uat-store",
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
"viewEndpoint": "https://zy-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
"region": "oss-cn-shanghai"
},
"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"
}
},
"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": "展影医疗"
},
"SystemPacsConfig": {
"Port": "11113",
"IP": "47.117.164.182"
}
}
@@ -10,28 +10,27 @@
"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-uat-store",
"bucketName": "zy-sir-uat-store",
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
"viewEndpoint": "https://zy-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
"viewEndpoint": "https://zy-sir-uat-store.oss-cn-shanghai.aliyuncs.com",
"region": "oss-cn-shanghai"
},
"AWS": {
"endPoint": "s3.us-east-1.amazonaws.com",
"MinIO": {
"endpoint": "http://192.168.3.68",
"port": "8001",
"useSSL": false,
"accessKey": "AKIAZQ3DRSOHFPJJ6FEU",
"secretKey": "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",
"bucketName": "ei-irc-test-store",
"viewEndpoint": "https://ei-irc-test-store.s3.amazonaws.com/"
"accessKey": "IDFkwEpWej0b4DtiuThL",
"secretKey": "Lhuu83yMhVwu7c1SnjvGY6lq74jzpYqifK6Qtj4h",
"bucketName": "test"
}
},
"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"
"RemoteNew": "Server=47.117.164.182,1434;Database=Uat.Study;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=47.117.164.182,1434;Database=Uat.Study.hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"BasicSystemConfig": {
@@ -45,6 +44,7 @@
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30
},
"SystemEmailSendConfig": {
@@ -54,14 +54,6 @@
"FromName": "Uat_Study",
"AuthorizationCode": "zhanying123",
"SiteUrl": "http://study.uat.extimaging.com/login"
},
"DicomSCPServiceConfig": {
"CalledAEList": [
"STORESCP",
"Value1",
"Value2",
"Value3"
],
"ServerPort": 11112
}
}
+6 -10
View File
@@ -1,10 +1,11 @@
{
"JwtSetting": {
"SecurityKey": "ShangHaiZhanYing_SecurityKey_SHzyyl@2021",
"Issuer": "Extimaging",
"Audience": "EICS",
"SecurityKey": "3e6dbfa227234a03977a2f421bdb7f4f",
"Issuer": "IRaCIS",
"Audience": "ZhiZhun",
"TokenExpireDays": "7"
},
//ip
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
@@ -19,6 +20,7 @@
"EndpointWhitelist": [
"post:/study/archivestudy/*"
],
"IpWhitelist": [],
"GeneralRules": [
{
@@ -90,13 +92,7 @@
"DicomStudyCodePrefix": "ST",
"SystemSiteCodePrefix": "S",
"DefaultPassword": "123456",
"DefaultInternalOrganizationName": "ExtImaging",
"ImageShareExpireDays": 10
},
"EncrypteResponseConfig": {
"IsEnable": true,
"ApiPathList": [
"/test/get"
]
}
}
Binary file not shown.
@@ -11,7 +11,7 @@
尊敬的 {0} ,您好:
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{company abbreviation}为您添加了账户,账户信息如下:
展影医疗为您添加了账户,账户信息如下:
</div>
<span style="color: #00D1B2"></span>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
@@ -23,7 +23,7 @@
</div>
<div>
首次登陆前,请通过该链接修改您的账户信息:
<a href='{3}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
<a href='{3}' style='margin-left:30px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
初始化账号信息
</a>
</div>
@@ -32,7 +32,7 @@
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>祝您顺利!</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 14px;">展影医疗</div>
</div>
</div>
</div>
@@ -4,17 +4,17 @@
<meta charset='UTF-8'>
<title>Title</title>
</head>
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
<div style='padding-left: 40px;background: #f6f6f6'>
<body style='font-family: Times New Roman;padding: 0;margin: 0;'>
<div style='padding-left: 40px;background: #f6f6f6;font-size: 16px'>
<div style='padding-top: 20px;'>
<div style='line-height: 40px;font-size: 18px'>
<div style='line-height: 40px;font-size: 16px'>
Dear {0} ,
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{company abbreviation} has created an account for you. The account information is as follows:
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
Extensive Imaging has generated a user account for you. <br>The account information is as follows:
</div>
<span style="color: #00D1B2"></span>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;font-size: 16px'>
<div>
User ID: {1}
</div>
@@ -22,17 +22,17 @@
Role: {2}
</div>
<div>
Before logging in for the first time, please modify the account information through this link
<a href='{3}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
Initialize account information
Before logging in for the first time, please initialize your account information through this link:
<a href='{3}' style='margin-left:30px;font-size:12px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;font-size: 16px'>
Initialize Account Information
</a>
</div>
</div>
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div style='line-height: 24px;font-size: 16px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>Best regards,</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 16px;">Extensive Imaging</div>
</div>
</div>
</div>
@@ -11,7 +11,7 @@
尊敬的 {0} ,您好:
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{company abbreviation}将您的账户密码已重置,账户信息如下:
展影医疗将您的账户密码已重置,账户信息如下:
</div>
<span style="color: #00D1B2"></span>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
@@ -29,7 +29,7 @@
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>祝您顺利!</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 14px;">展影医疗</div>
</div>
</div>
</div>
@@ -4,17 +4,17 @@
<meta charset='UTF-8'>
<title>Title</title>
</head>
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
<div style='padding-left: 40px;background: #f6f6f6'>
<body style='font-family: Times New Roman;padding: 0;margin: 0;'>
<div style='padding-left: 40px;background: #f6f6f6;font-size: 16px'>
<div style='padding-top: 20px;'>
<div style='line-height: 40px;font-size: 18px'>
<div style='line-height: 40px;font-size: 16px'>
Dear {0} ,
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{company abbreviation} has reset your account password, and the account information is as follows:
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
Extensive Imaging has reset your password.<br>The account information is as follows:
</div>
<span style="color: #00D1B2"></span>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 12px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;font-size: 16px'>
<div>
User ID: {1}
</div>
@@ -27,9 +27,9 @@
</div>
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div style='line-height: 24px;font-size: 16px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>Best regards,</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 16px;">Extensive Imaging</div>
</div>
</div>
</div>
@@ -19,7 +19,7 @@
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>祝您顺利!</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 14px;">展影医疗</div>
</div>
</div>
</div>
@@ -4,22 +4,22 @@
<meta charset='UTF-8'>
<title>Title</title>
</head>
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
<div style='padding-left: 40px;background: #f6f6f6'>
<body style='font-family: Times New Roman;padding: 0;margin: 0;font-size: 16px'>
<div style='padding-left: 40px;background: #f6f6f6;font-size: 16px'>
<div style='padding-top: 20px;'>
<div style='line-height: 40px;font-size: 18px'>
Dear
<div style='line-height: 40px;font-size: 16px'>
Dear Sir or Madam:
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
Thank you for using {company abbreviation} Cloud System.
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
Thank you for using our IRC imaging system.
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{0}
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
{0}.
</div>
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div style='line-height: 24px;font-size: 16px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>Best regards,</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 16px;">Extensive Imaging</div>
</div>
</div>
</div>
@@ -11,7 +11,7 @@
尊敬的 {0} ,您好:
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{company abbreviation}作为 [{1} (试验方案号:{2 })] 项目的供应商,诚邀您参加该项目阅片相关工作。
展影医疗作为 [{1} (试验方案号:{2 })] 项目的供应商,诚邀您参加该项目阅片相关工作。
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
该项目采用电子化工作流,系统及您的账号信息如下:
@@ -35,7 +35,7 @@
</div>
<div>
系统登录地址:
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
<a href='{6}' style='margin-left:30px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
点击跳转
</a>
</div>
@@ -43,7 +43,7 @@
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>祝您顺利!</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 14px;">展影医疗</div>
</div>
</div>
</div>
@@ -4,20 +4,20 @@
<meta charset='UTF-8'>
<title>Title</title>
</head>
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
<body style='font-family: Times New Roman;padding: 0;margin: 0;'>
<div style='padding-left: 40px;background: #f6f6f6'>
<div style='padding-top: 20px;'>
<div style='line-height: 40px;font-size: 18px'>
<div style='line-height: 40px;font-size: 16px'>
Dear {0},
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
{company abbreviation} invites you to participate in the IRC work of a trial ({1} , {2}).
As the service provider of {1} trialProtocol ID is {2}, Extensive Imaging invites you to participate in the independent assessment work of this trial.
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
Your account information is as follows
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
Digital workflow is implemented for this trial, and your account information is as follows:
</div>
<span style="color: #00D1B2"></span>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;font-size: 16px'>
<div>
Trial ID: {3}
</div>
@@ -28,23 +28,22 @@
Study Name: {1}
</div>
<div>
User ID: {4}
User Name: {4}
</div>
<div>
Role: {5}
</div>
<div>
Login URL:
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
Click to login
Login URL:
<a href='{6}' style='margin-left:30px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
click redirect
</a>
</div>
</div>
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div style='line-height: 24px;font-size: 16px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>Best regards,</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 16px;">Extensive Imaging</div>
</div>
</div>
</div>
@@ -11,7 +11,7 @@
尊敬的 {0} ,您好:
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{company abbreviation}作为 [{1} (试验方案号:{2 })] 项目的IRC供应商,诚邀您参加该项目IRC阅片相关工作,欢迎您提供指导和建议,非常感谢!
展影医疗作为 [{1} (试验方案号:{2 })] 项目的供应商,诚邀您参加该项目阅片相关工作,欢迎您提供指导和建议,非常感谢!
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
该项目采用电子化工作流,系统及您的账号信息如下:
@@ -35,7 +35,7 @@
</div>
<div>
首次登陆前,请通过该链接修改您的账户信息:
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
<a href='{6}' style='margin-left:30px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
初始化账号信息
</a>
</div>
@@ -44,7 +44,7 @@
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>祝您顺利!</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 14px;">展影医疗</div>
</div>
</div>
</div>
@@ -4,20 +4,21 @@
<meta charset='UTF-8'>
<title>Title</title>
</head>
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
<body style='font-family: Times New Roman;padding: 0;margin: 0;'>
<div style='padding-left: 40px;background: #f6f6f6'>
<div style='padding-top: 20px;'>
<div style='line-height: 40px;font-size: 18px'>
<div style='line-height: 40px;font-size: 16px'>
Dear {0},
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{company abbreviation} invites you to participate in the IRC work of a trial ({1}, {2}).
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
As the service provider of {1}trial (Protocol ID is {2}), Extensive Imaging invites you to participate in the independent assessment work of this trial.
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
Your account information is as follows
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
Digital workflow is implemented for this trial, and your account information is as follows:
</div>
<span style="color: #00D1B2"></span>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;font-size: 16px'>
<div>
Trial ID: {3}
</div>
@@ -34,17 +35,17 @@
Role: {5}
</div>
<div>
Before logging in for the first time, please modify the account information through this link
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
Initialize account information
Before logging in for the first time, please modify your account information through this link:
<a href='{6}' style='margin-left:30px;font-size:16px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
Initialize Account Information
</a>
</div>
</div>
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;font-size: 16px'>
<div>Best regards,</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 16px;">Extensive Imaging</div>
</div>
</div>
</div>
@@ -11,7 +11,7 @@
尊敬的 {0} ,您好:
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
您填写的中心调研表被驳回,详细信息如下:
好, 您填写的中心调研表被驳回,详细信息如下:
</div>
<span style="color: #00D1B2"></span>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
@@ -41,7 +41,7 @@
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>祝您顺利!</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 14px;">展影医疗</div>
</div>
</div>
</div>
@@ -4,17 +4,17 @@
<meta charset='UTF-8'>
<title>Title</title>
</head>
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
<div style='padding-left: 40px;background: #f6f6f6'>
<div style='padding-top: 20px;'>
<div style='line-height: 40px;font-size: 18px'>
Dear {0} ,
<body style='font-family: Times New Roman;padding: 0;margin: 0;font-size: 16px'>
<div style='padding-left: 40px;background: #f6f6f6;font-size: 16px'>
<div style='padding-top: 20px;font-size: 16px'>
<div style='line-height: 40px;font-size: 16px'>
Dear {0} ,
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
The site survey form you filled in has been rejected. The details are as follows
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
The site survey questionnaire you filled in has been rejected. Details are as follows:
</div>
<span style="color: #00D1B2"></span>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;font-size: 16px'>
<div>
Trial ID: {1}
</div>
@@ -28,20 +28,20 @@
Site ID: {4}
</div>
<div>
Site name: {5}
Site Name: {5}
</div>
<div>
Reason for rejection: {6}
</div>
</div>
<a href='{7}' style='margin-left:60px;font-size:14px;padding: 10px;text-decoration: none;display:{8} ;height: 40px;width: 140px;background: #00D1B2;color:#fff;border-radius: 5px;line-height: 40px;text-align: center;margin-bottom: 100px;'>
Login and view
<a href='{7}' style='margin-left:60px;font-size:16px;padding: 10px;text-decoration: none;display:{8} ;height: 40px;width: 140px;background: #00D1B2;color:#fff;border-radius: 5px;line-height: 40px;text-align: center;margin-bottom: 100px;font-size: 16px'>
Login & View
</a>
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div style='line-height: 24px;font-size: 16px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>Best regards,</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 16px;">Extensive Imaging</div>
</div>
</div>
</div>
@@ -11,7 +11,7 @@
尊敬的 {0} ,您好:
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{company abbreviation}作为 [{1} (试验方案号:{2 })] 项目的供应商,诚邀您参加该项目相关工作,欢迎您提供指导和建议,非常感谢!
展影医疗作为 [{1} (试验方案号:{2 })] 项目的供应商,诚邀您参加该项目相关工作,欢迎您提供指导和建议,非常感谢!
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
该项目采用电子化工作流,系统及您的账号信息如下:
@@ -35,7 +35,7 @@
</div>
<div>
系统登录地址:
<a href='{6}' style='margin-left:5px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
<a href='{6}' style='margin-left:30px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
点击跳转
</a>
</div>
@@ -44,7 +44,7 @@
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>祝您顺利!</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 14px;">展影医疗</div>
</div>
</div>
</div>
@@ -4,20 +4,20 @@
<meta charset='UTF-8'>
<title>Title</title>
</head>
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
<div style='padding-left: 40px;background: #f6f6f6'>
<div style='padding-top: 20px;'>
<div style='line-height: 40px;font-size: 18px'>
<body style='font-family: Times New Roman;padding: 0;margin: 0;font-size: 16px'>
<div style='padding-left: 40px;background: #f6f6f6;font-size: 16px'>
<div style='padding-top: 20px;font-size: 16px'>
<div style='line-height: 40px;font-size: 16px'>
Dear {0},
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
{company abbreviation} invites you to participate in the IRC work of a trial ({1}, {2}).
As the service provider of {1} trial (Protocol ID is {2}), Extensive Imaging invites you to participate in related work of this trial.
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
Your account information is as follows
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
Digital workflow is implemented for this trial, and your account information is as follows:
</div>
<span style="color: #00D1B2"></span>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;font-size: 16px'>
<div>
Trial ID: {3}
</div>
@@ -28,23 +28,23 @@
Study Name: {1}
</div>
<div>
User ID: {4}
User Name: {4}
</div>
<div>
Role: {5}
</div>
<div>
Login URL:
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
Click to login
Login URL:
<a href='{6}' style='margin-left:30px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
click redirect
</a>
</div>
</div>
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div style='line-height: 24px;font-size: 16px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>Best regards,</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 16px;">Extensive Imaging</div>
</div>
</div>
</div>
@@ -11,7 +11,7 @@
尊敬的 {0} ,您好:
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{company abbreviation}作为 [{1} (试验方案号:{2 })] 项目的IRC供应商,诚邀您参加该项目IRC相关工作,欢迎您提供指导和建议,非常感谢!
展影医疗作为 [{1} (试验方案号:{2 })] 项目的供应商,诚邀您参加该项目相关工作
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
该项目采用电子化工作流,系统及您的账号信息如下:
@@ -35,7 +35,7 @@
</div>
<div>
首次登陆前,请通过该链接修改您的账户信息:
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
<a href='{6}' style='margin-left:30px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
初始化账号信息
</a>
</div>
@@ -44,7 +44,7 @@
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>祝您顺利!</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 14px;">展影医疗</div>
</div>
</div>
</div>
@@ -4,20 +4,20 @@
<meta charset='UTF-8'>
<title>Title</title>
</head>
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
<body style='font-family: Times New Roman;padding: 0;margin: 0;font-size: 16px'>
<div style='padding-left: 40px;background: #f6f6f6'>
<div style='padding-top: 20px;'>
<div style='line-height: 40px;font-size: 18px'>
<div style='line-height: 40px;font-size: 16px'>
Dear {0},
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{company abbreviation} invites you to participate in the IRC work of a trial ({1}, {2}).
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
As the service provider of {1} trial (Protocol ID is {2}), Extensive Imaging invites you to participate in related work of this trial.
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
Your account information is as follows
Digital workflow is implemented for this trial, and your account information is as follows:
</div>
<span style="color: #00D1B2"></span>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;font-size: 16px'>
<div>
Trial ID: {3}
</div>
@@ -28,23 +28,23 @@
Study Name: {1}
</div>
<div>
User ID: {4}
User Name: {4}
</div>
<div>
Role: {5}
</div>
<div>
Before logging in for the first time, please modify the account information through this link
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
Initialize the account information
Before logging in for the first time, please modify your account information through this link:
<a href='{6}' style='margin-left:30px;font-size:16px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
Initialize Account Information
</a>
</div>
</div>
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div style='line-height: 24px;font-size: 16px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>Best regards,</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 16px;">Extensive Imaging</div>
</div>
</div>
</div>
@@ -8,20 +8,18 @@
<div style='padding-left: 40px;background: #f6f6f6'>
<div style='padding-top: 20px;'>
<div style='line-height: 40px;font-size: 18px'>
{0}您好,
Hello {0},
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
感谢您使用展影云平台。
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{1},验证码是: <span style="font-weight:bold">{2}</span>
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
请在3分钟内输入该验证码,进行后续操作
{1},验证码是: {2},请在3分钟内输入该验证码,进行后续操作。如非本人操作,请忽略该邮件
</div>
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>祝您顺利!</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 14px;">展影医疗</div>
</div>
</div>
</div>
@@ -4,25 +4,25 @@
<meta charset='UTF-8'>
<title>Title</title>
</head>
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
<body style='font-family: Times New Roman;padding: 0;margin: 0;'>
<div style='padding-left: 40px;background: #f6f6f6'>
<div style='padding-top: 20px;'>
<div style='line-height: 40px;font-size: 18px'>
Dear {0},
<div style='line-height: 40px;font-size: 16px'>
Hello {0},
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
{1}
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
Thank you for using our imaging system.
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
The verification code is <span style="font-weight:bold">{2}</span>.
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
{1}, the verification code is {2}. Please enter this code within 3 minutes for follow-up operations.
</div>
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
This code will expire in 3 minutes.
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
If you are not the intended person, please ignore this email.
</div>
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;font-size: 16px'>
<div>Best regards,</div>
<div style="font-size: 14px;">{company}</div>
<div style="font-size: 16px;">Extensive Imaging</div>
</div>
</div>
</div>
@@ -276,10 +276,8 @@ var abp = abp || {};
}
var password = document.getElementById('password').value;
var pwdMd5 = document.getElementById('pwdMd5').value;
console.log(pwdMd5);
if (!password && !pwdMd5) {
alert('PassWord And Md5 Can Not Be Null');
if (!password) {
alert('PassWord Can Not Be Null');
return false;
}
@@ -323,9 +321,6 @@ var abp = abp || {};
UserName: usernameOrEmailAddress,
Password: hex_md5(password),
}
if (pwdMd5 != '') {
parm.Password = pwdMd5;
}
xhr.send(JSON.stringify(parm));
//xhr.send("{" + "userName:'" + usernameOrEmailAddress + "'," + "passWord:'" + password + "'}");
@@ -420,8 +415,7 @@ var abp = abp || {};
//Inputs
createInput(modalUxContent, 'tenancyName', 'Tenancy Name (Leave empty for Host)');
createInput(modalUxContent, 'userName', 'Username or email address','text','cyldev');
createInput(modalUxContent, 'password', 'Password', 'password', '123456');
createInput(modalUxContent, 'pwdMd5', 'PwdMd5', 'text', '');
createInput(modalUxContent, 'password', 'Password','password','123456');
//Buttons
var authBtnWrapper = document.createElement('div');
@@ -0,0 +1,73 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using EasyCaching.Core;
using IRaCIS.Core.Domain;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using Microsoft.Extensions.Logging;
using Quartz;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Application.Contracts;
namespace IRaCIS.Application.Services.BackGroundJob
{
public class CancelTaskQuartZJob : IJob
{
private readonly IRepository<Subject> _subjectRepository;
private readonly ILogger<CancelTaskQuartZJob> _logger;
private readonly IRepository<VisitTask> _visitTaskRepository;
public CancelTaskQuartZJob(IRepository<Subject> subjectRepository, IEasyCachingProvider provider, ILogger<CancelTaskQuartZJob> logger, IRepository<VisitTask> visitTaskRepository)
{
_subjectRepository = subjectRepository;
_logger = logger;
_visitTaskRepository = visitTaskRepository;
}
public async Task Execute(IJobExecutionContext context)
{
_logger.LogInformation($"开始执行QuartZ定时取消任务作业");
try
{
JobDataMap dataMap = context.JobDetail.JobDataMap;
bool isInOrder = (bool)dataMap.Get("IsInOrder");
if (isInOrder)
{
Guid subjectId = (Guid)dataMap.Get("SubjectId");
Guid trialReadingCriterionId = (Guid)dataMap.Get("TrialReadingCriterionId");
await _visitTaskRepository.BatchUpdateNoTrackingAsync(t => t.SubjectId == subjectId && t.TrialReadingCriterionId==trialReadingCriterionId, u => new VisitTask() { SubjectCriterionClaimUserId = null });
}
else
{
Guid id = (Guid)dataMap.Get("VisitTaskId");
await _visitTaskRepository.UpdatePartialFromQueryAsync(t => t.Id == id && t.ReadingTaskState!=ReadingTaskState.HaveSigned, u => new VisitTask() { DoctorUserId = null }, true);
}
}
catch (Exception e)
{
_logger.LogError($"QuartZ定时取消任务异常" + e.Message);
}
_logger.LogInformation("QuartZ定时取消任务作业结束");
}
}
}
@@ -1,14 +1,14 @@
using Hangfire;
using EasyCaching.Core;
using Hangfire;
using Hangfire.Storage;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Service;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using SharpCompress.Common;
using ZiggyCreatures.Caching.Fusion;
namespace IRaCIS.Application.Services.BackGroundJob
{
@@ -16,50 +16,143 @@ namespace IRaCIS.Application.Services.BackGroundJob
public interface IIRaCISHangfireJob
{
//Task MemoryCacheTrialStatusAsync();
Task MemoryCacheTrialStatusAsync();
Task InitHangfireJobTaskAsync();
}
public class IRaCISCHangfireJob(ILogger<IRaCISCHangfireJob> _logger,
IRepository<Internationalization> _internationalizationRepository,
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository
) : IIRaCISHangfireJob
public class IRaCISCHangfireJob : IIRaCISHangfireJob
{
public static string JsonFileFolder = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources);
private readonly IRepository<Trial> _trialRepository;
private readonly IEasyCachingProvider _provider;
private readonly ILogger<IRaCISCHangfireJob> _logger;
private readonly IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository;
private readonly IRepository<Internationalization> _internationalizationRepository;
public IRaCISCHangfireJob(IRepository<Trial> trialRepository, ILogger<IRaCISCHangfireJob> logger, IEasyCachingProvider provider, IRepository<TrialEmailNoticeConfig> trialEmailNoticeConfigRepository, IRepository<Internationalization> internationalizationRepository)
{
_trialRepository = trialRepository;
_provider = provider;
_logger = logger;
_trialEmailNoticeConfigRepository = trialEmailNoticeConfigRepository;
_internationalizationRepository = internationalizationRepository;
}
public async Task InitHangfireJobTaskAsync()
{
_logger.LogInformation("项目启动 hangfire 任务初始化 执行开始~");
//初始化国际化
await InternationalizationHelper.InitInternationlizationDataAndWatchJsonFileAsync(_internationalizationRepository);
//项目状态 立即加载到缓存中
await MemoryCacheTrialStatusAsync();
//创建项目缓存 定时任务
HangfireJobHelper.AddOrUpdateInitCronJob<IIRaCISHangfireJob>("RecurringJob_Cache_TrialState", t => t.MemoryCacheTrialStatusAsync(), Cron.Daily());
//初始化
await InitInternationlizationDataAndWatchJsonFileAsync();
//创建邮件定时任务
await InitSysAndTrialCronJobAsync();
#region
////项目状态 立即加载到缓存中
//await MemoryCacheTrialStatusAsync();
////await MemoryCacheAnonymizeData();
////创建项目缓存 定时任务
//HangfireJobHelper.AddOrUpdateInitCronJob<IIRaCISHangfireJob>("RecurringJob_Cache_TrialState", t => t.MemoryCacheTrialStatusAsync(), Cron.Daily());
#endregion
_logger.LogInformation("项目启动 hangfire 任务初始化 执行结束");
}
/// <summary>
/// 缓存项目状态
/// </summary>
/// <returns></returns>
public async Task MemoryCacheTrialStatusAsync()
{
var list = await _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
.ToListAsync();
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
}
#region
public async Task InitInternationlizationDataAndWatchJsonFileAsync()
{
//查询数据库的数据
var toJsonList = await _internationalizationRepository.Where(t => t.InternationalizationType == 1).Select(t => new
{
t.Code,
t.Value,
t.ValueCN
}).ToListAsync();
//组织成json 文件
var usJsonPath = Path.Combine(JsonFileFolder, StaticData.En_US_Json);
var cnJsonPath = Path.Combine(JsonFileFolder, StaticData.Zh_CN_Json);
//本地静态文件国际化需要
foreach (var tojsonItem in toJsonList)
{
StaticData.En_US_Dic[tojsonItem.Code] = tojsonItem.Value;
StaticData.Zh_CN_Dic[tojsonItem.Code] = tojsonItem.ValueCN;
}
File.WriteAllText(usJsonPath, JsonConvert.SerializeObject(StaticData.En_US_Dic));
File.WriteAllText(cnJsonPath, JsonConvert.SerializeObject(StaticData.Zh_CN_Dic));
//监测Json文件变更 实时刷新数据
WatchJsonFile(usJsonPath);
WatchJsonFile(cnJsonPath);
}
public void WatchJsonFile(string filePath)
{
if (!File.Exists(filePath))
{
throw new BusinessValidationFailedException(StaticData.International("IRaCISCHangfireJob_FileNotFound"));
}
FileSystemWatcher watcher = new FileSystemWatcher(Path.GetDirectoryName(filePath), Path.GetFileName(filePath));
watcher.Changed += (sender, e) => LoadJsonFile(filePath);
watcher.EnableRaisingEvents = true;
}
private void LoadJsonFile(string filePath)
{
IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile(filePath);
IConfigurationRoot enConfiguration = builder.Build();
foreach (IConfigurationSection section in enConfiguration.GetChildren())
{
if (filePath.Contains(StaticData.En_US_Json))
{
StaticData.En_US_Dic[section.Key] = section.Value;
}
else
{
StaticData.Zh_CN_Dic[section.Key] = section.Value;
}
}
}
#endregion
public async Task InitSysAndTrialCronJobAsync()
{
@@ -101,9 +194,6 @@ namespace IRaCIS.Application.Services.BackGroundJob
}
}
+13 -15
View File
@@ -8,8 +8,6 @@ using Panda.DynamicWebApi;
using Panda.DynamicWebApi.Attributes;
using System.Diagnostics.CodeAnalysis;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Mvc;
using ZiggyCreatures.Caching.Fusion;
namespace IRaCIS.Core.Application
{
@@ -19,21 +17,20 @@ namespace IRaCIS.Core.Application
#region
[TypeFilter(typeof(UnifiedApiResultFilter))]
[Authorize, DynamicWebApi]
[Authorize, DynamicWebApi, UnifiedApiResultFilter]
public class BaseService : IBaseService, IDynamicWebApi
{
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
public IRepository _repository { get; set; }
public IStringLocalizer _localizer { get; set; }
public IWebHostEnvironment _hostEnvironment { get; set; }
public IFusionCache _fusionCache { get; set; }
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
@@ -52,6 +49,8 @@ namespace IRaCIS.Core.Application
[MemberNotNull(nameof(_userInfo))]
public IUserInfo _userInfo { get; set; }
[MemberNotNull(nameof(_repository))]
public IRepository _repository { get; set; }
[MemberNotNull(nameof(_localizer))]
public IStringLocalizer _localizer { get; set; }
@@ -59,9 +58,6 @@ namespace IRaCIS.Core.Application
[MemberNotNull(nameof(_hostEnvironment))]
public IWebHostEnvironment _hostEnvironment { get; set; }
[MemberNotNull(nameof(_fusionCache))]
public IFusionCache _fusionCache { get; set; }
}
#endregion
@@ -77,25 +73,27 @@ namespace IRaCIS.Core.Application
[MemberNotNull(nameof(_userInfo))]
public IUserInfo _userInfo { get; set; }
[MemberNotNull(nameof(_repository))]
public IRepository _repository { get; set; }
[MemberNotNull(nameof(_localizer))]
public IStringLocalizer _localizer { get; set; }
[MemberNotNull(nameof(_fusionCache))]
public IFusionCache _fusionCache { get; set; }
}
[TypeFilter(typeof(UnifiedApiResultFilter))]
[Authorize, DynamicWebApi]
[Authorize, DynamicWebApi, UnifiedApiResultFilter]
public class BaseServiceTest<T> : IBaseServiceTest<T>, IDynamicWebApi where T : Entity
{
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
public IStringLocalizer _localizer { get; set; }
public IRepository _repository { get; set; }
public IFusionCache _fusionCache { get; set; }
public IStringLocalizer _localizer { get; set; }
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
{

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