Compare commits
722 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 775704c509 | |||
| 96776b0b3d | |||
| 4e277bb9aa | |||
| d269131510 | |||
| bddfc633f4 | |||
| c72f50c1f7 | |||
| 5a27fbc127 | |||
| c8d181e557 | |||
| 3fdfb3cc4b | |||
| c91b645539 | |||
| 19bd2d145a | |||
| 7d81cb72ee | |||
| 49554ae764 | |||
| 9b0cde11c6 | |||
| a7c462210c | |||
| 4f83944a30 | |||
| 8801308002 | |||
| 56e109ce0a | |||
| 8c6b73c236 | |||
| 04f971e24f | |||
| 88c1bf7e76 | |||
| 02aebab5ea | |||
| 80378a23f7 | |||
| b3976783df | |||
| 4c11dd203c | |||
| cdc0822677 | |||
| fe209ee2c5 | |||
| a595ca10fe | |||
| 0fdbb5dde0 | |||
| e488ba5edd | |||
| 3a7961ded5 | |||
| 0db495a38a | |||
| 1b1a18bac8 | |||
| fee5cd7a75 | |||
| 3473a96014 | |||
| 88036f9355 | |||
| fdb9b825f8 | |||
| 3f85962584 | |||
| f52c5b5185 | |||
| 7452eae07f | |||
| cb712c181a | |||
| 41c5686ac9 | |||
| de500f28cd | |||
| 1dce9f7255 | |||
| 49346bc025 | |||
| e2d19c5738 | |||
| 5cab834978 | |||
| da7727c4b2 | |||
| 5111168349 | |||
| 07dc87d859 | |||
| 7e6c41a3ff | |||
| e3daf3af26 | |||
| 6af18aa977 | |||
| 179017fa2c | |||
| af691d155d | |||
| 4c5a40bd11 | |||
| ccb7d5edc0 | |||
| 972b18e4df | |||
| c290515e22 | |||
| 8ad11f018b | |||
| 78597d6866 | |||
| 274a8d2c21 | |||
| 4b9a277335 | |||
| 4d8b43f8df | |||
| 6a9f791b1b | |||
| f75c2d7283 | |||
| 88ded12f37 | |||
| 72d7136f1c | |||
| b95cc97f55 | |||
| 7fa043793e | |||
| 0cb2015aae | |||
| 7b5b7e4ffa | |||
| 7fed7072c1 | |||
| 6e5e49d322 | |||
| 8609c34fd7 | |||
| 596c46d885 | |||
| 790d751c1f | |||
| f3cc7be5d7 | |||
| 0ee3010e04 | |||
| c7d4159302 | |||
| 3ee81beb80 | |||
| db586038cf | |||
| 4240015056 | |||
| 37b942f0a6 | |||
| 87dcebd00b | |||
| 40fd641210 | |||
| 2f701246ff | |||
| 88a8a014c9 | |||
| fe7c6e5dfa | |||
| a6f055bb1a | |||
| 18d58951a2 | |||
| 54f1f917eb | |||
| a0fd472e2e | |||
| fb33acd827 | |||
| 9c3e72b1bb | |||
| 57515b2ecf | |||
| 9f060c900f | |||
| c804bdb5a1 | |||
| 48aafdc713 | |||
| 67b2d95c32 | |||
| ee3133adee | |||
| a1b5d960ff | |||
| df7eaf6986 | |||
| efd24ab9ba | |||
| bd9d1a6298 | |||
| 345189995e | |||
| 6dcdfe4d23 | |||
| 2addbe30dd | |||
| d2e3e4de86 | |||
| d78a42dead | |||
| 93362ea4c9 | |||
| 1033ff665c | |||
| f8478887ce | |||
| 763984ca62 | |||
| efbaae2a97 | |||
| 49e4980fd0 | |||
| b2bcc37dab | |||
| 32ee818be8 | |||
| d042be7828 | |||
| 2017d781bf | |||
| fccf6686eb | |||
| 88f40125e1 | |||
| facb318180 | |||
| 62352738e8 | |||
| a22b7802b7 | |||
| 6aaeeeaeb9 | |||
| 7b606aee05 | |||
| 841f1892d4 | |||
| 106916f7ad | |||
| 46ab1fc7bc | |||
| 3328c18279 | |||
| aed778bbc6 | |||
| 064e3836ca | |||
| 3407f2f00d | |||
| e496cf1117 | |||
| e5f6685719 | |||
| 837a3f66d5 | |||
| 0201c2f50f | |||
| a7ed38f03b | |||
| a436571364 | |||
| 34e6e1583e | |||
| 400504db74 | |||
| 88e7febec5 | |||
| 02a49b2239 | |||
| d72b28afc2 | |||
| 2ba9e6e2d4 | |||
| 1d38ee3f49 | |||
| 9879625781 | |||
| a0f5e7b7e5 | |||
| 337d0fa05f | |||
| 5d3df0b1f5 | |||
| dd4cd5d330 | |||
| 3c28be9bf0 | |||
| 6e75404175 | |||
| 5b08640a02 | |||
| 9b3e4194a9 | |||
| c4eabde7a9 | |||
| 66e5570d82 | |||
| d1be23a69e | |||
| 0ef8604da0 | |||
| 05124428ad | |||
| 17ce41209f | |||
| a1afbc2487 | |||
| 3f6e006a95 | |||
| 380546ca3c | |||
| e4cf4cc8b8 | |||
| ed580eab74 | |||
| 2530843931 | |||
| c4b588376d | |||
| e63d6ba652 | |||
| 64ef4ea0f2 | |||
| b293559225 | |||
| 7214626850 | |||
| a4ef209fb1 | |||
| e4cc044219 | |||
| db6c0457ae | |||
| e745271671 | |||
| 34686b10cc | |||
| 711c4c5888 | |||
| 3d19ee7b04 | |||
| 72fd347c01 | |||
| 4c1da73c33 | |||
| 2b01c777a7 | |||
| d1ae500735 | |||
| 214ea985d9 | |||
| 95fe063706 | |||
| b6ceca9744 | |||
| 42e9c58d7a | |||
| 8356fff9ce | |||
| e6f91b9c4b | |||
| ba9c88d836 | |||
| 237260dbd0 | |||
| 5a2136f205 | |||
| f9d69995d3 | |||
| 32d78f556c | |||
| d11afb10de | |||
| 67e7eaaa96 | |||
| af95166782 | |||
| 29093e5617 | |||
| b68c00c1b4 | |||
| 2d06b12368 | |||
| 0f7b80ff63 | |||
| 96c8b5d7f8 | |||
| 4ec15c2333 | |||
| 11d5722f46 | |||
| a079451951 | |||
| eb7db8478f | |||
| 444d5c8005 | |||
| d97edf6688 | |||
| 359a6bf602 | |||
| bab20666af | |||
| 05244cdaf7 | |||
| ef1b76f98c | |||
| f887699341 | |||
| 6b97d1ce68 | |||
| 334e51d9fd | |||
| 8b43474734 | |||
| 149cca011a | |||
| aa63ca2def | |||
| 9dcb63bdf2 | |||
| 323534e52b | |||
| b432002266 | |||
| e03884227e | |||
| 0580b11e39 | |||
| 90a3021938 | |||
| bc3f5c9394 | |||
| 9e3eafa925 | |||
| 98f0e9e1a1 | |||
| b66b3fcc6c | |||
| 608f6387ae | |||
| 4f7e73c990 | |||
| 8baa8b7421 | |||
| bb38899cee | |||
| 64f04a3953 | |||
| 38a42dc44f | |||
| 4c396dc4ae | |||
| e17d973fad | |||
| 1efe15a776 | |||
| d7f87f77ab | |||
| 7eff5fd1bb | |||
| 2fe3441c3f | |||
| 98741d9a3b | |||
| 9386b89110 | |||
| 32ca60156e | |||
| b2022a912f | |||
| ffedc3f378 | |||
| 6d042459e3 | |||
| 0a5164682f | |||
| 62037c0d43 | |||
| ec45d80b9b | |||
| 4187673b7a | |||
| ad62ad7ae0 | |||
| 87709f0122 | |||
| 5ade2135ee | |||
| f0a38ebec9 | |||
| 15b50e39f1 | |||
| 5f71d7f1b2 | |||
| f4f94f1f48 | |||
| 21cafcab53 | |||
| c37903b2f4 | |||
| 1fc70b1340 | |||
| 36844c291a | |||
| 9b96259e59 | |||
| 4c3a96a0f6 | |||
| 154c12eb93 | |||
| c09f27bf7d | |||
| f80ac02562 | |||
| f49d2ce06b | |||
| eff5920568 | |||
| 05be768188 | |||
| c9387463ba | |||
| b230139f67 | |||
| d833093c33 | |||
| c62fb1df92 | |||
| 8c1a25aae3 | |||
| 758e0aedcb | |||
| 563be56d27 | |||
| db2bd6b725 | |||
| 81d9fcae2e | |||
| ea87692f49 | |||
| cee9d92a72 | |||
| bbe89ade16 | |||
| 16e348a996 | |||
| b6e3032767 | |||
| 690c759fa1 | |||
| 56a15f3b61 | |||
| 589e9868a8 | |||
| 82afae93dc | |||
| 6875cf3188 | |||
| 076d99c6ba | |||
| 79d39125ff | |||
| aafc1cd064 | |||
| 26e7305bcf | |||
| d1e08b0fc0 | |||
| df87c56544 | |||
| a3b69d45ae | |||
| ef95cdd4ec | |||
| 4d7d42753f | |||
| 9e9db251c8 | |||
| 8b1626e292 | |||
| a5a2dcdac9 | |||
| 93ea0cf8d1 | |||
| b91ea2c176 | |||
| 75be9eba74 | |||
| 335535d6d3 | |||
| 8b61b288fc | |||
| f08a5b0d46 | |||
| 7bc3378e0c | |||
| b87e531920 | |||
| d5234db48a | |||
| 7f6933df35 | |||
| 70bff24348 | |||
| a8a1198c52 | |||
| bd83153743 | |||
| deeffe034b | |||
| 39f579c10b | |||
| 77eac6c1d0 | |||
| 5cc192b317 | |||
| ba12a2977b | |||
| 1a7576039b | |||
| 780f6451c3 | |||
| b576478eea | |||
| 8cbc5c5c26 | |||
| 0245aaf7ad | |||
| d954d13f81 | |||
| c9e12993a6 | |||
| 088a0b6fd5 | |||
| 6b18e5eced | |||
| 5673fcad5f | |||
| 697ac6f57b | |||
| e9b3b012f9 | |||
| d5d3d6e1c9 | |||
| 712d87a4dd | |||
| f082217e99 | |||
| 16e5a0567f | |||
| 5fa12786aa | |||
| 4350aa6459 | |||
| 897dd2118d | |||
| f84a9c481a | |||
| 3cb0ed4cd5 | |||
| e346bfc527 | |||
| 831ae8a591 | |||
| b359508ab4 | |||
| 7750b1ba12 | |||
| f5f4639cc8 | |||
| 32e659c26b | |||
| 2f69df7a83 | |||
| ff0662867e | |||
| 3ee9703dca | |||
| 217df5dc2f | |||
| 7fe61af141 | |||
| a37a77949a | |||
| eb885cc568 | |||
| c78a96eed0 | |||
| f8b23604c2 | |||
| 26d60857bf | |||
| 4c9b3e1a23 | |||
| 5526a2dd53 | |||
| f69ad1b4e3 | |||
| b869693d63 | |||
| 6f8f6000ba | |||
| ed5f8e8d9c | |||
| 550cdff28f | |||
| 6e363601a6 | |||
| 6a63ffd1f2 | |||
| 03c8cdd1d2 | |||
| 99e5b102b7 | |||
| b331799b3f | |||
| 20014e66d0 | |||
| 8be56c5a4d | |||
| fa3df97dab | |||
| dfd4cd533b | |||
| 0d3d1a7f70 | |||
| c418b7e474 | |||
| ab79eff346 | |||
| c6e8ec0149 | |||
| e143cb0e73 | |||
| 5d1499025b | |||
| 87c22f1033 | |||
| be5fc58ef7 | |||
| d769d43d23 | |||
| 9de6a3c813 | |||
| e38219a0ee | |||
| 874d94cefb | |||
| 8e3f7d4ba4 | |||
| 1d918909f0 | |||
| 13b4c90518 | |||
| 2d2f399601 | |||
| f49d8d81b1 | |||
| 450f6c00ce | |||
| 07d4df81f6 | |||
| 2b696855cc | |||
| 64bf0fb622 | |||
| 68fa7ce02e | |||
| bd8cf9ee42 | |||
| 224382bf62 | |||
| a19ba3c215 | |||
| 5975004858 | |||
| baffb0bb35 | |||
| 6ed0ea76da | |||
| 55f864c16c | |||
| 59ecaaa5a7 | |||
| 4945daa0d4 | |||
| 59339969da | |||
| fdbdda71eb | |||
| b7c85d6b56 | |||
| e3e884393f | |||
| 70c744498b | |||
| a3f8730aa8 | |||
| d0352590ed | |||
| fd04315f17 | |||
| 6482316195 | |||
| 525cae7232 | |||
| afaba95ff2 | |||
| 5258ae5d4b | |||
| 54e30f008c | |||
| 9569cdab5f | |||
| e189daf569 | |||
| 9b60114476 | |||
| 97c123677e | |||
| a3b57e2a04 | |||
| f80c1ec86e | |||
| 32d613b146 | |||
| 649b02d5d3 | |||
| e622f601a4 | |||
| fce4fd52de | |||
| ed2a777fd4 | |||
| 4de4e36e73 | |||
| 17937783e9 | |||
| d1f79cd06b | |||
| 3f075ec367 | |||
| 77add17984 | |||
| 06eae02b7a | |||
| d7b5066683 | |||
| 046ad55b57 | |||
| 9782c5ee04 | |||
| 5f7c4dda97 | |||
| 4ad3d30b1d | |||
| 0f272ad935 | |||
| 68ac4c80af | |||
| 66095bccb1 | |||
| 1fd2c01612 | |||
| 98547ef145 | |||
| efa9e511c3 | |||
| b4e2af4c63 | |||
| 25425eab93 | |||
| e7261b1c7e | |||
| 02f3bfbfdd | |||
| 9995a1b519 | |||
| 10b47de079 | |||
| ebf0c6b086 | |||
| 621da36150 | |||
| 34f52d8218 | |||
| 0c1dcd4610 | |||
| ebaa2af196 | |||
| 552509ad9e | |||
| 806f829e08 | |||
| 75f0f5e3a5 | |||
| 652d90af98 | |||
| c4d1c652a3 | |||
| 01b61f8fb6 | |||
| 7542c20bcc | |||
| 3a65046c48 | |||
| 659aadbc7f | |||
| 8b72566b91 | |||
| ce25556a9f | |||
| 1847e6f76f | |||
| e6bf9697a5 | |||
| d2eec7676d | |||
| 7525c14e7d | |||
| 5644a2acd7 | |||
| d48ffc5051 | |||
| 48bb5ce47a | |||
| 8693e3169c | |||
| f73529bfc1 | |||
| df6b89b3be | |||
| 893effcefe | |||
| 77444e35fa | |||
| 53007ccb6a | |||
| b301d51b2d | |||
| b5d259f907 | |||
| 721826e346 | |||
| c479574905 | |||
| 291801efe2 | |||
| 13e907f876 | |||
| bee3084bbf | |||
| 9300f5756d | |||
| 7b3cac1f63 | |||
| 0acdcbae0e | |||
| 2c3483fa4e | |||
| 1b6d1dd4cb | |||
| a9b907b717 | |||
| ce5ca145ed | |||
| 15c9a370ee | |||
| 006afc56d5 | |||
| 29da1ab464 | |||
| a7db0c2887 | |||
| f409c6468e | |||
| ade2bdf181 | |||
| 9ecbfb37aa | |||
| c44c861086 | |||
| a2deb93b6c | |||
| 5527f51880 | |||
| b8d9cf1630 | |||
| 73f1f2938f | |||
| 5ea6d221e3 | |||
| 30edf87bc0 | |||
| 93a6bee01b | |||
| 17a7634a37 | |||
| 4048c28628 | |||
| 816d81b555 | |||
| dedb1c152f | |||
| 083090ca05 | |||
| 31c86c5d4a | |||
| bf785156f4 | |||
| 15af716651 | |||
| a2bd2857b2 | |||
| d0351ef405 | |||
| 552a77ecd4 | |||
| 9f10af6654 | |||
| 55c87d673c | |||
| 2607a05104 | |||
| 4f2dc949a5 | |||
| 3695c5d596 | |||
| 91cf1ab48c | |||
| 2b2c5e3d77 | |||
| 94c4a81974 | |||
| b5956ef6d2 | |||
| 3861e7642a | |||
| 1bfe23f9ec | |||
| 9f0647e156 | |||
| 7f6222a0bc | |||
| 39c07ecc4f | |||
| 28c9b72e35 | |||
| 2778ecb74a | |||
| 40cbd73226 | |||
| 7b456c9008 | |||
| 011a75714e | |||
| 38f408d1de | |||
| 006d1bd167 | |||
| 83e64fd4aa | |||
| 7c7ce6632a | |||
| 787bc250c1 | |||
| 3b5ac96a98 | |||
| 3d4dc0c1f4 | |||
| 2990420361 | |||
| 2521147579 | |||
| 4f860cca07 | |||
| bea324aa56 | |||
| c78cbbb737 | |||
| e197f6c2bb | |||
| c7d8e38cd3 | |||
| 8a241754ca | |||
| b3e77ec422 | |||
| daf593f76a | |||
| 5c4388a2e7 | |||
| 0da73ce1db | |||
| 1d2ef4561f | |||
| dbf75535c5 | |||
| aa34c96a39 | |||
| e6b6a24b3b | |||
| 0b958f21a5 | |||
| e6310a4533 | |||
| 49c3a0d494 | |||
| 213cb69332 | |||
| e43dce220c | |||
| 52dc6e05d4 | |||
| 31e76a2e97 | |||
| 19d9ca44fb | |||
| c8b0681dfa | |||
| eed17feae0 | |||
| c0478ef96e | |||
| 4713d2a09b | |||
| ea72e6cf65 | |||
| 9f5aee9258 | |||
| e56d1b9573 | |||
| 6d5a7bd3a2 | |||
| a73ef7108b | |||
| 507500f051 | |||
| 913084cc8d | |||
| 5874223866 | |||
| d5609560e2 | |||
| a5b4ab6531 | |||
| a91705b35d | |||
| 65369c73bf | |||
| eb9bb75825 | |||
| 69216ae75d | |||
| 309ea7b1d1 | |||
| 5beacacc0f | |||
| 008a909f5b | |||
| bdfc65c07b | |||
| 5ee7a70c65 | |||
| c9590829b2 | |||
| 80805bde06 | |||
| 20718bca5d | |||
| 3d58e91644 | |||
| ade2a25fc4 | |||
| dcddf88a66 | |||
| 89574e05bc | |||
| 95fe14fece | |||
| cfaf14ed65 | |||
| a50f82c42a | |||
| 1c0e1e01ce | |||
| 5ec3fc3d13 | |||
| 9bd080b566 | |||
| f7cdb5b858 | |||
| 00c3ad8f9e | |||
| d4b3038f6d | |||
| dde513a976 | |||
| 8378e8f2d6 | |||
| 374f024f85 | |||
| 32aadceaac | |||
| 285e742136 | |||
| 704a876cf0 | |||
| 7184ea9565 | |||
| 6da50126e1 | |||
| 965c8a56c9 | |||
| 0611c1d9fe | |||
| 642acc9cba | |||
| b87fb98c6c | |||
| d0d249655b | |||
| a847bb1785 | |||
| 445ee00840 | |||
| ecd33d969b | |||
| 470420410e | |||
| 2952b9e59f | |||
| 7e8995a7b2 | |||
| e7046173f8 | |||
| f1a39e3b9d | |||
| 2838f232f3 | |||
| 9ac4b262f3 | |||
| 582b8b3c07 | |||
| 91b20e07f2 | |||
| 5a99f476f9 | |||
| e06b47c8b3 | |||
| 613cf6441b | |||
| 57dd964db2 | |||
| 42dd5d384f | |||
| f2138623f4 | |||
| c69b2569ce | |||
| 6f8b88422b | |||
| 4c4d19b0d6 | |||
| 91e0f0b787 | |||
| c7f64ea0fe | |||
| fdb0b74296 | |||
| 0d7a04f1e8 | |||
| 0a72c15dfd | |||
| 282c0b40c2 | |||
| 5783f5836a | |||
| aff1f5b599 | |||
| b12079f8d9 | |||
| 99de20ef76 | |||
| c187b5fb94 | |||
| d852de4a5b | |||
| d10020d944 | |||
| f7c17546da | |||
| c267bb34b4 | |||
| 98b0b36e3b | |||
| 468224cae9 | |||
| 6b385b619a | |||
| 88669ccbff | |||
| 5f338de0cd | |||
| c266c68be8 | |||
| 364b84fd1c | |||
| 982bd80898 | |||
| 0050ae8d0a | |||
| 8d11115fab | |||
| 355ca22134 | |||
| d568964c64 | |||
| 81443e5e36 | |||
| 1c4d513f5b | |||
| d0a3ce9a09 | |||
| 0a368c0607 | |||
| 1104c1481e | |||
| 7318dd4812 | |||
| 1ee30d047d | |||
| 39e7218b52 | |||
| 959fa1c40c | |||
| fb074048df | |||
| 0b20c42513 | |||
| 7c0e53db73 | |||
| d77a6ebda0 | |||
| 42f7bf9c97 | |||
| b9d9552ae8 | |||
| ba81a842b7 | |||
| 28b3f16ef0 | |||
| 37bf4905bb | |||
| 0ab9cebe45 | |||
| a8c9587572 | |||
| 48380aa7ea | |||
| b1831bfba0 | |||
| b9f866807e | |||
| 8896450fcc | |||
| 2dc0cc3525 | |||
| a3f635894b | |||
| 542ead68a7 | |||
| 7c25809ad5 | |||
| 1f14adec2a | |||
| 8173e6a8f2 | |||
| 0baf4700f1 | |||
| e3f1fe5569 | |||
| 9aa5c27f60 | |||
| a1479420c8 | |||
| 0f368f0a5e | |||
| 5d0c6417a4 | |||
| 12d8944ca7 | |||
| 521a4ad3f0 | |||
| 040777ec87 | |||
| b68d3a5d99 | |||
| 0af3c5ab8b | |||
| 6ca1e81b6a | |||
| 068b3fa8d7 | |||
| 976b89e970 | |||
| 47e85ebbdf | |||
| 44f33fb7f0 | |||
| 2c5ba280e9 | |||
| 5250cd524a | |||
| 787dd9aa5f | |||
| e059dcb2b2 | |||
| 75bf9b394b | |||
| c158d53a39 | |||
| 8e6125796b |
@@ -0,0 +1,42 @@
|
|||||||
|
using Serilog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Helper
|
||||||
|
{
|
||||||
|
public static class SafeBussinessHelper
|
||||||
|
{
|
||||||
|
public static async Task<bool> RunAsync(Func<Task> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await func();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<(bool Success, T? Result)> RunAsync<T>(Func<Task<T>> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await func();
|
||||||
|
return (true, result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
|
||||||
|
return (false, default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -27,8 +27,7 @@ namespace IRaCIS.Core.SCP
|
|||||||
//public static readonly ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });
|
//public static readonly ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });
|
||||||
var logFactory = LoggerFactory.Create(builder => { builder.AddDebug(); });
|
var logFactory = LoggerFactory.Create(builder => { builder.AddDebug(); });
|
||||||
|
|
||||||
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value,
|
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value);
|
||||||
contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
|
|
||||||
|
|
||||||
options.UseLoggerFactory(logFactory);
|
options.UseLoggerFactory(logFactory);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Swashbuckle.AspNetCore.Filters;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerUI;
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API;
|
||||||
|
|
||||||
|
public enum SwaggerVersion
|
||||||
|
{
|
||||||
|
//[Description("HIR修改")]
|
||||||
|
//HIR = -1,
|
||||||
|
|
||||||
|
//[Description("医生模块")]
|
||||||
|
//Reviewer = 1,
|
||||||
|
|
||||||
|
[Description("项目模块")]
|
||||||
|
Trial = 2,
|
||||||
|
//[Description("入组模块")]
|
||||||
|
//Enroll = 3,
|
||||||
|
//[Description("工作量模块")]
|
||||||
|
//Workload = 4,
|
||||||
|
//[Description("通用信息获取")]
|
||||||
|
//Common = 5,
|
||||||
|
//[Description("机构信息模块")]
|
||||||
|
//Institution = 6,
|
||||||
|
//[Description("统计模块")]
|
||||||
|
//DashboardStatistics = 7,
|
||||||
|
//[Description("财务模块")]
|
||||||
|
//Financial = 8,
|
||||||
|
//[Description("管理模块")]
|
||||||
|
//Management = 9,
|
||||||
|
//[Description("影像模块")]
|
||||||
|
//Image = 10,
|
||||||
|
//[Description("读片模块")]
|
||||||
|
//Reading = 11
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public static class SwaggerSetup
|
||||||
|
{
|
||||||
|
public static void AddSwaggerSetup(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddEndpointsApiExplorer();
|
||||||
|
services.AddSwaggerGen(options =>
|
||||||
|
{
|
||||||
|
|
||||||
|
typeof(SwaggerVersion).GetFields(BindingFlags.Public | BindingFlags.Static).ToList()
|
||||||
|
.ForEach(field =>
|
||||||
|
{
|
||||||
|
var description = field.GetCustomAttribute<DescriptionAttribute>()?.Description ?? field.Name;
|
||||||
|
options.SwaggerDoc(field.Name, new Microsoft.OpenApi.Models.OpenApiInfo
|
||||||
|
{
|
||||||
|
Version = field.Name,
|
||||||
|
Description = $"{field.Name} API",
|
||||||
|
Title = description // 使用Description作为Title
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 接口排序
|
||||||
|
options.OrderActionsBy(o => o.GroupName);
|
||||||
|
|
||||||
|
//添加注释
|
||||||
|
var basePath = AppContext.BaseDirectory;
|
||||||
|
//var xmlPath1 = Path.Combine(basePath, "IRaCIS.Core.Application.xml");
|
||||||
|
var xmlPath2 = Path.Combine(basePath, "IRC.Core.SCP.xml");
|
||||||
|
//options.IncludeXmlComments(xmlPath1, true);
|
||||||
|
options.IncludeXmlComments(xmlPath2, true);
|
||||||
|
|
||||||
|
// 在header中添加token,传递到后台
|
||||||
|
options.OperationFilter<SecurityRequirementsOperationFilter>();
|
||||||
|
|
||||||
|
|
||||||
|
// 添加登录按钮
|
||||||
|
options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme()
|
||||||
|
{
|
||||||
|
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
|
||||||
|
Name = "Authorization",
|
||||||
|
//In = "header",
|
||||||
|
//Type = "apiKey"
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI(options =>
|
||||||
|
{
|
||||||
|
typeof(SwaggerVersion).GetFields(BindingFlags.Public | BindingFlags.Static).ToList()
|
||||||
|
.ForEach(field =>
|
||||||
|
{
|
||||||
|
var description = field.GetCustomAttribute<DescriptionAttribute>()?.Description ?? field.Name;
|
||||||
|
options.SwaggerEndpoint($"swagger/{field.Name}/swagger.json", $"{description}");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var data = Assembly.GetExecutingAssembly().Location;
|
||||||
|
options.IndexStream = () => Assembly.GetExecutingAssembly()
|
||||||
|
.GetManifestResourceStream("IRC.Core.SCP.wwwroot.swagger.ui.Index.html");
|
||||||
|
|
||||||
|
//路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,
|
||||||
|
//注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.Route = "doc";
|
||||||
|
options.RoutePrefix = string.Empty;
|
||||||
|
|
||||||
|
//DocExpansion设置为none可折叠所有方法
|
||||||
|
options.DocExpansion(DocExpansion.None);
|
||||||
|
|
||||||
|
//DefaultModelsExpandDepth设置为 - 1 可不显示models
|
||||||
|
options.DefaultModelsExpandDepth(-1);
|
||||||
|
|
||||||
|
// 关键一句:关闭外网校验
|
||||||
|
options.ConfigObject.ValidatorUrl = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,31 +4,51 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<BaseOutputPath></BaseOutputPath>
|
||||||
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
|
<DocumentationFile>.\IRC.Core.SCP.xml</DocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.5" />
|
<Content Remove="wwwroot\swagger\ui\abp.js" />
|
||||||
|
<Content Remove="wwwroot\swagger\ui\Index.html" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="wwwroot\swagger\ui\abp.js">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="wwwroot\swagger\ui\Index.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.6" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
|
||||||
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
||||||
<PackageReference Include="AWSSDK.S3" Version="3.7.416.8" />
|
<PackageReference Include="AWSSDK.S3" Version="4.0.6.9" />
|
||||||
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.401.81" />
|
<PackageReference Include="AWSSDK.SecurityToken" Version="4.0.2" />
|
||||||
<PackageReference Include="DistributedLock.Core" Version="1.0.8" />
|
<PackageReference Include="DistributedLock.Core" Version="1.0.8" />
|
||||||
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
|
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
|
||||||
<PackageReference Include="fo-dicom" Version="5.2.1" />
|
<PackageReference Include="fo-dicom" Version="5.2.2" />
|
||||||
<PackageReference Include="fo-dicom.Codecs" Version="5.16.1" />
|
<PackageReference Include="fo-dicom.Codecs" Version="5.16.4" />
|
||||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.1" />
|
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
|
||||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||||
<PackageReference Include="Minio" Version="6.0.4" />
|
<PackageReference Include="Minio" Version="7.0.0" />
|
||||||
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
||||||
<TreatAsUsed>true</TreatAsUsed>
|
<TreatAsUsed>true</TreatAsUsed>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
||||||
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.1.2" />
|
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.4.0" />
|
||||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
|
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.3" />
|
||||||
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="9.0.0" />
|
||||||
|
<PackageReference Include="ZiggyCreatures.FusionCache" Version="2.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -36,4 +56,12 @@
|
|||||||
<ProjectReference Include="..\IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj" />
|
<ProjectReference Include="..\IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Update="appsettings.Prod_HIR_SCP.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<doc>
|
||||||
|
<assembly>
|
||||||
|
<name>IRC.Core.SCP</name>
|
||||||
|
</assembly>
|
||||||
|
<members>
|
||||||
|
<member name="M:IRaCIS.Core.SCP.Service.CacheKeys.UserLoginError(System.String)">
|
||||||
|
<summary>
|
||||||
|
用户登录错误 限制登录
|
||||||
|
</summary>
|
||||||
|
<param name="userName"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.SCP.Service.CacheKeys.SkipReadingCacheKey(System.Guid)">
|
||||||
|
<summary>
|
||||||
|
跳过阅片
|
||||||
|
</summary>
|
||||||
|
<param name="userId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.SCP.Service.CacheKeys.StartReadingTimeKey(System.Guid)">
|
||||||
|
<summary>
|
||||||
|
开始阅片时间
|
||||||
|
</summary>
|
||||||
|
<param name="userId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.SCP.Service.CacheKeys.StartRestTime(System.Guid)">
|
||||||
|
<summary>
|
||||||
|
开始休息时间
|
||||||
|
</summary>
|
||||||
|
<param name="userId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.SCP.Service.DicomArchiveService.ArchiveDicomFileAsync(FellowOakDicom.DicomFile,System.String,System.String,System.String,System.Int64)">
|
||||||
|
<summary>
|
||||||
|
单个文件接收 归档
|
||||||
|
</summary>
|
||||||
|
<param name="dataset"></param>
|
||||||
|
<returns></returns>
|
||||||
|
<exception cref="T:System.NotImplementedException"></exception>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.SCP.Service.PatientStudyService.AutoBindingPatientStudyVisitAsync(System.Collections.Generic.List{System.Guid})">
|
||||||
|
<summary>
|
||||||
|
传输完成后,自动给检查绑定访视
|
||||||
|
</summary>
|
||||||
|
<param name="inCommand"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.SCP.OSSService.UploadToOSSAsync(System.IO.Stream,System.String,System.String,System.Boolean)">
|
||||||
|
<summary>
|
||||||
|
oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
||||||
|
</summary>
|
||||||
|
<param name="fileStream"></param>
|
||||||
|
<param name="oosFolderPath"></param>
|
||||||
|
<param name="fileRealName"></param>
|
||||||
|
<param name="isFileNameAddGuid"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.SCP.OSSService.UploadToOSSAsync(System.String,System.String,System.Boolean)">
|
||||||
|
<summary>
|
||||||
|
oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
||||||
|
</summary>
|
||||||
|
<param name="localFilePath"></param>
|
||||||
|
<param name="oosFolderPath"></param>
|
||||||
|
<param name="isFileNameAddGuid"></param>
|
||||||
|
<returns></returns>
|
||||||
|
<exception cref="T:IRaCIS.Core.Infrastructure.BusinessValidationFailedException"></exception>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.SCP.OSSService.DeleteFromPrefix(System.String)">
|
||||||
|
<summary>
|
||||||
|
删除某个目录的文件
|
||||||
|
</summary>
|
||||||
|
<param name="prefix"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="T:IRaCIS.Core.Application.Service.BusinessFilter.UnifiedApiResultFilter">
|
||||||
|
<summary>
|
||||||
|
统一返回前端数据包装,之前在控制器包装,现在修改为动态Api 在ResultFilter这里包装,减少重复冗余代码
|
||||||
|
by zhouhang 2021.09.12 周末
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.Application.Service.BusinessFilter.UnifiedApiResultFilter.OnResultExecutionAsync(Microsoft.AspNetCore.Mvc.Filters.ResultExecutingContext,Microsoft.AspNetCore.Mvc.Filters.ResultExecutionDelegate)">
|
||||||
|
<summary>
|
||||||
|
异步版本
|
||||||
|
</summary>
|
||||||
|
<param name="context"></param>
|
||||||
|
<param name="next"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
</members>
|
||||||
|
</doc>
|
||||||
+28
-9
@@ -6,6 +6,7 @@ using FellowOakDicom;
|
|||||||
using FellowOakDicom.Imaging;
|
using FellowOakDicom.Imaging;
|
||||||
using FellowOakDicom.Imaging.NativeCodec;
|
using FellowOakDicom.Imaging.NativeCodec;
|
||||||
using FellowOakDicom.Network;
|
using FellowOakDicom.Network;
|
||||||
|
using IRaCIS.Core.API;
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
using IRaCIS.Core.SCP;
|
using IRaCIS.Core.SCP;
|
||||||
using IRaCIS.Core.SCP.Filter;
|
using IRaCIS.Core.SCP.Filter;
|
||||||
@@ -14,6 +15,7 @@ using MassTransit;
|
|||||||
using MassTransit.NewIdProviders;
|
using MassTransit.NewIdProviders;
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Identity.Client;
|
||||||
using Panda.DynamicWebApi;
|
using Panda.DynamicWebApi;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
@@ -82,7 +84,6 @@ builder.Services.AddControllers(options =>
|
|||||||
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
|
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
|
||||||
|
|
||||||
|
|
||||||
builder.Services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
|
|
||||||
builder.Services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
|
builder.Services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
|
||||||
builder.Services.AddOptions().Configure<DicomSCPServiceOption>(_configuration.GetSection("DicomSCPServiceConfig"));
|
builder.Services.AddOptions().Configure<DicomSCPServiceOption>(_configuration.GetSection("DicomSCPServiceConfig"));
|
||||||
|
|
||||||
@@ -126,14 +127,14 @@ builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
|||||||
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
builder.Services.AddFellowOakDicom().AddTranscoderManager<NativeTranscoderManager>()
|
builder.Services.AddFellowOakDicom().AddTranscoderManager<NativeTranscoderManager>()
|
||||||
//.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
//.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
||||||
.AddImageManager<ImageSharpImageManager>();
|
.AddImageManager<ImageSharpImageManager>();
|
||||||
|
|
||||||
|
|
||||||
//Dicom影像渲染图片 跨平台
|
|
||||||
//builder.Services.AddDicomSetup();
|
////Dicom影像渲染图片 跨平台
|
||||||
|
////builder.Services.AddDicomSetup();
|
||||||
//new DicomSetupBuilder()
|
//new DicomSetupBuilder()
|
||||||
// .RegisterServices(s =>
|
// .RegisterServices(s =>
|
||||||
// s.AddFellowOakDicom()
|
// s.AddFellowOakDicom()
|
||||||
@@ -141,8 +142,8 @@ builder.Services.AddFellowOakDicom().AddTranscoderManager<NativeTranscoderManage
|
|||||||
// //.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
// //.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
||||||
// .AddImageManager<ImageSharpImageManager>())
|
// .AddImageManager<ImageSharpImageManager>())
|
||||||
// .SkipValidation()
|
// .SkipValidation()
|
||||||
// .Build();
|
|
||||||
|
|
||||||
|
// .Build();
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -151,18 +152,29 @@ builder.Services.AddFellowOakDicom().AddTranscoderManager<NativeTranscoderManage
|
|||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
//builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
//builder.Services.AddSwaggerGen();
|
||||||
|
|
||||||
|
//Swagger Api 文档
|
||||||
|
builder.Services.AddSwaggerSetup();
|
||||||
|
|
||||||
|
// FusionCache
|
||||||
|
builder.Services.AddFusionCache();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
//if (app.Environment.IsDevelopment())
|
//if (app.Environment.IsDevelopment())
|
||||||
//{
|
//{
|
||||||
app.UseSwagger();
|
//app.UseSwagger();
|
||||||
app.UseSwaggerUI();
|
//app.UseSwaggerUI();
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
//不需要 token 访问的静态文件 wwwroot css, JavaScript, and images don't require authentication.
|
||||||
|
app.UseStaticFiles();
|
||||||
|
|
||||||
|
SwaggerSetup.Configure(app, app.Environment);
|
||||||
|
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
@@ -191,6 +203,7 @@ app.MapControllers();
|
|||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration()
|
||||||
//.MinimumLevel.Information()
|
//.MinimumLevel.Information()
|
||||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
|
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
|
||||||
|
.MinimumLevel.Override("ZiggyCreatures.Caching.Fusion", LogEventLevel.Warning)
|
||||||
.WriteTo.Console()
|
.WriteTo.Console()
|
||||||
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day)
|
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day)
|
||||||
.CreateLogger();
|
.CreateLogger();
|
||||||
@@ -219,9 +232,15 @@ else
|
|||||||
|
|
||||||
DicomSetupBuilder.UseServiceProvider(app.Services);
|
DicomSetupBuilder.UseServiceProvider(app.Services);
|
||||||
|
|
||||||
|
// Program.cs
|
||||||
|
IRCAppConfig.Configuration = builder.Configuration;
|
||||||
|
|
||||||
|
|
||||||
var logger = app.Services.GetService<Microsoft.Extensions.Logging.ILogger<Program>>();
|
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);
|
var server = DicomServerFactory.Create<CStoreSCPService>(_configuration.GetSection("DicomSCPServiceConfig").GetValue<int>("ServerPort"), userState: app.Services,logger: logger);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
"profiles": {
|
"profiles": {
|
||||||
"Test_IRC_SCP": {
|
"Test_HIR_SCP": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"launchUrl": "swagger",
|
"launchUrl": "swagger",
|
||||||
"applicationUrl": "http://localhost:6200",
|
"applicationUrl": "http://localhost:6200",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Test_IRC_SCP"
|
"ASPNETCORE_ENVIRONMENT": "Test_HIR_SCP"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Uat_IRC_SCP": {
|
"Uat_HIR_SCP": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"launchUrl": "swagger",
|
"launchUrl": "swagger",
|
||||||
"applicationUrl": "http://localhost:6200",
|
"applicationUrl": "http://localhost:6200",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Uat_IRC_SCP"
|
"ASPNETCORE_ENVIRONMENT": "Uat_HIR_SCP"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"US_Prod_IRC_SCP": {
|
"Prod_HIR_SCP": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"launchUrl": "swagger",
|
"launchUrl": "swagger",
|
||||||
"applicationUrl": "http://localhost:6200",
|
"applicationUrl": "http://localhost:6200",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "US_Prod_SCP"
|
"ASPNETCORE_ENVIRONMENT": "Prod_HIR_SCP"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,93 @@
|
|||||||
using FellowOakDicom.Network;
|
using FellowOakDicom;
|
||||||
using FellowOakDicom;
|
using FellowOakDicom.Imaging;
|
||||||
using System;
|
using FellowOakDicom.Imaging.Codec;
|
||||||
using System.Collections.Generic;
|
using FellowOakDicom.IO.Buffer;
|
||||||
using System.Linq;
|
using FellowOakDicom.Network;
|
||||||
using System.Text;
|
using FellowOakDicom.Network.Client;
|
||||||
using System.Threading.Tasks;
|
using IRaCIS.Core.Domain.Models;
|
||||||
using Microsoft.Extensions.Logging;
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using IRaCIS.Core.Infrastructure;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using IRaCIS.Core.SCP.Service;
|
||||||
|
using MassTransit.Futures.Contracts;
|
||||||
|
using Medallion.Threading;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using IRaCIS.Core.SCP.Service;
|
using Microsoft.Extensions.Logging;
|
||||||
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 Microsoft.Extensions.Options;
|
||||||
using System.Data;
|
using Microsoft.Identity.Client;
|
||||||
using FellowOakDicom.Imaging;
|
using Newtonsoft.Json;
|
||||||
|
using Serilog;
|
||||||
using SharpCompress.Common;
|
using SharpCompress.Common;
|
||||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||||
using IRaCIS.Core.Infrastructure;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using ZiggyCreatures.Caching.Fusion;
|
||||||
|
|
||||||
namespace IRaCIS.Core.SCP.Service
|
namespace IRaCIS.Core.SCP.Service
|
||||||
{
|
{
|
||||||
|
|
||||||
public class DicomSCPServiceOption
|
public class DicomSCPServiceOption
|
||||||
{
|
{
|
||||||
|
public bool IsSupportThirdService { get; set; }
|
||||||
|
|
||||||
|
public bool IsForwardImageMultiThread { get; set; }
|
||||||
|
|
||||||
|
public bool IsUploadImageAnonymization { get; set; }
|
||||||
|
|
||||||
public List<string> CalledAEList { get; set; }
|
public List<string> CalledAEList { get; set; }
|
||||||
|
|
||||||
public string ServerPort { get; set; }
|
public string ServerPort { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ThirdDestinationAE
|
||||||
|
{
|
||||||
|
public int Port { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string IP { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class IRCAppConfig
|
||||||
|
{
|
||||||
|
public static IConfiguration Configuration { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class CStoreSCPService : DicomService, IDicomServiceProvider, IDicomCStoreProvider, IDicomCEchoProvider
|
public class CStoreSCPService : DicomService, IDicomServiceProvider, IDicomCStoreProvider, IDicomCEchoProvider
|
||||||
{
|
{
|
||||||
|
//private IServiceProvider _injectServiceProvider { get; set; }
|
||||||
private IServiceProvider _serviceProvider { get; set; }
|
private IServiceProvider _serviceProvider { get; set; }
|
||||||
|
|
||||||
private List<Guid> _SCPStudyIdList { get; set; } = new List<Guid>();
|
private List<Guid> _SCPStudyIdList => _ImageUploadList.Where(t => t.SCPStudyId != Guid.Empty).Select(t => t.SCPStudyId).ToList();
|
||||||
|
|
||||||
|
private List<ImageUploadInfo> _ImageUploadList { get; set; } = new List<ImageUploadInfo>();
|
||||||
|
|
||||||
private SCPImageUpload _upload { get; set; }
|
private SCPImageUpload _upload { get; set; }
|
||||||
|
|
||||||
private Guid _trialId { get; set; }
|
private DicomSCPServiceOption DicomSCPServiceConfig { get; set; }
|
||||||
|
|
||||||
|
public HospitalGroup CurrentHospitalGroup { get; set; }
|
||||||
|
|
||||||
|
private List<Guid> HospitalGroupIdList { get; set; }
|
||||||
|
|
||||||
|
private bool _releasedNormally = false;
|
||||||
|
|
||||||
|
private bool _isCurrentThirdForward = false;
|
||||||
|
|
||||||
|
private List<ThirdDestinationAE> ThirdDestinationAEList { get; set; }
|
||||||
|
|
||||||
private Guid _trialSiteId { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -59,22 +101,38 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
private static readonly DicomTransferSyntax[] _acceptedImageTransferSyntaxes = new DicomTransferSyntax[]
|
private static readonly DicomTransferSyntax[] _acceptedImageTransferSyntaxes = new DicomTransferSyntax[]
|
||||||
{
|
{
|
||||||
// Lossless
|
// Lossless
|
||||||
DicomTransferSyntax.JPEGLSLossless, //1.2.840.10008.1.2.4.80
|
DicomTransferSyntax.JPEGLSLossless,
|
||||||
DicomTransferSyntax.JPEG2000Lossless, //1.2.840.10008.1.2.4.90
|
DicomTransferSyntax.JPEG2000Lossless,
|
||||||
DicomTransferSyntax.JPEGProcess14SV1, //1.2.840.10008.1.2.4.70
|
DicomTransferSyntax.JPEGProcess14SV1,
|
||||||
DicomTransferSyntax.JPEGProcess14, //1.2.840.10008.1.2.4.57 JPEG Lossless, Non-Hierarchical (Process 14)
|
DicomTransferSyntax.JPEGProcess14,
|
||||||
DicomTransferSyntax.RLELossless, //1.2.840.10008.1.2.5
|
DicomTransferSyntax.RLELossless,
|
||||||
// Lossy
|
// Lossy
|
||||||
DicomTransferSyntax.JPEGLSNearLossless,//1.2.840.10008.1.2.4.81"
|
DicomTransferSyntax.JPEGLSNearLossless,
|
||||||
DicomTransferSyntax.JPEG2000Lossy, //1.2.840.10008.1.2.4.91
|
DicomTransferSyntax.JPEG2000Lossy,
|
||||||
DicomTransferSyntax.JPEGProcess1, //1.2.840.10008.1.2.4.50
|
DicomTransferSyntax.JPEGProcess1,
|
||||||
DicomTransferSyntax.JPEGProcess2_4, //1.2.840.10008.1.2.4.51
|
DicomTransferSyntax.JPEGProcess2_4,
|
||||||
// Uncompressed
|
// Uncompressed
|
||||||
DicomTransferSyntax.ExplicitVRLittleEndian, //1.2.840.10008.1.2.1
|
DicomTransferSyntax.ExplicitVRLittleEndian,
|
||||||
DicomTransferSyntax.ExplicitVRBigEndian, //1.2.840.10008.1.2.2
|
DicomTransferSyntax.ExplicitVRBigEndian,
|
||||||
DicomTransferSyntax.ImplicitVRLittleEndian //1.2.840.10008.1.2
|
DicomTransferSyntax.ImplicitVRLittleEndian
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 定义一个静态信号量,控制同时最多 N 个转发线程
|
||||||
|
|
||||||
|
private static SemaphoreSlim _forwardLimiter;
|
||||||
|
|
||||||
|
// ✅ 静态构造函数(只执行一次,全局初始化)
|
||||||
|
static CStoreSCPService()
|
||||||
|
{
|
||||||
|
// 默认单线程
|
||||||
|
|
||||||
|
var maxThreads = IRCAppConfig.Configuration.GetValue<int>("DicomSCPServiceConfig:MultiThreadCount", 1);
|
||||||
|
|
||||||
|
_forwardLimiter = new SemaphoreSlim(maxThreads);
|
||||||
|
|
||||||
|
Log.Logger.Information($"初始化 DICOM 转发线程限制为: {maxThreads}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public CStoreSCPService(INetworkStream stream, Encoding fallbackEncoding, Microsoft.Extensions.Logging.ILogger log, DicomServiceDependencies dependencies, IServiceProvider injectServiceProvider)
|
public CStoreSCPService(INetworkStream stream, Encoding fallbackEncoding, Microsoft.Extensions.Logging.ILogger log, DicomServiceDependencies dependencies, IServiceProvider injectServiceProvider)
|
||||||
: base(stream, fallbackEncoding, log, dependencies)
|
: base(stream, fallbackEncoding, log, dependencies)
|
||||||
@@ -88,53 +146,42 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
public Task OnReceiveAssociationRequestAsync(DicomAssociation association)
|
public Task OnReceiveAssociationRequestAsync(DicomAssociation association)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
_upload = new SCPImageUpload() { StartTime = DateTime.Now, CallingAE = association.CallingAE, CalledAE = association.CalledAE, CallingAEIP = association.RemoteHost };
|
_upload = new SCPImageUpload() { StartTime = DateTime.Now, CallingAE = association.CallingAE, CalledAE = association.CalledAE, CallingAEIP = association.RemoteHost };
|
||||||
|
|
||||||
|
|
||||||
Log.Logger.Warning($"接收到来自{association.CallingAE}的连接");
|
Log.Logger.Warning($"接收到来自{association.CallingAE}的连接");
|
||||||
|
|
||||||
//_serviceProvider = (IServiceProvider)this.UserState;
|
|
||||||
|
|
||||||
var _trialDicomAERepository = _serviceProvider.GetService<IRepository<TrialDicomAE>>();
|
var option = _serviceProvider.GetService<IOptionsMonitor<DicomSCPServiceOption>>().CurrentValue;
|
||||||
|
|
||||||
|
DicomSCPServiceConfig = option;
|
||||||
|
|
||||||
|
var _hospitalGroupRepository = _serviceProvider.GetService<IRepository<HospitalGroup>>();
|
||||||
|
|
||||||
|
var _dicomAERepository = _serviceProvider.GetService<IRepository<DicomAE>>();
|
||||||
|
|
||||||
|
|
||||||
var trialDicomAEList = _trialDicomAERepository.Select(t => new { t.CalledAE, t.TrialId }).ToList();
|
ThirdDestinationAEList = _dicomAERepository.Where(t => t.PacsTypeEnum == PacsType.Destination).Select(t => new ThirdDestinationAE() { IP = t.IP, Port = t.Port, Name = t.CalledAE }).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();
|
var aeList = _dicomAERepository/*.Where(t => t.PacsTypeEnum == PacsType.PacsServer)*/.Select(t => t.CalledAE).ToList();
|
||||||
|
|
||||||
if (findTrialSiteAE != null)
|
var list = _hospitalGroupRepository.Where(t => t.IsEnable).ToList();
|
||||||
{
|
|
||||||
_trialSiteId = findTrialSiteAE.TrialSiteId;
|
|
||||||
|
|
||||||
isCanReceiveIamge = true;
|
CurrentHospitalGroup = list.FirstOrDefault(t => t.CallingAE == association.CallingAE);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
var unionAEList = aeList.Union(list.Select(t => t.CallingAE)).ToList();
|
||||||
|
|
||||||
if (association.CallingAE == "test-callingAE")
|
|
||||||
{
|
|
||||||
isCanReceiveIamge = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!trialCalledAEList.Contains(association.CalledAE) || isCanReceiveIamge == false)
|
|
||||||
|
var calledAEList = option.CalledAEList;
|
||||||
|
|
||||||
|
if (!calledAEList.Contains(association.CalledAE) || !unionAEList.Any(t => t == association.CallingAE))
|
||||||
{
|
{
|
||||||
|
|
||||||
Log.Logger.Warning($"拒绝CallingAE:{association.CallingAE} CalledAE:{association.CalledAE}的连接");
|
Log.Logger.Warning($"拒绝CalledAE:{association.CalledAE} CallingAE:{association.CallingAE}连接");
|
||||||
|
|
||||||
return SendAssociationRejectAsync(
|
return SendAssociationRejectAsync(
|
||||||
DicomRejectResult.Permanent,
|
DicomRejectResult.Permanent,
|
||||||
@@ -154,53 +201,82 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return SendAssociationAcceptAsync(association);
|
return SendAssociationAcceptAsync(association);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task OnReceiveAssociationReleaseRequestAsync()
|
public async Task OnReceiveAssociationReleaseRequestAsync()
|
||||||
{
|
{
|
||||||
|
if (_isCurrentThirdForward == false)
|
||||||
|
{
|
||||||
|
var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();
|
||||||
|
|
||||||
|
|
||||||
|
var @lock = _distributedLockProvider.CreateLock($"{_upload.CallingAE}");
|
||||||
|
|
||||||
|
using (await @lock.AcquireAsync())
|
||||||
|
{
|
||||||
|
|
||||||
await DataMaintenanceAsaync();
|
await DataMaintenanceAsaync();
|
||||||
|
|
||||||
//记录监控
|
await AddUploadLogAsync();
|
||||||
|
|
||||||
var _SCPImageUploadRepository = _serviceProvider.GetService<IRepository<SCPImageUpload>>();
|
_releasedNormally = true;
|
||||||
|
|
||||||
_upload.EndTime = DateTime.Now;
|
Log.Logger.Information($"进入释放连接请求 {_releasedNormally}");
|
||||||
_upload.StudyCount = _SCPStudyIdList.Count;
|
}
|
||||||
_upload.TrialId = _trialId;
|
}
|
||||||
_upload.TrialSiteId = _trialSiteId;
|
|
||||||
|
|
||||||
await _SCPImageUploadRepository.AddAsync(_upload, true);
|
|
||||||
|
|
||||||
|
|
||||||
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
|
||||||
//将检查设置为传输结束
|
|
||||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
|
||||||
|
|
||||||
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
|
||||||
|
|
||||||
await SendAssociationReleaseResponseAsync();
|
await SendAssociationReleaseResponseAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task AddUploadLogAsync()
|
||||||
|
{
|
||||||
|
//转发第三方,那么不记录日志
|
||||||
|
if (_isCurrentThirdForward == false)
|
||||||
|
{
|
||||||
|
//记录监控
|
||||||
|
|
||||||
|
var _SCPImageUploadRepository = _serviceProvider.GetService<IRepository<SCPImageUpload>>();
|
||||||
|
|
||||||
|
_upload.EndTime = DateTime.Now;
|
||||||
|
_upload.StudyCount = _ImageUploadList.Count;
|
||||||
|
|
||||||
|
_upload.UploadJsonStr = (new SCPImageLog() { UploadList = _ImageUploadList }).ToJsonStr();
|
||||||
|
|
||||||
|
|
||||||
|
if (_upload.FileCount > 0)
|
||||||
|
{
|
||||||
|
//可能是测试echo 导致记录了
|
||||||
|
await _SCPImageUploadRepository.AddAsync(_upload, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task DataMaintenanceAsaync()
|
private async Task DataMaintenanceAsaync()
|
||||||
{
|
{
|
||||||
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}传输结束:开始维护数据,处理检查Modality");
|
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}传输结束:开始维护数据,处理检查Modality 以及自动创建访视,绑定检查");
|
||||||
|
|
||||||
|
var patientStudyService = _serviceProvider.GetService<IPatientStudyService>();
|
||||||
|
|
||||||
|
await patientStudyService.AutoBindingPatientStudyVisitAsync(_SCPStudyIdList);
|
||||||
|
|
||||||
//处理检查Modality
|
//处理检查Modality
|
||||||
var _dictionaryRepository = _serviceProvider.GetService<IRepository<Dictionary>>();
|
var _dictionaryRepository = _serviceProvider.GetService<IRepository<Dictionary>>();
|
||||||
var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();
|
var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();
|
||||||
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
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 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, t.StudyInstanceUid }).ToList();
|
||||||
|
|
||||||
|
foreach (var g in seriesModalityList.GroupBy(t => new { t.SCPStudyId, t.StudyInstanceUid }))
|
||||||
{
|
{
|
||||||
var modality = string.Join('、', g.Select(t => t.Modality).Distinct().ToList());
|
var modality = string.Join('、', g.Select(t => t.Modality).Distinct().ToList());
|
||||||
|
|
||||||
@@ -221,7 +297,9 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
modalityForEdit = "PET-CT";
|
modalityForEdit = "PET-CT";
|
||||||
}
|
}
|
||||||
|
|
||||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => t.Id == g.Key, u => new SCPStudy() { Modalities = modality, ModalityForEdit = modalityForEdit });
|
await _studyRepository.BatchUpdateNoTrackingAsync(t => t.Id == g.Key.SCPStudyId, u => new SCPStudy() { Modalities = modality, ModalityForEdit = modalityForEdit });
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,68 +315,459 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
|
|
||||||
public async void OnConnectionClosed(Exception exception)
|
public async void OnConnectionClosed(Exception exception)
|
||||||
{
|
{
|
||||||
/* nothing to do here */
|
if (_isCurrentThirdForward == false)
|
||||||
|
|
||||||
//奇怪的bug 上传的时候,用王捷修改的影像,会关闭,重新连接,导致检查id 丢失,然后状态不一致
|
|
||||||
if (exception == null)
|
|
||||||
{
|
{
|
||||||
//var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
||||||
////将检查设置为传输结束
|
|
||||||
//await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
|
||||||
|
|
||||||
//await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
|
||||||
|
if (exception != null || _releasedNormally == false)
|
||||||
|
{
|
||||||
|
//客户端断网,恢复后,也是没有异常的,估计是超时走了关闭
|
||||||
|
|
||||||
|
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true, IsUploadFaild = true });
|
||||||
|
//记录日志
|
||||||
|
await AddUploadLogAsync();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
Log.Logger.Warning($"连接关闭 {exception?.Message} {exception?.InnerException?.Message}");
|
{
|
||||||
|
//将检查设置为传输结束
|
||||||
|
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true, IsUploadFaild = false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Logger.Warning($"连接关闭 {_releasedNormally} {exception?.Message} {exception?.InnerException?.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<DicomStatus> ForwardToThirdPartyAsync(DicomCStoreRequest request, ThirdDestinationAE findDestination)
|
||||||
|
{
|
||||||
|
await _forwardLimiter.WaitAsync(); // 限制并发数量
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var forwardRequest = new DicomCStoreRequest(request.File.Clone());
|
||||||
|
|
||||||
|
var client = DicomClientFactory.Create(
|
||||||
|
findDestination.IP,
|
||||||
|
findDestination.Port,
|
||||||
|
false,
|
||||||
|
DicomSCPServiceConfig.CalledAEList.First(),
|
||||||
|
findDestination.Name);
|
||||||
|
|
||||||
|
DicomStatus finalStatus = DicomStatus.Success;
|
||||||
|
|
||||||
|
forwardRequest.OnResponseReceived += (rq, rp) =>
|
||||||
|
{
|
||||||
|
Log.Logger.Information($"Forwarded C-STORE Response: {rq.SOPInstanceUID} {rp.Status}");
|
||||||
|
finalStatus = rp.Status; // 记录目标 PACS 返回状态
|
||||||
|
};
|
||||||
|
|
||||||
|
await client.AddRequestAsync(forwardRequest);
|
||||||
|
await client.SendAsync();
|
||||||
|
|
||||||
|
return finalStatus; // 返回实际状态
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Logger.Error("Error forwarding C-STORE: " + ex.Message);
|
||||||
|
return DicomStatus.ProcessingFailure; // 出错返回失败状态
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_forwardLimiter.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<DicomCStoreResponse> OnCStoreRequestAsync(DicomCStoreRequest request)
|
public async Task<DicomCStoreResponse> OnCStoreRequestAsync(DicomCStoreRequest request)
|
||||||
{
|
{
|
||||||
|
|
||||||
string studyInstanceUid = request.Dataset.GetString(DicomTag.StudyInstanceUID);
|
string studyInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty);
|
||||||
string seriesInstanceUid = request.Dataset.GetString(DicomTag.SeriesInstanceUID);
|
string seriesInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty);
|
||||||
string sopInstanceUid = request.Dataset.GetString(DicomTag.SOPInstanceUID);
|
string sopInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty);
|
||||||
|
string patientIdStr = request.Dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
|
||||||
|
|
||||||
//Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid, trialId.ToString());
|
if (studyInstanceUid.IsNullOrEmpty() || seriesInstanceUid.IsNullOrEmpty() || sopInstanceUid.IsNullOrEmpty())
|
||||||
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, _trialId.ToString());
|
{
|
||||||
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, _trialId.ToString());
|
Log.Logger.Error($"接收数据读取StudyInstanceUID:{studyInstanceUid}、SeriesInstanceUID:{seriesInstanceUid}、SOPInstanceUID:{sopInstanceUid}有空 ");
|
||||||
|
|
||||||
|
return new DicomCStoreResponse(request, DicomStatus.Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _cmoveStudyRepository = _serviceProvider.GetService<IRepository<CmoveStudy>>();
|
||||||
|
|
||||||
|
#region 判断是否转发第三方影像
|
||||||
|
|
||||||
|
if (DicomSCPServiceConfig.IsSupportThirdService)
|
||||||
|
{
|
||||||
|
var cmoveInfo = _cmoveStudyRepository.Where(t => t.StudyInstanceUIDList.Any(c => c == studyInstanceUid)).OrderByDescending(t => t.CreateTime).FirstOrDefault();
|
||||||
|
|
||||||
|
//确定是第三方请求
|
||||||
|
if (cmoveInfo != null && ThirdDestinationAEList.Any(t => t.Name == cmoveInfo.DestinationAE))
|
||||||
|
{
|
||||||
|
_isCurrentThirdForward = true;
|
||||||
|
|
||||||
|
var findDestination = ThirdDestinationAEList.FirstOrDefault(t => t.Name == cmoveInfo.DestinationAE);
|
||||||
|
|
||||||
|
if (DicomSCPServiceConfig.IsForwardImageMultiThread)
|
||||||
|
{
|
||||||
|
// 多线程模式,异步执行
|
||||||
|
_ = Task.Run(() => ForwardToThirdPartyAsync(request, findDestination));
|
||||||
|
|
||||||
|
// 立即返回 Success
|
||||||
|
return new DicomCStoreResponse(request, DicomStatus.Success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 单线程模式,同步等待完成
|
||||||
|
var responseStatus = await ForwardToThirdPartyAsync(request, findDestination);
|
||||||
|
|
||||||
|
return new DicomCStoreResponse(request, responseStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
//确保来了影像集合存在
|
||||||
|
if (!_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
|
||||||
|
{
|
||||||
|
_ImageUploadList.Add(new ImageUploadInfo() { StudyInstanceUid = studyInstanceUid });
|
||||||
|
}
|
||||||
|
|
||||||
|
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid);
|
||||||
|
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid);
|
||||||
|
|
||||||
|
|
||||||
var ossService = _serviceProvider.GetService<IOSSService>();
|
var ossService = _serviceProvider.GetService<IOSSService>();
|
||||||
var dicomArchiveService = _serviceProvider.GetService<IDicomArchiveService>();
|
var dicomArchiveService = _serviceProvider.GetService<IDicomArchiveService>();
|
||||||
var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();
|
var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();
|
||||||
|
var _studyGroupRepository = _serviceProvider.GetService<IRepository<SCPStudyHospitalGroup>>();
|
||||||
|
var _fusionCache = _serviceProvider.GetService<IFusionCache>();
|
||||||
|
var _systemAnonymizationRepository = _serviceProvider.GetService<IRepository<SystemAnonymization>>();
|
||||||
|
|
||||||
|
|
||||||
var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();
|
var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();
|
||||||
|
|
||||||
var storeRelativePath = string.Empty;
|
var storeRelativePath = string.Empty;
|
||||||
var ossFolderPath = $"{_trialId}/Image/PACS/{_trialSiteId}/{studyInstanceUid}";
|
var ossFolderPath = $"Dicom/{studyInstanceUid}";
|
||||||
|
|
||||||
|
|
||||||
long fileSize = 0;
|
long fileSize = 0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 直接拿 Dataset(已经完整)
|
||||||
|
var dataset = request.Dataset;
|
||||||
|
|
||||||
|
#region 匿名化
|
||||||
|
|
||||||
|
if (DicomSCPServiceConfig.IsUploadImageAnonymization)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
var anonymizeList = await _fusionCache.GetOrSetAsync(CacheKeys.SystemAnonymization, _ => CacheHelper.GetSystemAnonymizationListAsync(_systemAnonymizationRepository), TimeSpan.FromDays(7));
|
||||||
|
|
||||||
|
|
||||||
|
var fixedFiledList = anonymizeList.Where(t => t.IsFixed).ToList();
|
||||||
|
|
||||||
|
var ircFiledList = anonymizeList.Where(t => t.IsFixed == false).ToList();
|
||||||
|
|
||||||
|
foreach (var item in fixedFiledList)
|
||||||
|
{
|
||||||
|
|
||||||
|
var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16));
|
||||||
|
|
||||||
|
dataset.AddOrUpdate(dicomTag, item.ReplaceValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in ircFiledList)
|
||||||
|
{
|
||||||
|
|
||||||
|
var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16));
|
||||||
|
|
||||||
|
if (dicomTag == DicomTag.ClinicalTrialProtocolID)
|
||||||
|
{
|
||||||
|
dataset.AddOrUpdate(DicomTag.ClinicalTrialProtocolID, "");
|
||||||
|
|
||||||
|
}
|
||||||
|
if (dicomTag == DicomTag.ClinicalTrialSiteID)
|
||||||
|
{
|
||||||
|
dataset.AddOrUpdate(DicomTag.ClinicalTrialSiteID, "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dicomTag == DicomTag.ClinicalTrialSubjectID)
|
||||||
|
{
|
||||||
|
dataset.AddOrUpdate(DicomTag.ClinicalTrialSubjectID, "");
|
||||||
|
|
||||||
|
}
|
||||||
|
if (dicomTag == DicomTag.ClinicalTrialTimePointID)
|
||||||
|
{
|
||||||
|
dataset.AddOrUpdate(DicomTag.ClinicalTrialTimePointID, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (dicomTag == DicomTag.PatientID)
|
||||||
|
//{
|
||||||
|
// var pid = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
|
||||||
|
|
||||||
|
// dataset.AddOrUpdate(DicomTag.PatientID, trialSiteInfo.TrialCode + "_" + pid);
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
// 构造 DicomFile(不用 Open)
|
||||||
|
var dicomFile = new DicomFile(dataset);
|
||||||
|
|
||||||
|
|
||||||
|
#region 1帧拆成多个固定大小的,方便移动端浏览
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var numberOfFrames = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 1);
|
||||||
|
|
||||||
|
//多帧处理逻辑
|
||||||
|
if (numberOfFrames > 1)
|
||||||
|
{
|
||||||
|
//一定要有像素数据才处理
|
||||||
|
var pixelData = DicomPixelData.Create(dicomFile.Dataset);
|
||||||
|
|
||||||
|
if (pixelData != null)
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
using (MemoryStream ms = new MemoryStream())
|
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 开始处理多帧instanceId:{instanceId}");
|
||||||
|
|
||||||
|
var syntax = pixelData.Syntax;
|
||||||
|
|
||||||
|
// 每个 fragment 固定大小 (64KB 示例,可以自己调整)
|
||||||
|
int fragmentSize = 20 * 1024;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var frag = dicomFile.Dataset.GetDicomItem<DicomOtherByteFragment>(DicomTag.PixelData);
|
||||||
|
|
||||||
|
int fragmentCount = frag?.Fragments?.Count() ?? 0;
|
||||||
|
|
||||||
|
var originOffsetTable = frag?.OffsetTable; //有可能没有表,需要自己重建
|
||||||
|
|
||||||
|
var bot = new List<uint>();
|
||||||
|
|
||||||
|
uint botOffset = 0;
|
||||||
|
|
||||||
|
//需要拆成固定片段的
|
||||||
|
if (syntax.IsEncapsulated && fragmentCount == pixelData.NumberOfFrames && numberOfFrames > 1)
|
||||||
{
|
{
|
||||||
await request.File.SaveAsync(ms);
|
|
||||||
|
|
||||||
|
|
||||||
|
var newFragments = new DicomOtherByteFragment(DicomTag.PixelData);
|
||||||
|
|
||||||
|
#region test
|
||||||
|
//var newDicomFile = dicomFile.Clone();
|
||||||
|
|
||||||
|
//var newDataset = newDicomFile.Dataset;
|
||||||
|
|
||||||
|
//var dstPd = DicomPixelData.Create(newDataset, true);
|
||||||
|
|
||||||
|
//for (int i = 0; i < pixelData.NumberOfFrames; i++)
|
||||||
|
//{
|
||||||
|
// var frame = pixelData.GetFrame(i);
|
||||||
|
|
||||||
|
// dstPd.AddFrame(frame);
|
||||||
|
|
||||||
|
// var data = frame.Data;
|
||||||
|
// int offset = 0;
|
||||||
|
|
||||||
|
// while (offset < data.Length)
|
||||||
|
// {
|
||||||
|
// int size = Math.Min(fragmentSize, data.Length - offset);
|
||||||
|
// var buffer = new byte[size];
|
||||||
|
// Buffer.BlockCopy(data, offset, buffer, 0, size);
|
||||||
|
|
||||||
|
// newFragments.Fragments.Add(new MemoryByteBuffer(buffer));
|
||||||
|
|
||||||
|
// offset += size;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
//}
|
||||||
|
//var newOffsetTable = newDataset.GetDicomItem<DicomOtherByteFragment>(DicomTag.PixelData).OffsetTable;
|
||||||
|
|
||||||
|
//newFragments.OffsetTable.AddRange(newOffsetTable.ToArray());
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region test fo-dicom auto bot
|
||||||
|
//var newDicomFile = dicomFile.Clone();
|
||||||
|
|
||||||
|
//var newDataset = newDicomFile.Dataset;
|
||||||
|
|
||||||
|
//var dstPd = DicomPixelData.Create(newDataset, true);
|
||||||
|
|
||||||
|
//for (int i = 0; i < pixelData.NumberOfFrames; i++)
|
||||||
|
//{
|
||||||
|
// var frame = pixelData.GetFrame(i);
|
||||||
|
|
||||||
|
// dstPd.AddFrame(frame);
|
||||||
|
//}
|
||||||
|
//var newOffsetTable = newDataset.GetDicomItem<DicomOtherByteFragment>(DicomTag.PixelData).OffsetTable;
|
||||||
|
|
||||||
|
//Console.WriteLine(newOffsetTable.ToJsonStr());
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 最终使用
|
||||||
|
|
||||||
|
for (int n = 0; n < pixelData.NumberOfFrames; n++)
|
||||||
|
{
|
||||||
|
var frameData = pixelData.GetFrame(n); // 获取完整一帧
|
||||||
|
var data = frameData.Data;
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
bot.Add(botOffset);
|
||||||
|
|
||||||
|
botOffset += (uint)data.Length;
|
||||||
|
|
||||||
|
|
||||||
|
while (offset < data.Length)
|
||||||
|
{
|
||||||
|
botOffset += 8;
|
||||||
|
|
||||||
|
|
||||||
|
int size = Math.Min(fragmentSize, data.Length - offset);
|
||||||
|
var buffer = new byte[size];
|
||||||
|
Buffer.BlockCopy(data, offset, buffer, 0, size);
|
||||||
|
|
||||||
|
newFragments.Fragments.Add(new MemoryByteBuffer(buffer));
|
||||||
|
|
||||||
|
offset += size;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//保留原始偏移表
|
||||||
|
|
||||||
|
if (originOffsetTable.Count == pixelData.NumberOfFrames)
|
||||||
|
{
|
||||||
|
newFragments.OffsetTable.AddRange(originOffsetTable.ToArray());
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newFragments.OffsetTable.AddRange(bot.ToArray());
|
||||||
|
|
||||||
|
//Console.WriteLine(bot.ToJsonStr());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
dicomFile.Dataset.AddOrUpdate(newFragments);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
//传递过来的就是拆分的,但是是没有偏移表的,我需要自己创建偏移表,不然生成缩略图失败
|
||||||
|
else if (syntax.IsEncapsulated && fragmentCount > pixelData.NumberOfFrames && originOffsetTable.Count == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint offset = 0;
|
||||||
|
|
||||||
|
bot.Add(offset);
|
||||||
|
|
||||||
|
var fistSize = frag.Fragments.FirstOrDefault()?.Size ?? 0;
|
||||||
|
|
||||||
|
//和上一个大小不一样
|
||||||
|
var isDiffrentBefore = false;
|
||||||
|
|
||||||
|
uint count = 0;
|
||||||
|
|
||||||
|
// 假设你知道每帧对应的 fragment 数量
|
||||||
|
foreach (var frameFragments in frag.Fragments)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (frameFragments.Size == fistSize)
|
||||||
|
{
|
||||||
|
isDiffrentBefore = false;
|
||||||
|
// 累加这一帧所有 fragment 的大小
|
||||||
|
offset += (uint)frameFragments.Size;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offset += (uint)frameFragments.Size;
|
||||||
|
isDiffrentBefore = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDiffrentBefore)
|
||||||
|
{
|
||||||
|
//每个Fragment 也占用字节
|
||||||
|
offset += 8 * count;
|
||||||
|
bot.Add(offset);
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.RemoveAt(bot.Count - 1);
|
||||||
|
// 设置到新的 PixelData
|
||||||
|
frag.OffsetTable.AddRange(bot.ToArray());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception mutiEx)
|
||||||
|
{
|
||||||
|
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 处理多帧失败,上传原始文件:{mutiEx.ToString()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 本地测试
|
||||||
|
//// --- 保存到本地文件测试 ---
|
||||||
|
//var localPath = @"D:\TestDicom.dcm";
|
||||||
|
//using (var fs = new FileStream(localPath, FileMode.Create, FileAccess.Write))
|
||||||
|
//{
|
||||||
|
// ms.CopyTo(fs);
|
||||||
|
//}
|
||||||
|
//return new DicomCStoreResponse(request, DicomStatus.Success);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
// 直接写入内存
|
||||||
|
await using var ms = new MemoryStream();
|
||||||
|
await dicomFile.SaveAsync(ms);
|
||||||
|
ms.Position = 0;
|
||||||
|
|
||||||
//irc 从路径最后一截取Guid
|
//irc 从路径最后一截取Guid
|
||||||
storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false);
|
storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false);
|
||||||
|
|
||||||
fileSize = ms.Length;
|
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}");
|
var @lock = _distributedLockProvider.CreateLock($"{studyInstanceUid}");
|
||||||
@@ -307,12 +776,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.Dataset, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE,fileSize);
|
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(dicomFile, storeRelativePath, Association.CallingAE, Association.CalledAE, fileSize);
|
||||||
|
|
||||||
if (!_SCPStudyIdList.Contains(scpStudyId))
|
|
||||||
{
|
|
||||||
_SCPStudyIdList.Add(scpStudyId);
|
|
||||||
}
|
|
||||||
|
|
||||||
var series = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
|
var series = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
|
||||||
|
|
||||||
@@ -323,30 +787,91 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
// 生成缩略图
|
// 生成缩略图
|
||||||
using (var memoryStream = new MemoryStream())
|
using (var memoryStream = new MemoryStream())
|
||||||
{
|
{
|
||||||
DicomImage image = new DicomImage(request.Dataset);
|
DicomImage image = new DicomImage(dicomFile.Dataset);
|
||||||
|
|
||||||
var sharpimage = image.RenderImage().AsSharpImage();
|
var sharpimage = image.RenderImage().AsSharpImage();
|
||||||
sharpimage.Save(memoryStream, new JpegEncoder());
|
sharpimage.Save(memoryStream, new JpegEncoder());
|
||||||
|
|
||||||
// 上传缩略图到 OSS
|
// 上传缩略图到 OSS
|
||||||
|
|
||||||
var seriesPath = await ossService.UploadToOSSAsync(memoryStream, ossFolderPath, seriesId.ToString() + ".preview.jpg", false);
|
var seriesPath = await ossService.UploadToOSSAsync(memoryStream, ossFolderPath, $"{seriesId.ToString()}_{instanceId.ToString()}.preview.jpg", false);
|
||||||
|
|
||||||
Console.WriteLine(seriesPath + " Id: " + seriesId);
|
|
||||||
|
|
||||||
series.ImageResizePath = seriesPath;
|
series.ImageResizePath = seriesPath;
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
//await _seriesRepository.BatchUpdateNoTrackingAsync(t => t.Id == seriesId, u => new SCPSeries() { ImageResizePath = seriesPath });
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await _seriesRepository.SaveChangesAsync();
|
await _seriesRepository.SaveChangesAsync();
|
||||||
|
|
||||||
|
if (_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
|
||||||
|
{
|
||||||
|
var find = _ImageUploadList.FirstOrDefault(t => t.StudyInstanceUid.Equals(studyInstanceUid));
|
||||||
|
|
||||||
|
|
||||||
|
find.SuccessImageCount++;
|
||||||
|
|
||||||
|
if (!find.PatientNameList.Any(t => t == patientIdStr) && patientIdStr.IsNotNullOrEmpty())
|
||||||
|
{
|
||||||
|
find.PatientNameList.Add(patientIdStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//首次 (默认是Guid 空,数据库归档出了Id)
|
||||||
|
if (find.SCPStudyId != scpStudyId)
|
||||||
|
{
|
||||||
|
find.SCPStudyId = scpStudyId;
|
||||||
|
|
||||||
|
#region 给检查打课题组标签
|
||||||
|
|
||||||
|
//添加课题组标签
|
||||||
|
if (CurrentHospitalGroup != null)
|
||||||
|
{
|
||||||
|
if (!_studyGroupRepository.Any(t => t.SCPStudyId == scpStudyId && t.HospitalGroupId == CurrentHospitalGroup.Id))
|
||||||
|
{
|
||||||
|
await _studyGroupRepository.AddAsync(new SCPStudyHospitalGroup() { SCPStudyId = scpStudyId, HospitalGroupId = CurrentHospitalGroup.Id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var findCmoveInfo = _cmoveStudyRepository.Where(t => t.StudyInstanceUIDList.Any(c => c == studyInstanceUid)).OrderByDescending(t => t.CreateTime).FirstOrDefault();
|
||||||
|
|
||||||
|
if (findCmoveInfo != null)
|
||||||
|
{
|
||||||
|
foreach (var item in findCmoveInfo.HopitalGroupIdList)
|
||||||
|
{
|
||||||
|
if (!_studyGroupRepository.Any(t => t.SCPStudyId == scpStudyId && t.HospitalGroupId == item))
|
||||||
|
{
|
||||||
|
await _studyGroupRepository.AddAsync(new SCPStudyHospitalGroup() { SCPStudyId = scpStudyId, HospitalGroupId = item });
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Logger.Warning($"未找到{studyInstanceUid}的Cmove记录");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
||||||
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 传输处理异常:{ex.ToString()}");
|
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 传输处理异常:{ex.ToString()}");
|
||||||
|
|
||||||
|
if (_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
|
||||||
|
{
|
||||||
|
var find = _ImageUploadList.FirstOrDefault(t => t.StudyInstanceUid.Equals(studyInstanceUid));
|
||||||
|
|
||||||
|
find.FailedImageCount++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -356,12 +881,27 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
//监控信息设置
|
//监控信息设置
|
||||||
_upload.FileCount++;
|
_upload.FileCount++;
|
||||||
_upload.FileSize = _upload.FileSize + fileSize;
|
_upload.FileSize = _upload.FileSize + fileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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}");
|
||||||
|
}
|
||||||
|
|
||||||
return new DicomCStoreResponse(request, DicomStatus.Success);
|
return new DicomCStoreResponse(request, DicomStatus.Success);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Task OnCStoreRequestExceptionAsync(string tempFileName, Exception e)
|
public Task OnCStoreRequestExceptionAsync(string tempFileName, Exception e)
|
||||||
{
|
{
|
||||||
|
Log.Logger.Warning($"CStoreRequestException {tempFileName} {e?.Message} {e?.InnerException?.Message}");
|
||||||
|
|
||||||
// let library handle logging and error response
|
// let library handle logging and error response
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
using IRaCIS.Core.Domain.Models;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.SCP.Service;
|
||||||
|
|
||||||
|
|
||||||
|
public static class CacheKeys
|
||||||
|
{
|
||||||
|
//项目缓存
|
||||||
|
public static string Trial(string trialIdStr) => $"TrialId:{trialIdStr}";
|
||||||
|
|
||||||
|
//检查编号递增锁
|
||||||
|
public static string TrialStudyMaxCode(Guid trialId) => $"TrialStudyMaxCode:{trialId}";
|
||||||
|
|
||||||
|
public static string TrialStudyUidUploading(Guid trialId, string studyUid) => $"TrialStudyUid:{trialId}_{studyUid}";
|
||||||
|
//CRC上传影像提交锁key
|
||||||
|
public static string TrialStudyUidDBLock(Guid trialId, string studyUid) => $"TrialStudyUidDBLock:{trialId}_{studyUid}";
|
||||||
|
|
||||||
|
public static string TrialTaskStudyUidUploading(Guid trialId, Guid visiTaskId, string studyUid) => $"TrialStudyUid:{trialId}_{visiTaskId}_{studyUid}";
|
||||||
|
//影像后处理上传提交锁key
|
||||||
|
public static string TrialTaskStudyUidDBLock(Guid trialId, Guid visiTaskId, string studyUid) => $"TrialTaskStudyUidDBLock:{trialId}_{visiTaskId}_{studyUid}";
|
||||||
|
//系统匿名化
|
||||||
|
public static string SystemAnonymization => $"SystemAnonymization";
|
||||||
|
//前端国际化
|
||||||
|
public static string FrontInternational => $"FrontInternationalList";
|
||||||
|
|
||||||
|
//登录挤账号
|
||||||
|
public static string UserToken(Guid userId) => $"UserToken:{userId}";
|
||||||
|
|
||||||
|
//超时没请求接口自动退出
|
||||||
|
public static string UserAutoLoginOut(Guid userId) => $"UserAutoLoginOut:{userId}";
|
||||||
|
|
||||||
|
|
||||||
|
public static string UserDisable(Guid userId) => $"UserDisable:{userId}";
|
||||||
|
|
||||||
|
public static string UserRoleDisable(Guid userRoleId) => $"UserRoleDisable:{userRoleId}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用户登录错误 限制登录
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userName"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string UserLoginError(string userName) => $"login-failures:{userName}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 跳过阅片
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string SkipReadingCacheKey(Guid userId) => $"{userId}SkipReadingCache";
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开始阅片时间
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string StartReadingTimeKey(Guid userId) => $"{userId}StartReadingTime";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开始休息时间
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string StartRestTime(Guid userId) => $"{userId}StartRestTime";
|
||||||
|
|
||||||
|
//每个用户 每个浏览器独立时间
|
||||||
|
public static string UserMFAVerifyPass(Guid userId, string browserFingerprint) => $"UserMFAVerifyPass:{userId}:{browserFingerprint}";
|
||||||
|
|
||||||
|
public static string TrialSiteInfo(Guid trialSiteId) => $"{trialSiteId}TrialSiteInfo";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CacheHelper
|
||||||
|
{
|
||||||
|
public static async Task<string?> GetTrialStatusAsync(Guid trialId, IRepository<Trial> _trialRepository)
|
||||||
|
{
|
||||||
|
var statusStr = await _trialRepository.Where(t => t.Id == trialId, ignoreQueryFilters: true).Select(t => t.TrialStatusStr).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
return statusStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TrialSiteInfoDTO
|
||||||
|
{
|
||||||
|
public string TrialSiteCode { get; set; }
|
||||||
|
public string TrialCode { get; set; }
|
||||||
|
}
|
||||||
|
public static async Task<TrialSiteInfoDTO> GetTrialSiteInfo(Guid trialSiteId, IRepository<TrialSite> _trialSiteRepository)
|
||||||
|
{
|
||||||
|
var obj = await _trialSiteRepository.Where(t => t.Id == trialSiteId, ignoreQueryFilters: true).Select(t => new TrialSiteInfoDTO { TrialCode= t.Trial.TrialCode, TrialSiteCode= t.TrialSiteCode }).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
return obj??new TrialSiteInfoDTO();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<List<SystemAnonymization>> GetSystemAnonymizationListAsync(IRepository<SystemAnonymization> _systemAnonymizationRepository)
|
||||||
|
{
|
||||||
|
var list = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync();
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,38 +11,20 @@ using FellowOakDicom.Network;
|
|||||||
using IRaCIS.Core.SCP.Service;
|
using IRaCIS.Core.SCP.Service;
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using System.Runtime.Intrinsics.X86;
|
|
||||||
using Serilog.Sinks.File;
|
using Serilog.Sinks.File;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using ZiggyCreatures.Caching.Fusion;
|
||||||
|
|
||||||
namespace IRaCIS.Core.SCP.Service
|
namespace IRaCIS.Core.SCP.Service
|
||||||
{
|
{
|
||||||
public class DicomArchiveService : BaseService, IDicomArchiveService
|
public class DicomArchiveService(IRepository<SCPPatient> _patientRepository,
|
||||||
|
IRepository<SCPStudy> _studyRepository,
|
||||||
|
IRepository<SCPSeries> _seriesRepository,
|
||||||
|
IRepository<SCPInstance> _instanceRepository
|
||||||
|
) : 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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -52,8 +34,10 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
/// <param name="dataset"></param>
|
/// <param name="dataset"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
public async Task<Guid> ArchiveDicomFileAsync(DicomDataset dataset, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize)
|
public async Task<Guid> ArchiveDicomFileAsync(DicomFile dicomFile, string fileRelativePath, string callingAE, string calledAE, long fileSize)
|
||||||
{
|
{
|
||||||
|
var dataset = dicomFile.Dataset;
|
||||||
|
|
||||||
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
||||||
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
|
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
|
||||||
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
|
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
|
||||||
@@ -61,9 +45,9 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
|
string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
|
||||||
|
|
||||||
//Guid patientId= IdentifierHelper.CreateGuid(patientIdStr);
|
//Guid patientId= IdentifierHelper.CreateGuid(patientIdStr);
|
||||||
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid,trialId.ToString());
|
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid);
|
||||||
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, trialId.ToString());
|
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid);
|
||||||
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, trialId.ToString());
|
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid);
|
||||||
|
|
||||||
var isStudyNeedAdd = false;
|
var isStudyNeedAdd = false;
|
||||||
var isSeriesNeedAdd = false;
|
var isSeriesNeedAdd = false;
|
||||||
@@ -74,15 +58,16 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
|
|
||||||
//using (@lock.Acquire())
|
//using (@lock.Acquire())
|
||||||
{
|
{
|
||||||
var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr && t.TrialSiteId==trialSiteId );
|
var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr);
|
||||||
var findStudy = await _studyRepository.FirstOrDefaultAsync(t => t.Id == studyId);
|
var findStudy = await _studyRepository.FirstOrDefaultAsync(t => t.Id == studyId);
|
||||||
var findSerice = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
|
var findSerice = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
|
||||||
var findInstance = await _instanceRepository.FirstOrDefaultAsync(t => t.Id == instanceId);
|
var findInstance = await _instanceRepository.FirstOrDefaultAsync(t => t.Id == instanceId);
|
||||||
|
|
||||||
|
|
||||||
DateTime? studyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.StudyTime).TimeOfDay);
|
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
|
//先传输了,修改了患者编号的,又传输了没有修改患者编号的,导致后传输的没有修改患者编号的下面的检查为0
|
||||||
if (findPatient == null && findStudy==null)
|
if (findPatient == null /*&& findStudy == null*/)
|
||||||
{
|
{
|
||||||
isPatientNeedAdd = true;
|
isPatientNeedAdd = true;
|
||||||
|
|
||||||
@@ -90,8 +75,6 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
findPatient = new SCPPatient()
|
findPatient = new SCPPatient()
|
||||||
{
|
{
|
||||||
Id = NewId.NextSequentialGuid(),
|
Id = NewId.NextSequentialGuid(),
|
||||||
TrialId=trialId,
|
|
||||||
TrialSiteId=trialSiteId,
|
|
||||||
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
|
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
|
||||||
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
|
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
|
||||||
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
|
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
|
||||||
@@ -117,20 +100,6 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
{
|
{
|
||||||
findPatient.PatientBirthDate = birthDateStr;
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -151,6 +120,32 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
}
|
}
|
||||||
|
|
||||||
findPatient.LatestPushTime = DateTime.Now;
|
findPatient.LatestPushTime = DateTime.Now;
|
||||||
|
findPatient.PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
|
||||||
|
findPatient.PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty);
|
||||||
|
findPatient.PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty);
|
||||||
|
findPatient.PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty);
|
||||||
|
|
||||||
|
if (findPatient.PatientBirthDate.Length == 8)
|
||||||
|
{
|
||||||
|
var birthDateStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}-{findPatient.PatientBirthDate[4]}{findPatient.PatientBirthDate[5]}-{findPatient.PatientBirthDate[6]}{findPatient.PatientBirthDate[7]}";
|
||||||
|
|
||||||
|
var yearStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}";
|
||||||
|
|
||||||
|
int year = 0;
|
||||||
|
|
||||||
|
var canParse = int.TryParse(yearStr, out year);
|
||||||
|
|
||||||
|
if (canParse && year > 1900)
|
||||||
|
{
|
||||||
|
findPatient.PatientBirthDate = birthDateStr;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
findPatient.PatientBirthDate = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (findStudy == null)
|
if (findStudy == null)
|
||||||
@@ -163,10 +158,12 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
|
|
||||||
PatientId = findPatient.Id,
|
PatientId = findPatient.Id,
|
||||||
Id = studyId,
|
Id = studyId,
|
||||||
TrialId = trialId,
|
|
||||||
TrialSiteId = trialSiteId,
|
|
||||||
StudyInstanceUid = studyInstanceUid,
|
StudyInstanceUid = studyInstanceUid,
|
||||||
StudyTime = studyTime,
|
StudyTime = studyTime,
|
||||||
|
DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty),
|
||||||
|
DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty),
|
||||||
|
|
||||||
|
|
||||||
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||||
//ModalityForEdit = modalityForEdit,
|
//ModalityForEdit = modalityForEdit,
|
||||||
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
|
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
|
||||||
@@ -201,6 +198,20 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
findStudy.PatientBirthDate = $"{findStudy.PatientBirthDate[0]}{findStudy.PatientBirthDate[1]}{findStudy.PatientBirthDate[2]}{findStudy.PatientBirthDate[3]}-{findStudy.PatientBirthDate[4]}{findStudy.PatientBirthDate[5]}-{findStudy.PatientBirthDate[6]}{findStudy.PatientBirthDate[7]}";
|
findStudy.PatientBirthDate = $"{findStudy.PatientBirthDate[0]}{findStudy.PatientBirthDate[1]}{findStudy.PatientBirthDate[2]}{findStudy.PatientBirthDate[3]}-{findStudy.PatientBirthDate[4]}{findStudy.PatientBirthDate[5]}-{findStudy.PatientBirthDate[6]}{findStudy.PatientBirthDate[7]}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
findStudy.DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty);
|
||||||
|
findStudy.DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty);
|
||||||
|
findStudy.CalledAE = calledAE;
|
||||||
|
findStudy.CallingAE = callingAE;
|
||||||
|
findStudy.PatientIdStr = patientIdStr;
|
||||||
|
findStudy.PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
|
||||||
|
findStudy.PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty);
|
||||||
|
findStudy.PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty);
|
||||||
|
findStudy.UpdateTime = DateTime.Now;
|
||||||
|
|
||||||
|
await _patientRepository.BatchUpdateNoTrackingAsync(t => t.Id == findStudy.PatientId, u => new SCPPatient() { LatestPushTime = DateTime.Now });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (findSerice == null)
|
if (findSerice == null)
|
||||||
@@ -218,6 +229,9 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
//SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay),
|
//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 = 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),
|
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay),
|
||||||
|
DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty),
|
||||||
|
DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty),
|
||||||
|
|
||||||
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||||
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
|
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
|
||||||
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
||||||
@@ -239,7 +253,20 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
|
|
||||||
++findStudy.SeriesCount;
|
++findStudy.SeriesCount;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
findSerice.DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty);
|
||||||
|
findSerice.DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty);
|
||||||
|
findSerice.UpdateTime = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
var transferSyntaxUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty);
|
||||||
|
|
||||||
|
var isEncapsulated = false;
|
||||||
|
if (transferSyntaxUID.IsNotNullOrEmpty())
|
||||||
|
{
|
||||||
|
isEncapsulated = DicomTransferSyntax.Lookup(DicomUID.Parse(transferSyntaxUID)).IsEncapsulated;
|
||||||
|
}
|
||||||
|
|
||||||
if (findInstance == null)
|
if (findInstance == null)
|
||||||
{
|
{
|
||||||
@@ -253,6 +280,12 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
SeriesInstanceUid = findSerice.SeriesInstanceUid,
|
SeriesInstanceUid = findSerice.SeriesInstanceUid,
|
||||||
|
|
||||||
SopInstanceUid = sopInstanceUid,
|
SopInstanceUid = sopInstanceUid,
|
||||||
|
SOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty),
|
||||||
|
MediaStorageSOPClassUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty),
|
||||||
|
TransferSyntaxUID = transferSyntaxUID,
|
||||||
|
MediaStorageSOPInstanceUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty),
|
||||||
|
IsEncapsulated = isEncapsulated,
|
||||||
|
|
||||||
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
|
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 = 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 = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.ContentDate) + dataset.GetSingleValue<string>(DicomTag.ContentTime), out DateTime dt) ? dt : null,
|
||||||
@@ -264,7 +297,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0),
|
SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0),
|
||||||
|
|
||||||
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
||||||
NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 0),
|
NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 1),
|
||||||
PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty),
|
PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty),
|
||||||
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
||||||
FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty),
|
FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty),
|
||||||
@@ -274,12 +307,20 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
Path = fileRelativePath,
|
Path = fileRelativePath,
|
||||||
|
|
||||||
FileSize = fileSize,
|
FileSize = fileSize,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
++findStudy.InstanceCount;
|
++findStudy.InstanceCount;
|
||||||
++findSerice.InstanceCount;
|
++findSerice.InstanceCount;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
findInstance.SOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty);
|
||||||
|
findInstance.MediaStorageSOPClassUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty);
|
||||||
|
findInstance.TransferSyntaxUID = transferSyntaxUID;
|
||||||
|
findInstance.MediaStorageSOPInstanceUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty);
|
||||||
|
findInstance.IsEncapsulated = isEncapsulated;
|
||||||
|
findInstance.UpdateTime = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
if (isPatientNeedAdd)
|
if (isPatientNeedAdd)
|
||||||
{
|
{
|
||||||
@@ -298,6 +339,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
{
|
{
|
||||||
await _seriesRepository.AddAsync(findSerice);
|
await _seriesRepository.AddAsync(findSerice);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInstanceNeedAdd)
|
if (isInstanceNeedAdd)
|
||||||
{
|
{
|
||||||
await _instanceRepository.AddAsync(findInstance);
|
await _instanceRepository.AddAsync(findInstance);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
{
|
{
|
||||||
public interface IDicomArchiveService
|
public interface IDicomArchiveService
|
||||||
{
|
{
|
||||||
Task<Guid> ArchiveDicomFileAsync(DicomDataset dicomDataset,Guid trialId,Guid trialSiteId, string fileRelativePath,string callingAE,string calledAE,long fileSize);
|
Task<Guid> ArchiveDicomFileAsync(DicomFile dicomFile,string fileRelativePath,string callingAE,string calledAE,long fileSize);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using MassTransit;
|
|||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Minio;
|
using Minio;
|
||||||
using Minio.DataModel.Args;
|
using Minio.DataModel.Args;
|
||||||
|
using System.Net;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
@@ -118,7 +119,7 @@ public class AWSTempToken
|
|||||||
public string SecretAccessKey { get; set; }
|
public string SecretAccessKey { get; set; }
|
||||||
public string BucketName { get; set; }
|
public string BucketName { get; set; }
|
||||||
public string ViewEndpoint { get; set; }
|
public string ViewEndpoint { get; set; }
|
||||||
public DateTime Expiration { get; set; }
|
public DateTime? Expiration { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ObjectStoreUse
|
public enum ObjectStoreUse
|
||||||
@@ -216,9 +217,19 @@ public class OSSService : IOSSService
|
|||||||
.WithBucket(minIOConfig.BucketName)
|
.WithBucket(minIOConfig.BucketName)
|
||||||
.WithObject(ossRelativePath)
|
.WithObject(ossRelativePath)
|
||||||
.WithStreamData(memoryStream)
|
.WithStreamData(memoryStream)
|
||||||
|
|
||||||
.WithObjectSize(memoryStream.Length);
|
.WithObjectSize(memoryStream.Length);
|
||||||
|
|
||||||
await minioClient.PutObjectAsync(putObjectArgs);
|
var putResponse = await minioClient.PutObjectAsync(putObjectArgs);
|
||||||
|
|
||||||
|
if (putResponse.ResponseStatusCode == HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new BusinessValidationFailedException($"上传失败ResponseStatusCode:{putResponse.ResponseStatusCode}{putResponse.ResponseContent}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,317 @@
|
|||||||
|
using FellowOakDicom;
|
||||||
|
using FellowOakDicom.Imaging;
|
||||||
|
using FellowOakDicom.Imaging.Codec;
|
||||||
|
using FellowOakDicom.Network;
|
||||||
|
using IRaCIS.Core.Domain.Models;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using IRaCIS.Core.Infrastructure;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using IRaCIS.Core.SCP.Service;
|
||||||
|
using MassTransit;
|
||||||
|
using Medallion.Threading;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||||
|
using System.Data;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.SCP.Service
|
||||||
|
{
|
||||||
|
public interface IPatientStudyService
|
||||||
|
{
|
||||||
|
Task<IResponseOutput> AutoBindingPatientStudyVisitAsync(List<Guid> scpStudyIdList);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ApiExplorerSettings(GroupName = "Trial")]
|
||||||
|
public class PatientStudyService : BaseService, IPatientStudyService
|
||||||
|
{
|
||||||
|
private readonly IRepository<SCPStudySubjectVisit> _studySubjectVisitRepository;
|
||||||
|
private readonly IRepository<SubjectPatient> _subjectPatientRepository;
|
||||||
|
private readonly IRepository<Trial> _trialRepository;
|
||||||
|
private readonly IRepository<SCPPatient> _patientRepository;
|
||||||
|
private readonly IRepository<SCPStudy> _studyRepository;
|
||||||
|
private readonly IRepository<Subject> _subjectRepository;
|
||||||
|
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
|
||||||
|
private readonly IDistributedLockProvider _distributedLockProvider;
|
||||||
|
|
||||||
|
public PatientStudyService(IRepository<SCPStudySubjectVisit> studySubjectVisitRepository, IRepository<SCPStudy> studyRepository, IRepository<SubjectPatient> subjectPatientRepository, IRepository<Trial> trialRepository, IRepository<SCPPatient> patientRepository, IRepository<Subject> subjectRepository, IRepository<SubjectVisit> subjectVisitRepository, IDistributedLockProvider distributedLockProvider)
|
||||||
|
{
|
||||||
|
_studySubjectVisitRepository = studySubjectVisitRepository;
|
||||||
|
_studyRepository = studyRepository;
|
||||||
|
_subjectPatientRepository = subjectPatientRepository;
|
||||||
|
_trialRepository = trialRepository;
|
||||||
|
_patientRepository = patientRepository;
|
||||||
|
_subjectRepository = subjectRepository;
|
||||||
|
_subjectVisitRepository = subjectVisitRepository;
|
||||||
|
_distributedLockProvider = distributedLockProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
[AllowAnonymous]
|
||||||
|
public async Task<IResponseOutput> TestImage(string folderPath)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!Directory.Exists(folderPath))
|
||||||
|
return ResponseOutput.Ok("目录不存在");
|
||||||
|
|
||||||
|
// 获取所有 .dcm 文件
|
||||||
|
var dicomFiles = Directory.GetFiles(folderPath);
|
||||||
|
|
||||||
|
foreach (var fileFullPath in dicomFiles)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var file = await DicomFile.OpenAsync(fileFullPath);
|
||||||
|
|
||||||
|
|
||||||
|
// 生成缩略图
|
||||||
|
using (var memoryStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
DicomImage image = new DicomImage(file.Dataset);
|
||||||
|
|
||||||
|
var sharpimage = image.RenderImage().AsSharpImage();
|
||||||
|
sharpimage.Save(memoryStream, new JpegEncoder());
|
||||||
|
|
||||||
|
|
||||||
|
// 关键点:一定要回到开头
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
|
||||||
|
using (var fileStream = File.Create($"{fileFullPath}.jpg"))
|
||||||
|
{
|
||||||
|
await memoryStream.CopyToAsync(fileStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return ResponseOutput.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AuToBindingStudyInfo
|
||||||
|
{
|
||||||
|
public Guid SCPStudyId { get; set; }
|
||||||
|
public DateTime? StudyTime { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DealAutoBindingStudyAsync(Guid trialId, Guid subjectId, List<AuToBindingStudyInfo> studyList, decimal? startBindVisitNum = null)
|
||||||
|
{
|
||||||
|
|
||||||
|
//自动创建访视 和检查绑定
|
||||||
|
|
||||||
|
//1. 查询已存在的访视
|
||||||
|
var subjectAllVisitList = await _subjectVisitRepository.Where(t => t.SubjectId == subjectId)
|
||||||
|
.Select(t => new
|
||||||
|
{
|
||||||
|
t.SubjectId,
|
||||||
|
SubjectVisitId = t.Id,
|
||||||
|
t.SubmitState,
|
||||||
|
VisitNum = t.VisitNum,
|
||||||
|
MaxStudyTime = t.SCPStudySubjectVisitList.Max(t => t.SCPStudy.StudyTime),
|
||||||
|
MinStudyTime = t.SCPStudySubjectVisitList.Min(t => t.SCPStudy.StudyTime)
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
|
||||||
|
//2、获取项目配置
|
||||||
|
var trialconfig = _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.BlindBaseLineName, t.BlindFollowUpPrefix }).FirstOrDefault();
|
||||||
|
|
||||||
|
//3、 未提交的最小的访视号 从这个访视开始绑定
|
||||||
|
|
||||||
|
decimal subjectMaxVisitNum = 0;
|
||||||
|
|
||||||
|
if (startBindVisitNum == null)
|
||||||
|
{
|
||||||
|
if (subjectAllVisitList.Any(t => t.SubmitState != SubmitStateEnum.Submitted))
|
||||||
|
{
|
||||||
|
subjectMaxVisitNum = subjectAllVisitList.Where(t => t.SubmitState != SubmitStateEnum.Submitted).MinOrDefault(t => t.VisitNum);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//没有未提交的,那么开始绑定的就是已提交的加1
|
||||||
|
subjectMaxVisitNum = subjectAllVisitList.Any() ? subjectAllVisitList.Last().VisitNum + 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subjectMaxVisitNum = startBindVisitNum.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//var subjectMaxVisitNum = startBindVisitNum == null ? subjectAllVisitList.Where(t => t.SubmitState != SubmitStateEnum.Submitted).MinOrDefault(t => t.VisitNum) : startBindVisitNum.Value;
|
||||||
|
|
||||||
|
|
||||||
|
List<(int VisitCount, Guid SCPStudyId)> visits = new List<(int, Guid)>();
|
||||||
|
|
||||||
|
int visitCount = 0;
|
||||||
|
|
||||||
|
DateTime? lastVisitTime = null;
|
||||||
|
|
||||||
|
foreach (var study in studyList)
|
||||||
|
{
|
||||||
|
if (lastVisitTime == null || (study.StudyTime - lastVisitTime.Value).Value.TotalDays >= 15)
|
||||||
|
{
|
||||||
|
// 当前时间点与上一个访视时间点间隔大于等于 15 天,需要建立一个新的访视
|
||||||
|
visitCount++;
|
||||||
|
|
||||||
|
visits.Add((visitCount, study.SCPStudyId));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
visits.Add((visitCount, study.SCPStudyId));
|
||||||
|
}
|
||||||
|
|
||||||
|
lastVisitTime = study.StudyTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
//4、生成访视 并且绑定
|
||||||
|
|
||||||
|
for (int i = 0; i < visitCount; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
var bindSubjectVisitId = Guid.Empty;
|
||||||
|
|
||||||
|
var bindVisitNum = i + subjectMaxVisitNum;
|
||||||
|
|
||||||
|
var existSubjectVisit = subjectAllVisitList.FirstOrDefault(t => t.SubjectId == subjectId && t.VisitNum == bindVisitNum);
|
||||||
|
|
||||||
|
if (existSubjectVisit == null)
|
||||||
|
{
|
||||||
|
bindSubjectVisitId = NewId.NextGuid();
|
||||||
|
|
||||||
|
//基线
|
||||||
|
if (bindVisitNum == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
await _subjectVisitRepository.AddAsync(new SubjectVisit() { TrialId = trialId, SubjectId = subjectId, VisitName = trialconfig.BlindBaseLineName, VisitNum = bindVisitNum, Id = bindSubjectVisitId, SubmitState = SubmitStateEnum.ToSubmit, IsBaseLine = true });
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _subjectVisitRepository.AddAsync(new SubjectVisit() { TrialId = trialId, SubjectId = subjectId, VisitName = trialconfig.BlindFollowUpPrefix + $" {(int)bindVisitNum}", VisitNum = bindVisitNum, Id = bindSubjectVisitId, SubmitState = SubmitStateEnum.ToSubmit });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bindSubjectVisitId = existSubjectVisit.SubjectVisitId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var currentVisitStudyList = visits.Where(t => t.VisitCount == (i + 1)).ToList();
|
||||||
|
|
||||||
|
foreach (var item in currentVisitStudyList)
|
||||||
|
{
|
||||||
|
//访视状态为未提交才绑定
|
||||||
|
if (!subjectAllVisitList.Any(t => t.SubjectId == subjectId && t.SubjectVisitId == bindSubjectVisitId && t.SubmitState == SubmitStateEnum.Submitted))
|
||||||
|
{
|
||||||
|
var find = await _subjectVisitRepository.FindAsync(bindSubjectVisitId);
|
||||||
|
find.SubmitState = SubmitStateEnum.ToSubmit;
|
||||||
|
await _studySubjectVisitRepository.AddAsync(new SCPStudySubjectVisit() { TrialId = trialId, SubjectVisitId = bindSubjectVisitId, SCPStudyId = item.SCPStudyId, SubjectId = subjectId });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await _subjectPatientRepository.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 传输完成后,自动给检查绑定访视
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inCommand"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IResponseOutput> AutoBindingPatientStudyVisitAsync(List<Guid> scpStudyIdList)
|
||||||
|
{
|
||||||
|
//一个检查 可能绑定到不同的项目的不同subject 有的该检查已绑定访视,有的该检查绑定了访视
|
||||||
|
|
||||||
|
var query = from scpStudy in _studyRepository.Where(t => scpStudyIdList.Contains(t.Id))
|
||||||
|
join subjectPatient in _subjectPatientRepository.AsQueryable()
|
||||||
|
on scpStudy.PatientId equals subjectPatient.PatientId
|
||||||
|
select new
|
||||||
|
{
|
||||||
|
subjectPatient.Subject.Status,
|
||||||
|
subjectPatient.Subject.TrialId,
|
||||||
|
subjectPatient.SubjectId,
|
||||||
|
subjectPatient.PatientId,
|
||||||
|
SCPStudyId = scpStudy.Id,
|
||||||
|
scpStudy.StudyTime
|
||||||
|
};
|
||||||
|
|
||||||
|
var list = query.ToList();
|
||||||
|
|
||||||
|
if (list.Count > 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
var subjectIdList = list.Select(t => t.SubjectId).ToList();
|
||||||
|
|
||||||
|
var allSubjectVisitList = await _subjectVisitRepository.Where(t => subjectIdList.Contains(t.SubjectId))
|
||||||
|
.Select(t => new { t.SubjectId, SubjectVisitId = t.Id, t.SubmitState, VisitNum = t.VisitNum, MaxStudyTime = t.SCPStudySubjectVisitList.Max(t => t.SCPStudy.StudyTime), MinStudyTime = t.SCPStudySubjectVisitList.Min(t => t.SCPStudy.StudyTime) })
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
foreach (var g in list.GroupBy(t => new { t.SubjectId, t.TrialId, t.Status }))
|
||||||
|
{
|
||||||
|
var subjectId = g.Key.SubjectId;
|
||||||
|
var trialId = g.Key.TrialId;
|
||||||
|
|
||||||
|
//访视结束,那么就不处理
|
||||||
|
if (g.Key.Status == SubjectStatus.EndOfVisit)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 预先处理1: 数据库可能有已存在的subject 患者绑定,在这里要一起考虑绑定
|
||||||
|
|
||||||
|
var dbPatientIdList = _subjectPatientRepository.Where(t => t.SubjectId == subjectId).Select(t => t.PatientId).ToList();
|
||||||
|
|
||||||
|
// 预先处理2: 删除未提交的所有绑定的检查记录,所有检查一起考虑绑定
|
||||||
|
|
||||||
|
await _studySubjectVisitRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState != SubmitStateEnum.Submitted);
|
||||||
|
|
||||||
|
//预处理3 找到该subjecct 已提交的访视的最大检查时间,绑定的检查时间要比这个时间要大
|
||||||
|
|
||||||
|
var maxStudyTime = allSubjectVisitList.Where(t => t.SubjectId == subjectId && t.SubmitState == SubmitStateEnum.Submitted).MaxOrDefault(t => t.MaxStudyTime);
|
||||||
|
|
||||||
|
|
||||||
|
// 预处理4: 处理需要绑定的检查
|
||||||
|
//获取 该受试者绑定患者已存在的检查,考虑要生成多少个访视,去除已提交的检查
|
||||||
|
|
||||||
|
var studyList = await _studyRepository.Where(t => dbPatientIdList.Contains(t.PatientId)
|
||||||
|
&& !t.SCPStudySubjectVisitList.Any(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState == SubmitStateEnum.Submitted))
|
||||||
|
.WhereIf(maxStudyTime != null, t => t.StudyTime > maxStudyTime)
|
||||||
|
.Select(t => new AuToBindingStudyInfo { SCPStudyId = t.Id, StudyTime = t.StudyTime }).OrderBy(t => t.StudyTime).ToListAsync();
|
||||||
|
|
||||||
|
await DealAutoBindingStudyAsync(trialId, subjectId, studyList);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
await _subjectVisitRepository.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
//将检查设置为传输结束
|
||||||
|
await _studyRepository.BatchUpdateNoTrackingAsync(t => scpStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
||||||
|
|
||||||
|
return ResponseOutput.Ok();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ObjectStoreService": {
|
||||||
|
"ObjectStoreUse": "MinIO",
|
||||||
|
"MinIO": {
|
||||||
|
"EndPoint": "47.102.87.183",
|
||||||
|
"Port": "9000",
|
||||||
|
"UseSSL": false,
|
||||||
|
"AccessKeyId": "fbStsVYCIPKHQneeqMwD",
|
||||||
|
"SecretAccessKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
|
||||||
|
"BucketName": "hir-images",
|
||||||
|
"ViewEndpoint": "http://47.102.87.18:9001/hir-images/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"RemoteNew": "Server=47.102.87.183,1434;Database=HIR_Prod;User ID=sa;Password=xc_123456;TrustServerCertificate=true",
|
||||||
|
"Hangfire": "Server=47.102.87.183,1434;Database=HIR_Prod_Hangfire;User ID=sa;Password=xc_123456;TrustServerCertificate=true"
|
||||||
|
},
|
||||||
|
"DicomSCPServiceConfig": {
|
||||||
|
"IsUploadImageAnonymization": true,
|
||||||
|
"IsSupportThirdService": true,
|
||||||
|
"IsForwardImageMultiThread": true,
|
||||||
|
"MultiThreadCount": 10,
|
||||||
|
"CalledAEList": [
|
||||||
|
"HIRAE",
|
||||||
|
"STORESCP"
|
||||||
|
],
|
||||||
|
"ServerPort": 11115
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ObjectStoreService": {
|
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
|
||||||
"AliyunOSS": {
|
|
||||||
"RegionId": "cn-shanghai",
|
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"AccessKeyId": "LTAI5tNRTsqL6aWmHkDmTwoH",
|
|
||||||
"AccessKeySecret": "7mtGz3qrYWI6JMMBZiLeC119VWicZH",
|
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/irc-oss-access",
|
|
||||||
"BucketName": "zy-irc-store",
|
|
||||||
"ViewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"Region": "oss-cn-shanghai",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"RemoteNew": "Server=prod_mssql_standard,1433;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=prod_mssql_standard,1433;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
|
|
||||||
"DicomSCPServiceConfig": {
|
|
||||||
"CalledAEList": [
|
|
||||||
"STORESCP"
|
|
||||||
],
|
|
||||||
"ServerPort": 11112
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ObjectStoreService": {
|
||||||
|
"ObjectStoreUse": "MinIO",
|
||||||
|
"MinIO": {
|
||||||
|
"EndPoint": "192.168.40.99",
|
||||||
|
"Port": "9000",
|
||||||
|
"UseSSL": false,
|
||||||
|
"AccessKeyId": "Jnywl9aIw83yewZIJKod",
|
||||||
|
"SecretAccessKey": "N83bTzoJGkg4OLW8x54IZRwwSvdxcdYi9UZ2BYII",
|
||||||
|
"BucketName": "tj-hir",
|
||||||
|
"ViewEndpoint": "http://192.168.40.99:9000/tj-hir"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"RemoteNew": "Server=192.168.40.98,1433;Database=TJ_Prod_HIR;User ID=sa;Password=xc_123456;TrustServerCertificate=true",
|
||||||
|
"Hangfire": "Server=192.168.40.98,1433;Database=TJ_Prod_HIR_Hangfire;User ID=sa;Password=xc_123456;TrustServerCertificate=true"
|
||||||
|
},
|
||||||
|
"DicomSCPServiceConfig": {
|
||||||
|
"CalledAEList": [
|
||||||
|
"STORESCP",
|
||||||
|
"HIRAE",
|
||||||
|
"Value2",
|
||||||
|
"Value3"
|
||||||
|
],
|
||||||
|
"ServerPort": 11112
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ObjectStoreService": {
|
||||||
|
"ObjectStoreUse": "MinIO",
|
||||||
|
"MinIO": {
|
||||||
|
"EndPoint": "106.14.89.110",
|
||||||
|
"Port": "9001",
|
||||||
|
"UseSSL": false,
|
||||||
|
"AccessKeyId": "fbStsVYCIPKHQneeqMwD",
|
||||||
|
"SecretAccessKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
|
||||||
|
"BucketName": "hir-test",
|
||||||
|
"ViewEndpoint": "http://106.14.89.110:9001/hir-test/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_HIR_New;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
|
"Hangfire": "Server=106.14.89.110,1435;Database=Test_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
|
},
|
||||||
|
"DicomSCPServiceConfig": {
|
||||||
|
"IsUploadImageAnonymization": false,
|
||||||
|
"IsSupportThirdService": true,
|
||||||
|
"IsForwardImageMultiThread": true,
|
||||||
|
"MultiThreadCount": 10,
|
||||||
|
"CalledAEList": [
|
||||||
|
"HIRAE",
|
||||||
|
"STORESCP"
|
||||||
|
],
|
||||||
|
"ServerPort": 11115
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ObjectStoreService": {
|
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
|
||||||
"AliyunOSS": {
|
|
||||||
"RegionId": "cn-shanghai",
|
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"AccessKeyId": "LTAI5tRRZehUp2V9pyTPtAJm",
|
|
||||||
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
|
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
|
|
||||||
"BucketName": "zy-irc-test-store",
|
|
||||||
"ViewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"Region": "oss-cn-shanghai",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
},
|
|
||||||
|
|
||||||
"MinIO": {
|
|
||||||
"endPoint": "106.14.89.110",
|
|
||||||
"port": "9001",
|
|
||||||
"useSSL": false,
|
|
||||||
"accessKey": "fbStsVYCIPKHQneeqMwD",
|
|
||||||
"secretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
|
|
||||||
"bucketName": "hir-test",
|
|
||||||
"viewEndpoint": "http://106.14.89.110:9001/hir-test/"
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
|
|
||||||
"DicomSCPServiceConfig": {
|
|
||||||
"CalledAEList": [
|
|
||||||
"STORESCP"
|
|
||||||
],
|
|
||||||
"ServerPort": 11112
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ObjectStoreService": {
|
||||||
|
"ObjectStoreUse": "MinIO",
|
||||||
|
"MinIO": {
|
||||||
|
"EndPoint": "3.226.182.187",
|
||||||
|
"Port": "9001",
|
||||||
|
"UseSSL": false,
|
||||||
|
"AccessKeyId": "7rvVIHs7D6pbyscRcJhz",
|
||||||
|
"SecretAccessKey": "DQsCQldHFL3QRjlnaLWV7oM4E9PtsO21QPC2h9BD",
|
||||||
|
"BucketName": "hir-us",
|
||||||
|
"ViewEndpoint": "http://hir-minio.uat.elevateimaging.ai/hir-us"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"RemoteNew": "Server=3.226.182.187,1435;Database=US_HIR;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
|
"Hangfire": "Server=3.226.182.187,1435;Database=US_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
|
},
|
||||||
|
"DicomSCPServiceConfig": {
|
||||||
|
"IsUploadImageAnonymization": true,
|
||||||
|
"IsSupportThirdService": true,
|
||||||
|
"IsForwardImageMultiThread": true,
|
||||||
|
"MultiThreadCount": 10,
|
||||||
|
"CalledAEList": [
|
||||||
|
"STORESCP",
|
||||||
|
"HIRAE"
|
||||||
|
],
|
||||||
|
"ServerPort": 11115
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ObjectStoreService": {
|
|
||||||
"ObjectStoreUse": "AWS",
|
|
||||||
"AWS": {
|
|
||||||
"Region": "us-east-1",
|
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
|
||||||
"UseSSL": true,
|
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/lili_s3_access",
|
|
||||||
"AccessKeyId": "AKIAW3MEAFJXZ2TZK7GM",
|
|
||||||
"SecretAccessKey": "9MLQCQ1HifEVW1gf068zBRAOb4wNnfrOkvBVByth",
|
|
||||||
"BucketName": "ei-med-s3-lili-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-store.s3.amazonaws.com",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"RemoteNew": "Server=us-mssql-prod,1433;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=us-mssql-prod,1433;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
"DicomSCPServiceConfig": {
|
|
||||||
"CalledAEList": [
|
|
||||||
"STORESCP"
|
|
||||||
],
|
|
||||||
"ServerPort": 11112
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ObjectStoreService": {
|
|
||||||
"ObjectStoreUse": "AWS",
|
|
||||||
"AWS": {
|
|
||||||
"Region": "us-east-1",
|
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
|
||||||
"UseSSL": true,
|
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
|
|
||||||
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
|
|
||||||
"SecretAccessKey": "Pgrg3le5jPxZQ7MR1yYNS30J0XRyJeKVyIIjElXc",
|
|
||||||
"BucketName": "ei-med-s3-lili-uat-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com/",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"RemoteNew": "Server=us-mssql-service,1433;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=us-mssql-service,1433;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
"DicomSCPServiceConfig": {
|
|
||||||
"CalledAEList": [
|
|
||||||
"STORESCP"
|
|
||||||
],
|
|
||||||
"ServerPort": 11112
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ObjectStoreService": {
|
||||||
|
"ObjectStoreUse": "MinIO",
|
||||||
|
"MinIO": {
|
||||||
|
"EndPoint": "101.132.253.119",
|
||||||
|
"Port": "9001",
|
||||||
|
"UseSSL": false,
|
||||||
|
"AccessKeyId": "ylWQa99fDdVdTfnj47ll",
|
||||||
|
"SecretAccessKey": "kVpy2RIYN0GmyFsU2qAWhbKDf4Nskt23tEqd6sob",
|
||||||
|
"BucketName": "hir-uat",
|
||||||
|
"ViewEndpoint": "http://101.132.253.119:9001/hir-uat/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"RemoteNew": "Server=101.132.253.119,1435;Database=Uat_HIR_New;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
|
"Hangfire": "Server=101.132.253.119,1435;Database=Uat_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
|
},
|
||||||
|
"DicomSCPServiceConfig": {
|
||||||
|
"IsUploadImageAnonymization": true,
|
||||||
|
"IsSupportThirdService": true,
|
||||||
|
"IsForwardImageMultiThread": true,
|
||||||
|
"MultiThreadCount": 10,
|
||||||
|
"CalledAEList": [
|
||||||
|
"STORESCP",
|
||||||
|
"HIRAE"
|
||||||
|
],
|
||||||
|
"ServerPort": 11115
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ObjectStoreService": {
|
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
|
||||||
"AliyunOSS": {
|
|
||||||
"RegionId": "cn-shanghai",
|
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"AccessKeyId": "LTAI5tFUCCmz5TwghZHsj45Y",
|
|
||||||
"AccessKeySecret": "8evrBy1fVfzJG25i67Jm0xqn9Xcw2T",
|
|
||||||
"RoleArn": "acs:ram::1078130221702011:role/uat-oss-access",
|
|
||||||
"BucketName": "tl-med-irc-uat-store",
|
|
||||||
"ViewEndpoint": "https://tl-med-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"Region": "oss-cn-shanghai",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"RemoteNew": "Server=101.132.253.119,1435;Database=Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server101.132.253.119,1435;Database=Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
"DicomSCPServiceConfig": {
|
|
||||||
"CalledAEList": [
|
|
||||||
"STORESCP"
|
|
||||||
],
|
|
||||||
"ServerPort": 11112
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
<!-- HTML for static distribution bundle build -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<title>%(DocumentTitle)</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" type="text/css" href="./swagger-ui.css">
|
||||||
|
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||||
|
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||||
|
<style>
|
||||||
|
|
||||||
|
html {
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: -moz-scrollbars-vertical;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after {
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
%(HeadContent)
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0">
|
||||||
|
<defs>
|
||||||
|
<symbol viewBox="0 0 20 20" id="unlocked">
|
||||||
|
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
|
||||||
|
</symbol>
|
||||||
|
<symbol viewBox="0 0 20 20" id="locked">
|
||||||
|
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol viewBox="0 0 20 20" id="close">
|
||||||
|
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol viewBox="0 0 20 20" id="large-arrow">
|
||||||
|
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol viewBox="0 0 20 20" id="large-arrow-down">
|
||||||
|
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z" />
|
||||||
|
</symbol>
|
||||||
|
|
||||||
|
<symbol viewBox="0 0 24 24" id="jump-to">
|
||||||
|
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol viewBox="0 0 24 24" id="expand">
|
||||||
|
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" />
|
||||||
|
</symbol>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
<script src="./swagger-ui-bundle.js"></script>
|
||||||
|
<script src="./swagger-ui-standalone-preset.js"></script>
|
||||||
|
<script src="/swagger/ui/abp.js"></script>
|
||||||
|
<script src="/swagger/ui/abp.swagger.js?v=1"></script>
|
||||||
|
<!--<script src="/lib/jquery/jquery.min.js"></script>-->
|
||||||
|
<script>
|
||||||
|
window.onload = function () {
|
||||||
|
var configObject = JSON.parse('%(ConfigObject)');
|
||||||
|
|
||||||
|
// Apply mandatory parameters
|
||||||
|
configObject.dom_id = "#swagger-ui";
|
||||||
|
configObject.presets = [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset];
|
||||||
|
configObject.layout = "StandaloneLayout";
|
||||||
|
configObject.requestInterceptor = function (request) {
|
||||||
|
request.headers.Authorization = "Bearer " + abp.auth.getToken();
|
||||||
|
return request;
|
||||||
|
};
|
||||||
|
if (!configObject.hasOwnProperty("oauth2RedirectUrl")) {
|
||||||
|
configObject.oauth2RedirectUrl = window.location + "oauth2-redirect.html"; // use the built-in default
|
||||||
|
}
|
||||||
|
function getAuthorizeButtonText() {
|
||||||
|
return abp.auth.getToken() ? 'Logout' : 'Authorize';
|
||||||
|
}
|
||||||
|
function getAuthorizeButtonCssClass() {
|
||||||
|
return abp.auth.getToken() ? 'cancel' : 'authorize';
|
||||||
|
}
|
||||||
|
configObject.plugins = [
|
||||||
|
function (system) {
|
||||||
|
return {
|
||||||
|
components: {
|
||||||
|
authorizeBtn: function () {
|
||||||
|
return system.React.createElement("button",
|
||||||
|
{
|
||||||
|
id: "authorize",
|
||||||
|
className: "btn " + getAuthorizeButtonCssClass(),
|
||||||
|
style: {
|
||||||
|
lineHeight: "normal"
|
||||||
|
},
|
||||||
|
onClick: function () {
|
||||||
|
var authorizeButton = document.getElementById('authorize');
|
||||||
|
if (abp.auth.getToken()) {
|
||||||
|
abp.swagger.logout();
|
||||||
|
authorizeButton.innerText = getAuthorizeButtonText();
|
||||||
|
authorizeButton.className = 'btn ' + getAuthorizeButtonCssClass();
|
||||||
|
} else {
|
||||||
|
abp.swagger.openAuthDialog(function () {
|
||||||
|
authorizeButton.innerText = getAuthorizeButtonText();
|
||||||
|
authorizeButton.className = 'btn ' + getAuthorizeButtonCssClass();
|
||||||
|
abp.swagger.closeAuthDialog();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, getAuthorizeButtonText());
|
||||||
|
}, info: function () {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// Build a system
|
||||||
|
SwaggerUIBundle(configObject);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
var abp = abp || {};
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
/* Application paths *****************************************/
|
||||||
|
|
||||||
|
// Current application root path (including virtual directory if exists).
|
||||||
|
abp.appPath = abp.appPath || '/';
|
||||||
|
|
||||||
|
/* AUTHORIZATION **********************************************/
|
||||||
|
// Implements Authorization API that simplifies usage of authorization scripts generated by Abp.
|
||||||
|
|
||||||
|
abp.auth = abp.auth || {};
|
||||||
|
|
||||||
|
abp.auth.tokenCookieName = 'Abp.AuthToken';
|
||||||
|
abp.auth.tokenHeaderName = 'Authorization';
|
||||||
|
|
||||||
|
abp.auth.setToken = function (authToken, expireDate) {
|
||||||
|
abp.utils.setCookieValue(abp.auth.tokenCookieName, authToken, expireDate, abp.appPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
abp.auth.getToken = function () {
|
||||||
|
return abp.utils.getCookieValue(abp.auth.tokenCookieName);
|
||||||
|
}
|
||||||
|
|
||||||
|
abp.auth.clearToken = function () {
|
||||||
|
abp.auth.setToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UTILS ***************************************************/
|
||||||
|
|
||||||
|
abp.utils = abp.utils || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a cookie value for given key.
|
||||||
|
* This is a simple implementation created to be used by ABP.
|
||||||
|
* Please use a complete cookie library if you need.
|
||||||
|
* @param {string} key
|
||||||
|
* @param {string} value
|
||||||
|
* @param {Date} expireDate (optional). If not specified the cookie will expire at the end of session.
|
||||||
|
* @param {string} path (optional)
|
||||||
|
*/
|
||||||
|
abp.utils.setCookieValue = function (key, value, expireDate, path) {
|
||||||
|
var cookieValue = encodeURIComponent(key) + '=';
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
cookieValue = cookieValue + encodeURIComponent(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expireDate) {
|
||||||
|
cookieValue = cookieValue + "; expires=" + expireDate.toUTCString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
cookieValue = cookieValue + "; path=" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.cookie = cookieValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a cookie with given key.
|
||||||
|
* This is a simple implementation created to be used by ABP.
|
||||||
|
* Please use a complete cookie library if you need.
|
||||||
|
* @param {string} key
|
||||||
|
* @returns {string} Cookie value or null
|
||||||
|
*/
|
||||||
|
abp.utils.getCookieValue = function (key) {
|
||||||
|
var equalities = document.cookie.split('; ');
|
||||||
|
for (var i = 0; i < equalities.length; i++) {
|
||||||
|
if (!equalities[i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var splitted = equalities[i].split('=');
|
||||||
|
if (splitted.length != 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decodeURIComponent(splitted[0]) === key) {
|
||||||
|
return decodeURIComponent(splitted[1] || '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes cookie for given key.
|
||||||
|
* This is a simple implementation created to be used by ABP.
|
||||||
|
* Please use a complete cookie library if you need.
|
||||||
|
* @param {string} key
|
||||||
|
* @param {string} path (optional)
|
||||||
|
*/
|
||||||
|
abp.utils.deleteCookie = function (key, path) {
|
||||||
|
var cookieValue = encodeURIComponent(key) + '=';
|
||||||
|
|
||||||
|
cookieValue = cookieValue + "; expires=" + (new Date(new Date().getTime() - 86400000)).toUTCString();
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
cookieValue = cookieValue + "; path=" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.cookie = cookieValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SECURITY ***************************************/
|
||||||
|
abp.security = abp.security || {};
|
||||||
|
abp.security.antiForgery = abp.security.antiForgery || {};
|
||||||
|
|
||||||
|
abp.security.antiForgery.tokenCookieName = 'XSRF-TOKEN';
|
||||||
|
abp.security.antiForgery.tokenHeaderName = 'X-XSRF-TOKEN';
|
||||||
|
|
||||||
|
abp.security.antiForgery.getToken = function () {
|
||||||
|
return abp.utils.getCookieValue(abp.security.antiForgery.tokenCookieName);
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
||||||
@@ -0,0 +1,597 @@
|
|||||||
|
var abp = abp || {};
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
/* md5*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
|
||||||
|
* Digest Algorithm, as defined in RFC 1321.
|
||||||
|
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
|
||||||
|
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||||
|
* Distributed under the BSD License
|
||||||
|
* See http://pajhome.org.uk/crypt/md5 for more info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configurable variables. You may need to tweak these to be compatible with
|
||||||
|
* the server-side, but the defaults work in most cases.
|
||||||
|
*/
|
||||||
|
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
|
||||||
|
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
|
||||||
|
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These are the functions you'll usually want to call
|
||||||
|
* They take string arguments and return either hex or base-64 encoded strings
|
||||||
|
*/
|
||||||
|
function hex_md5(s) { return binl2hex(core_md5(str2binl(s), s.length * chrsz)); }
|
||||||
|
function b64_md5(s) { return binl2b64(core_md5(str2binl(s), s.length * chrsz)); }
|
||||||
|
function str_md5(s) { return binl2str(core_md5(str2binl(s), s.length * chrsz)); }
|
||||||
|
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
|
||||||
|
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
|
||||||
|
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform a simple self-test to see if the VM is working
|
||||||
|
*/
|
||||||
|
function md5_vm_test() {
|
||||||
|
return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the MD5 of an array of little-endian words, and a bit length
|
||||||
|
*/
|
||||||
|
function core_md5(x, len) {
|
||||||
|
/* append padding */
|
||||||
|
x[len >> 5] |= 0x80 << ((len) % 32);
|
||||||
|
x[(((len + 64) >>> 9) << 4) + 14] = len;
|
||||||
|
|
||||||
|
var a = 1732584193;
|
||||||
|
var b = -271733879;
|
||||||
|
var c = -1732584194;
|
||||||
|
var d = 271733878;
|
||||||
|
|
||||||
|
for (var i = 0; i < x.length; i += 16) {
|
||||||
|
var olda = a;
|
||||||
|
var oldb = b;
|
||||||
|
var oldc = c;
|
||||||
|
var oldd = d;
|
||||||
|
|
||||||
|
a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
|
||||||
|
d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
|
||||||
|
c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
|
||||||
|
b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
|
||||||
|
a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
|
||||||
|
d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
|
||||||
|
c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
|
||||||
|
b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
|
||||||
|
a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
|
||||||
|
d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
|
||||||
|
c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
|
||||||
|
b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
|
||||||
|
a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
|
||||||
|
d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
|
||||||
|
c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
|
||||||
|
b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
|
||||||
|
|
||||||
|
a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
|
||||||
|
d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
|
||||||
|
c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
|
||||||
|
b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
|
||||||
|
a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
|
||||||
|
d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
|
||||||
|
c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
|
||||||
|
b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
|
||||||
|
a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
|
||||||
|
d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
|
||||||
|
c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
|
||||||
|
b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
|
||||||
|
a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
|
||||||
|
d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
|
||||||
|
c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
|
||||||
|
b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
|
||||||
|
|
||||||
|
a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
|
||||||
|
d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
|
||||||
|
c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
|
||||||
|
b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
|
||||||
|
a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
|
||||||
|
d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
|
||||||
|
c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
|
||||||
|
b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
|
||||||
|
a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
|
||||||
|
d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
|
||||||
|
c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
|
||||||
|
b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
|
||||||
|
a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
|
||||||
|
d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
|
||||||
|
c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
|
||||||
|
b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
|
||||||
|
|
||||||
|
a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
|
||||||
|
d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
|
||||||
|
c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
|
||||||
|
b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
|
||||||
|
a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
|
||||||
|
d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
|
||||||
|
c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
|
||||||
|
b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
|
||||||
|
a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
|
||||||
|
d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
|
||||||
|
c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
|
||||||
|
b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
|
||||||
|
a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
|
||||||
|
d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
|
||||||
|
c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
|
||||||
|
b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
|
||||||
|
|
||||||
|
a = safe_add(a, olda);
|
||||||
|
b = safe_add(b, oldb);
|
||||||
|
c = safe_add(c, oldc);
|
||||||
|
d = safe_add(d, oldd);
|
||||||
|
}
|
||||||
|
return Array(a, b, c, d);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These functions implement the four basic operations the algorithm uses.
|
||||||
|
*/
|
||||||
|
function md5_cmn(q, a, b, x, s, t) {
|
||||||
|
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
|
||||||
|
}
|
||||||
|
function md5_ff(a, b, c, d, x, s, t) {
|
||||||
|
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
|
||||||
|
}
|
||||||
|
function md5_gg(a, b, c, d, x, s, t) {
|
||||||
|
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
|
||||||
|
}
|
||||||
|
function md5_hh(a, b, c, d, x, s, t) {
|
||||||
|
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
|
||||||
|
}
|
||||||
|
function md5_ii(a, b, c, d, x, s, t) {
|
||||||
|
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the HMAC-MD5, of a key and some data
|
||||||
|
*/
|
||||||
|
function core_hmac_md5(key, data) {
|
||||||
|
var bkey = str2binl(key);
|
||||||
|
if (bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
|
||||||
|
|
||||||
|
var ipad = Array(16), opad = Array(16);
|
||||||
|
for (var i = 0; i < 16; i++) {
|
||||||
|
ipad[i] = bkey[i] ^ 0x36363636;
|
||||||
|
opad[i] = bkey[i] ^ 0x5C5C5C5C;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
|
||||||
|
return core_md5(opad.concat(hash), 512 + 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
|
||||||
|
* to work around bugs in some JS interpreters.
|
||||||
|
*/
|
||||||
|
function safe_add(x, y) {
|
||||||
|
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
||||||
|
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
||||||
|
return (msw << 16) | (lsw & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bitwise rotate a 32-bit number to the left.
|
||||||
|
*/
|
||||||
|
function bit_rol(num, cnt) {
|
||||||
|
return (num << cnt) | (num >>> (32 - cnt));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a string to an array of little-endian words
|
||||||
|
* If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
|
||||||
|
*/
|
||||||
|
function str2binl(str) {
|
||||||
|
var bin = Array();
|
||||||
|
var mask = (1 << chrsz) - 1;
|
||||||
|
for (var i = 0; i < str.length * chrsz; i += chrsz)
|
||||||
|
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32);
|
||||||
|
return bin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert an array of little-endian words to a string
|
||||||
|
*/
|
||||||
|
function binl2str(bin) {
|
||||||
|
var str = "";
|
||||||
|
var mask = (1 << chrsz) - 1;
|
||||||
|
for (var i = 0; i < bin.length * 32; i += chrsz)
|
||||||
|
str += String.fromCharCode((bin[i >> 5] >>> (i % 32)) & mask);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert an array of little-endian words to a hex string.
|
||||||
|
*/
|
||||||
|
function binl2hex(binarray) {
|
||||||
|
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||||
|
var str = "";
|
||||||
|
for (var i = 0; i < binarray.length * 4; i++) {
|
||||||
|
str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) +
|
||||||
|
hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert an array of little-endian words to a base-64 string
|
||||||
|
*/
|
||||||
|
function binl2b64(binarray) {
|
||||||
|
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
var str = "";
|
||||||
|
for (var i = 0; i < binarray.length * 4; i += 3) {
|
||||||
|
var triplet = (((binarray[i >> 2] >> 8 * (i % 4)) & 0xFF) << 16)
|
||||||
|
| (((binarray[i + 1 >> 2] >> 8 * ((i + 1) % 4)) & 0xFF) << 8)
|
||||||
|
| ((binarray[i + 2 >> 2] >> 8 * ((i + 2) % 4)) & 0xFF);
|
||||||
|
for (var j = 0; j < 4; j++) {
|
||||||
|
if (i * 8 + j * 6 > binarray.length * 32) str += b64pad;
|
||||||
|
else str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Swagger */
|
||||||
|
|
||||||
|
abp.swagger = abp.swagger || {};
|
||||||
|
|
||||||
|
abp.swagger.addAuthToken = function () {
|
||||||
|
var authToken = abp.auth.getToken();
|
||||||
|
if (!authToken) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cookieAuth = new SwaggerClient.ApiKeyAuthorization(abp.auth.tokenHeaderName, 'Bearer ' + authToken, 'header');
|
||||||
|
swaggerUi.api.clientAuthorizations.add('bearerAuth', cookieAuth);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
abp.swagger.addCsrfToken = function () {
|
||||||
|
var csrfToken = abp.security.antiForgery.getToken();
|
||||||
|
if (!csrfToken) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var csrfCookieAuth = new SwaggerClient.ApiKeyAuthorization(abp.security.antiForgery.tokenHeaderName, csrfToken, 'header');
|
||||||
|
swaggerUi.api.clientAuthorizations.add(abp.security.antiForgery.tokenHeaderName, csrfCookieAuth);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loginUserInternal(tenantId, callback) {
|
||||||
|
|
||||||
|
var usernameOrEmailAddress = document.getElementById('userName').value;
|
||||||
|
// if (!usernameOrEmailAddress) {
|
||||||
|
// alert('UserName Can Not Be Null');
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
var password = document.getElementById('password').value;
|
||||||
|
var pwdMd5 = document.getElementById('pwdMd5').value;
|
||||||
|
console.log(pwdMd5);
|
||||||
|
if (!password && !pwdMd5) {
|
||||||
|
alert('PassWord And Md5 Can Not Be Null');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
|
xhr.onreadystatechange = function () {
|
||||||
|
|
||||||
|
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||||
|
// debugger;
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
// debugger;
|
||||||
|
|
||||||
|
var resultdata = JSON.parse(xhr.responseText);
|
||||||
|
if (resultdata.ErrorMessage != '') {
|
||||||
|
alert(resultdata.ErrorMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (resultdata.code == 300) {
|
||||||
|
alert(resultdata.message);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var responseJSON = JSON.parse(xhr.responseText);
|
||||||
|
var result = responseJSON;
|
||||||
|
var expireDate = new Date(Date.now() + (60 * 60 * 24 * 1000));
|
||||||
|
abp.auth.setToken(result.Result.JWTStr, expireDate);
|
||||||
|
let selectDom = document.getElementById("roleSelect")
|
||||||
|
selectDom.options.length = 0;
|
||||||
|
result.Result.BasicInfo.AccountList.forEach(item => {
|
||||||
|
selectDom.options.add(new Option(item.UserTypeShortName, item.Id));
|
||||||
|
})
|
||||||
|
// callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
alert('Login failed !');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.open('POST', '/User/getUserLoginRoleList', true);
|
||||||
|
xhr.setRequestHeader('Abp.TenantId', tenantId);
|
||||||
|
xhr.setRequestHeader('Content-type', 'application/json');
|
||||||
|
var parm = {
|
||||||
|
|
||||||
|
|
||||||
|
UserName: usernameOrEmailAddress,
|
||||||
|
Password: hex_md5(password),
|
||||||
|
}
|
||||||
|
if (pwdMd5 != '') {
|
||||||
|
parm.Password = pwdMd5;
|
||||||
|
}
|
||||||
|
xhr.send(JSON.stringify(parm));
|
||||||
|
//xhr.send("{" + "userName:'" + usernameOrEmailAddress + "'," + "passWord:'" + password + "'}");
|
||||||
|
|
||||||
|
};
|
||||||
|
function loginUserInternalRole(tenantId, callback) {
|
||||||
|
|
||||||
|
var usernameOrEmailAddress = document.getElementById('roleSelect').value;
|
||||||
|
//if (!usernameOrEmailAddress) {
|
||||||
|
// alert('UserName Can Not Be Null');
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
|
||||||
|
var password = document.getElementById('password').value;
|
||||||
|
var pwdMd5 = document.getElementById('pwdMd5').value;
|
||||||
|
console.log(pwdMd5);
|
||||||
|
if (!password && !pwdMd5) {
|
||||||
|
alert('PassWord And Md5 Can Not Be Null');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
|
xhr.onreadystatechange = function () {
|
||||||
|
|
||||||
|
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||||
|
// debugger;
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
// debugger;
|
||||||
|
|
||||||
|
var resultdata = JSON.parse(xhr.responseText);
|
||||||
|
if (resultdata.ErrorMessage != '') {
|
||||||
|
alert(resultdata.ErrorMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (resultdata.code == 300) {
|
||||||
|
alert(resultdata.message);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var responseJSON = JSON.parse(xhr.responseText);
|
||||||
|
var result = responseJSON;
|
||||||
|
var expireDate = new Date(Date.now() + (60 * 60 * 24 * 1000));
|
||||||
|
abp.auth.setToken(result.Result, expireDate);
|
||||||
|
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
alert('Login failed !');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.open('get', `/User/loginSelectUserRole?userRoleId=${usernameOrEmailAddress}`, true);
|
||||||
|
xhr.setRequestHeader('Abp.TenantId', tenantId);
|
||||||
|
xhr.setRequestHeader('Content-type', 'application/json');
|
||||||
|
var authToken = abp.auth.getToken();
|
||||||
|
xhr.setRequestHeader('Authorization', `Bearer ${authToken}`);
|
||||||
|
xhr.send();
|
||||||
|
//xhr.send("{" + "userName:'" + usernameOrEmailAddress + "'," + "passWord:'" + password + "'}");
|
||||||
|
|
||||||
|
};
|
||||||
|
abp.swagger.login = function (callback) {
|
||||||
|
//Get TenantId first
|
||||||
|
var tenancyName = document.getElementById('tenancyName').value;
|
||||||
|
|
||||||
|
if (tenancyName) {
|
||||||
|
var xhrTenancyName = new XMLHttpRequest();
|
||||||
|
xhrTenancyName.onreadystatechange = function () {
|
||||||
|
if (xhrTenancyName.readyState === XMLHttpRequest.DONE && xhrTenancyName.status === 200) {
|
||||||
|
var responseJSON = JSON.parse(xhrTenancyName.responseText);
|
||||||
|
var result = responseJSON.result;
|
||||||
|
if (result.state === 1) { // Tenant exists and active.
|
||||||
|
loginUserInternal(result.tenantId, callback); // Login for tenant
|
||||||
|
} else {
|
||||||
|
alert('There is no such tenant or tenant is not active !');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhrTenancyName.open('POST', '/api/services/app/Account/IsTenantAvailable', true);
|
||||||
|
xhrTenancyName.setRequestHeader('Content-type', 'application/json');
|
||||||
|
xhrTenancyName.send("{" + "tenancyName:'" + tenancyName + "'}");
|
||||||
|
} else {
|
||||||
|
loginUserInternal(null, callback); // Login for host
|
||||||
|
}
|
||||||
|
};
|
||||||
|
abp.swagger.loginRole = function (callback) {
|
||||||
|
//Get TenantId first
|
||||||
|
var tenancyName = document.getElementById('tenancyName').value;
|
||||||
|
|
||||||
|
if (tenancyName) {
|
||||||
|
var xhrTenancyName = new XMLHttpRequest();
|
||||||
|
xhrTenancyName.onreadystatechange = function () {
|
||||||
|
if (xhrTenancyName.readyState === XMLHttpRequest.DONE && xhrTenancyName.status === 200) {
|
||||||
|
var responseJSON = JSON.parse(xhrTenancyName.responseText);
|
||||||
|
var result = responseJSON.result;
|
||||||
|
if (result.state === 1) { // Tenant exists and active.
|
||||||
|
loginUserInternalRole(result.tenantId, callback); // Login for tenant
|
||||||
|
} else {
|
||||||
|
alert('There is no such tenant or tenant is not active !');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhrTenancyName.open('POST', '/api/services/app/Account/IsTenantAvailable', true);
|
||||||
|
xhrTenancyName.setRequestHeader('Content-type', 'application/json');
|
||||||
|
xhrTenancyName.send("{" + "tenancyName:'" + tenancyName + "'}");
|
||||||
|
} else {
|
||||||
|
loginUserInternalRole(null, callback); // Login for host
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
abp.swagger.logout = function () {
|
||||||
|
abp.auth.clearToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
abp.swagger.closeAuthDialog = function () {
|
||||||
|
if (document.getElementById('abp-auth-dialog')) {
|
||||||
|
document.getElementsByClassName("swagger-ui")[1].removeChild(document.getElementById('abp-auth-dialog'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abp.swagger.openAuthDialog = function (loginCallback) {
|
||||||
|
abp.swagger.closeAuthDialog();
|
||||||
|
|
||||||
|
var abpAuthDialog = document.createElement('div');
|
||||||
|
abpAuthDialog.className = 'dialog-ux';
|
||||||
|
abpAuthDialog.id = 'abp-auth-dialog';
|
||||||
|
|
||||||
|
document.getElementsByClassName("swagger-ui")[1].appendChild(abpAuthDialog);
|
||||||
|
|
||||||
|
// -- backdrop-ux
|
||||||
|
var backdropUx = document.createElement('div');
|
||||||
|
backdropUx.className = 'backdrop-ux';
|
||||||
|
abpAuthDialog.appendChild(backdropUx);
|
||||||
|
|
||||||
|
// -- modal-ux
|
||||||
|
var modalUx = document.createElement('div');
|
||||||
|
modalUx.className = 'modal-ux';
|
||||||
|
abpAuthDialog.appendChild(modalUx);
|
||||||
|
|
||||||
|
// -- -- modal-dialog-ux
|
||||||
|
var modalDialogUx = document.createElement('div');
|
||||||
|
modalDialogUx.className = 'modal-dialog-ux';
|
||||||
|
modalUx.appendChild(modalDialogUx);
|
||||||
|
|
||||||
|
// -- -- -- modal-ux-inner
|
||||||
|
var modalUxInner = document.createElement('div');
|
||||||
|
modalUxInner.className = 'modal-ux-inner';
|
||||||
|
modalDialogUx.appendChild(modalUxInner);
|
||||||
|
|
||||||
|
// -- -- -- -- modal-ux-header
|
||||||
|
var modalUxHeader = document.createElement('div');
|
||||||
|
modalUxHeader.className = 'modal-ux-header';
|
||||||
|
modalUxInner.appendChild(modalUxHeader);
|
||||||
|
|
||||||
|
var modalHeader = document.createElement('h3');
|
||||||
|
modalHeader.innerText = 'Authorize';
|
||||||
|
modalUxHeader.appendChild(modalHeader);
|
||||||
|
|
||||||
|
// -- -- -- -- modal-ux-content
|
||||||
|
var modalUxContent = document.createElement('div');
|
||||||
|
modalUxContent.className = 'modal-ux-content';
|
||||||
|
modalUxInner.appendChild(modalUxContent);
|
||||||
|
|
||||||
|
modalUxContent.onkeydown = function (e) {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
//try to login when user presses enter on authorize modal
|
||||||
|
abp.swagger.login(loginCallback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//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', '');
|
||||||
|
createSelect(modalUxContent, 'roleSelect', 'role', [])
|
||||||
|
|
||||||
|
//Buttons
|
||||||
|
var authBtnWrapper = document.createElement('div');
|
||||||
|
authBtnWrapper.className = 'auth-btn-wrapper';
|
||||||
|
modalUxContent.appendChild(authBtnWrapper);
|
||||||
|
|
||||||
|
//Close button
|
||||||
|
var closeButton = document.createElement('button');
|
||||||
|
closeButton.className = 'btn modal-btn auth btn-done button';
|
||||||
|
closeButton.innerText = 'Close';
|
||||||
|
closeButton.style.marginRight = '5px';
|
||||||
|
closeButton.onclick = abp.swagger.closeAuthDialog;
|
||||||
|
authBtnWrapper.appendChild(closeButton);
|
||||||
|
|
||||||
|
//Authorize button
|
||||||
|
var authorizeButton = document.createElement('button');
|
||||||
|
authorizeButton.className = 'btn modal-btn auth authorize button';
|
||||||
|
authorizeButton.innerText = 'Login';
|
||||||
|
authorizeButton.onclick = function () {
|
||||||
|
abp.swagger.login(loginCallback);
|
||||||
|
};
|
||||||
|
authBtnWrapper.appendChild(authorizeButton);
|
||||||
|
|
||||||
|
// login role
|
||||||
|
var authorizeButton = document.createElement('button');
|
||||||
|
authorizeButton.className = 'btn modal-btn auth authorize button';
|
||||||
|
authorizeButton.innerText = 'LoginRole';
|
||||||
|
authorizeButton.onclick = function () {
|
||||||
|
abp.swagger.loginRole(loginCallback);
|
||||||
|
};
|
||||||
|
authBtnWrapper.appendChild(authorizeButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createInput(container, id, title, type, value = "") {
|
||||||
|
var wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'wrapper';
|
||||||
|
if (id == "tenancyName") {
|
||||||
|
wrapper.style.display = 'none';
|
||||||
|
}
|
||||||
|
container.appendChild(wrapper);
|
||||||
|
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.innerText = title;
|
||||||
|
wrapper.appendChild(label);
|
||||||
|
|
||||||
|
var section = document.createElement('section');
|
||||||
|
section.className = 'block-tablet col-10-tablet block-desktop col-10-desktop';
|
||||||
|
wrapper.appendChild(section);
|
||||||
|
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.id = id;
|
||||||
|
input.type = type ? type : 'text';
|
||||||
|
input.style.width = '100%';
|
||||||
|
input.value = value;
|
||||||
|
input.autocomplete = "off";
|
||||||
|
|
||||||
|
|
||||||
|
section.appendChild(input);
|
||||||
|
}
|
||||||
|
function createSelect(container, id, title, option = []) {
|
||||||
|
var wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'wrapper';
|
||||||
|
if (id == "tenancyName") {
|
||||||
|
wrapper.style.display = 'none';
|
||||||
|
}
|
||||||
|
container.appendChild(wrapper);
|
||||||
|
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.innerText = title;
|
||||||
|
wrapper.appendChild(label);
|
||||||
|
|
||||||
|
var section = document.createElement('section');
|
||||||
|
section.className = 'block-tablet col-10-tablet block-desktop col-10-desktop';
|
||||||
|
wrapper.appendChild(section);
|
||||||
|
|
||||||
|
var input = document.createElement('select');
|
||||||
|
input.id = id;
|
||||||
|
input.style.width = '100%';
|
||||||
|
option.forEach(item => {
|
||||||
|
input.options.add(new Option(item.UserTypeShortName, item.Id));
|
||||||
|
})
|
||||||
|
|
||||||
|
section.appendChild(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using AlibabaCloud.SDK.Sts20150401;
|
using AlibabaCloud.SDK.Sts20150401;
|
||||||
using Amazon.Auth.AccessControlPolicy;
|
using Amazon.Auth.AccessControlPolicy;
|
||||||
using Amazon.SecurityToken;
|
using Amazon.SecurityToken;
|
||||||
using AutoMapper;
|
|
||||||
using Azure.Core;
|
using Azure.Core;
|
||||||
using IdentityModel.Client;
|
using IdentityModel.Client;
|
||||||
using IdentityModel.OidcClient;
|
using IdentityModel.OidcClient;
|
||||||
@@ -22,7 +21,6 @@ using Microsoft.AspNetCore.Http;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Org.BouncyCastle.Tls;
|
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
using RestSharp.Authenticators;
|
using RestSharp.Authenticators;
|
||||||
using System;
|
using System;
|
||||||
@@ -104,11 +102,6 @@ namespace IRaCIS.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[HttpGet, Route("user/getPublicKey")]
|
[HttpGet, Route("user/getPublicKey")]
|
||||||
public IResponseOutput GetPublicKey([FromServices] IOptionsMonitor<IRCEncreptOption> _IRCEncreptOption)
|
public IResponseOutput GetPublicKey([FromServices] IOptionsMonitor<IRCEncreptOption> _IRCEncreptOption)
|
||||||
@@ -134,6 +127,7 @@ namespace IRaCIS.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("user/GetObjectStoreToken")]
|
[HttpGet("user/GetObjectStoreToken")]
|
||||||
|
[AllowAnonymous]
|
||||||
public async Task<IResponseOutput> GetObjectStoreTokenAsync([FromServices] IOptionsMonitor<ObjectStoreServiceOptions> options, [FromServices] IOSSService _oSSService)
|
public async Task<IResponseOutput> GetObjectStoreTokenAsync([FromServices] IOptionsMonitor<ObjectStoreServiceOptions> options, [FromServices] IOSSService _oSSService)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -183,7 +177,6 @@ namespace IRaCIS.Api.Controllers
|
|||||||
return tempToken;
|
return tempToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#region 老项目依赖
|
#region 老项目依赖
|
||||||
|
|
||||||
[HttpGet("user/GenerateSTS")]
|
[HttpGet("user/GenerateSTS")]
|
||||||
@@ -210,23 +203,7 @@ namespace IRaCIS.Api.Controllers
|
|||||||
var response = client.AssumeRoleWithOptions(assumeRoleRequest, runtime);
|
var response = client.AssumeRoleWithOptions(assumeRoleRequest, runtime);
|
||||||
var credentials = response.Body.Credentials;
|
var credentials = response.Body.Credentials;
|
||||||
|
|
||||||
var tempToken = new AliyunOSSTempToken()
|
|
||||||
{
|
|
||||||
AccessKeyId = credentials.AccessKeyId,
|
|
||||||
AccessKeySecret = credentials.AccessKeySecret,
|
|
||||||
|
|
||||||
//转为服务器时区,最后统一转为客户端时区
|
|
||||||
Expiration = TimeZoneInfo.ConvertTimeFromUtc(DateTime.Parse(credentials.Expiration), TimeZoneInfo.Local),
|
|
||||||
SecurityToken = credentials.SecurityToken,
|
|
||||||
|
|
||||||
|
|
||||||
Region = ossOptions.Region,
|
|
||||||
BucketName = ossOptions.BucketName,
|
|
||||||
EndPoint = ossOptions.EndPoint,
|
|
||||||
ViewEndpoint = ossOptions.ViewEndpoint,
|
|
||||||
PreviewEndpoint = ossOptions.PreviewEndpoint
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// 返回STS令牌信息给前端
|
// 返回STS令牌信息给前端
|
||||||
var stsToken = new
|
var stsToken = new
|
||||||
|
|||||||
@@ -51,30 +51,30 @@ namespace IRaCIS.Core.API.Controllers.Special
|
|||||||
[TrialGlobalLimit( "AddOrUpdateTrial", "BeforeOngoingCantOpt", "AfterStopCannNotOpt" )]
|
[TrialGlobalLimit( "AddOrUpdateTrial", "BeforeOngoingCantOpt", "AfterStopCannNotOpt" )]
|
||||||
public async Task<IResponseOutput<Trial>> AddOrUpdateTrial(TrialCommand param)
|
public async Task<IResponseOutput<Trial>> AddOrUpdateTrial(TrialCommand param)
|
||||||
{
|
{
|
||||||
//var userId = Guid.Parse(User.FindFirst("id").Value);
|
var userId = Guid.Parse(User.FindFirst("id").Value);
|
||||||
var result = await _trialService.AddOrUpdateTrial(param);
|
var result = await _trialService.AddOrUpdateTrial(param);
|
||||||
|
|
||||||
//if (_trialService.TrialExpeditedChange)
|
if (_trialService.TrialExpeditedChange)
|
||||||
//{
|
{
|
||||||
// var needCalReviewerIds = await _trialService.GetTrialEnrollmentReviewerIds(param.Id.Value);
|
var needCalReviewerIds = await _trialService.GetTrialEnrollmentReviewerIds(param.Id.Value);
|
||||||
// var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
|
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
|
||||||
|
|
||||||
// calcList.ForEach(t =>
|
calcList.ForEach(t =>
|
||||||
// {
|
{
|
||||||
// if (needCalReviewerIds.Contains(t.DoctorId))
|
if (needCalReviewerIds.Contains(t.DoctorId))
|
||||||
// {
|
{
|
||||||
// _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
_calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||||
// {
|
{
|
||||||
// NeedCalculateReviewers = new List<Guid>()
|
NeedCalculateReviewers = new List<Guid>()
|
||||||
// {
|
{
|
||||||
// t.DoctorId
|
t.DoctorId
|
||||||
// },
|
},
|
||||||
// CalculateMonth = DateTime.Parse(t.YearMonth)
|
CalculateMonth = DateTime.Parse(t.YearMonth)
|
||||||
// }, User.FindFirst("id").Value);
|
}, User.FindFirst("id").Value);
|
||||||
|
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
//}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
[ApiController, ApiExplorerSettings(GroupName = "Reviewer")]
|
[ApiController, ApiExplorerSettings(GroupName = "Reviewer")]
|
||||||
[UnitOfWork]
|
[UnitOfWork]
|
||||||
public class InspectionController(
|
public class InspectionController(
|
||||||
ITrialDocumentService _trialDocumentService,
|
|
||||||
IReadingImageTaskService _iReadingImageTaskService,
|
IReadingImageTaskService _iReadingImageTaskService,
|
||||||
ITrialConfigService _trialConfigService,
|
ITrialConfigService _trialConfigService,
|
||||||
IClinicalAnswerService _clinicalAnswerService,
|
IClinicalAnswerService _clinicalAnswerService,
|
||||||
@@ -429,21 +428,11 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
public async Task<IResponseOutput> QCPassedOrFailed(DataInspectionDto<QCPassedOrFailedDto> opt)
|
public async Task<IResponseOutput> QCPassedOrFailed(DataInspectionDto<QCPassedOrFailedDto> opt)
|
||||||
{
|
{
|
||||||
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
if (opt.Data.IsSecondPass != null)
|
|
||||||
{
|
|
||||||
var result = await _qCOperationService.QCSecondReviewPassedOrFailed(opt.Data.trialId, opt.Data.subjectVisitId, (bool)opt.Data.IsSecondPass);
|
|
||||||
await _inspectionService.CompletedSign(singid, result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var result = await _qCOperationService.QCPassedOrFailed(opt.Data.trialId, opt.Data.subjectVisitId, opt.Data.auditState);
|
var result = await _qCOperationService.QCPassedOrFailed(opt.Data.trialId, opt.Data.subjectVisitId, opt.Data.auditState);
|
||||||
await _inspectionService.CompletedSign(singid, result);
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 一致性核查 回退 对话记录不清除 只允许PM回退
|
/// 一致性核查 回退 对话记录不清除 只允许PM回退
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -507,21 +496,7 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用户 签名某个文档
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost, Route("Inspection/TrialDocument/userConfirm")]
|
|
||||||
[TrialGlobalLimit("BeforeOngoingCantOpt", "SignSystemDocNoTrialId", "AfterStopCannNotOpt")]
|
|
||||||
[UnitOfWork]
|
|
||||||
public async Task<IResponseOutput> UserConfirm(DataInspectionDto<UserConfirmCommand> opt)
|
|
||||||
{
|
|
||||||
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
|
||||||
opt.Data.SignText = opt.SignInfo.SignText;
|
|
||||||
var result = await _trialDocumentService.UserConfirm(opt.Data);
|
|
||||||
await _inspectionService.CompletedSign(singid, result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -532,10 +507,10 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
|
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
|
||||||
[UnitOfWork]
|
[UnitOfWork]
|
||||||
|
|
||||||
public async Task<IResponseOutput> ConfirmReReading(DataInspectionDto<ConfirmReReadingCommand> opt, [FromServices] IVisitTaskService _visitTaskService)
|
public async Task<IResponseOutput> ConfirmReReading(DataInspectionDto<ConfirmReReadingCommand> opt, [FromServices] IVisitTaskHelpeService _visitTaskCommonService, [FromServices] IVisitTaskService _visitTaskService)
|
||||||
{
|
{
|
||||||
var singId = await _inspectionService.RecordSing(opt.SignInfo);
|
var singId = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
var result = await _visitTaskService.ConfirmReReading(opt.Data);
|
var result = await _visitTaskService.ConfirmReReading(opt.Data, _visitTaskCommonService);
|
||||||
await _inspectionService.CompletedSign(singId, result);
|
await _inspectionService.CompletedSign(singId, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,363 @@
|
|||||||
|
using AutoMapper.Execution;
|
||||||
|
using DocumentFormat.OpenXml.Bibliography;
|
||||||
|
using FellowOakDicom;
|
||||||
|
using FellowOakDicom.Network;
|
||||||
|
using FellowOakDicom.Network.Client;
|
||||||
|
using IRaCIS.Core.Application.Contracts;
|
||||||
|
using IRaCIS.Core.Domain.Models;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Org.BouncyCastle.Bcpg;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API.HostService
|
||||||
|
{
|
||||||
|
|
||||||
|
public class DicomSCPService : DicomService, IDicomServiceProvider, IDicomCFindProvider, IDicomCEchoProvider, IDicomCMoveProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
private static readonly DicomTransferSyntax[] _acceptedTransferSyntaxes = new DicomTransferSyntax[]
|
||||||
|
{
|
||||||
|
DicomTransferSyntax.ExplicitVRLittleEndian,
|
||||||
|
DicomTransferSyntax.ExplicitVRBigEndian,
|
||||||
|
DicomTransferSyntax.ImplicitVRLittleEndian
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private static readonly DicomTransferSyntax[] _acceptedImageTransferSyntaxes = new DicomTransferSyntax[]
|
||||||
|
{
|
||||||
|
// Lossless
|
||||||
|
DicomTransferSyntax.JPEGLSLossless,
|
||||||
|
DicomTransferSyntax.JPEG2000Lossless,
|
||||||
|
DicomTransferSyntax.JPEGProcess14SV1,
|
||||||
|
DicomTransferSyntax.JPEGProcess14,
|
||||||
|
DicomTransferSyntax.RLELossless,
|
||||||
|
|
||||||
|
// Lossy
|
||||||
|
DicomTransferSyntax.JPEGLSNearLossless,
|
||||||
|
DicomTransferSyntax.JPEG2000Lossy,
|
||||||
|
DicomTransferSyntax.JPEGProcess1,
|
||||||
|
DicomTransferSyntax.JPEGProcess2_4,
|
||||||
|
|
||||||
|
// Uncompressed
|
||||||
|
DicomTransferSyntax.ExplicitVRLittleEndian,
|
||||||
|
DicomTransferSyntax.ExplicitVRBigEndian,
|
||||||
|
DicomTransferSyntax.ImplicitVRLittleEndian
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private IServiceProvider _serviceProvider { get; set; }
|
||||||
|
|
||||||
|
private DicomSCPServiceOption DicomSCPServiceConfig { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public string CallingAE { get; protected set; }
|
||||||
|
public string CalledAE { get; protected set; }
|
||||||
|
|
||||||
|
public DicomSCPService(INetworkStream stream, Encoding fallbackEncoding, Microsoft.Extensions.Logging.ILogger log, DicomServiceDependencies dependencies, IServiceProvider injectServiceProvider)
|
||||||
|
: base(stream, fallbackEncoding, log, dependencies)
|
||||||
|
{
|
||||||
|
_serviceProvider = injectServiceProvider.CreateScope().ServiceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void OnConnectionClosed(Exception exception)
|
||||||
|
{
|
||||||
|
if (exception != null)
|
||||||
|
{
|
||||||
|
Logger.LogError($"Closed, exception is {exception.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReceiveAbort(DicomAbortSource source, DicomAbortReason reason)
|
||||||
|
{
|
||||||
|
Logger.LogError($"Received abort from {source}, reason is {reason}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task OnReceiveAssociationReleaseRequestAsync()
|
||||||
|
{
|
||||||
|
return SendAssociationReleaseResponseAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task OnReceiveAssociationRequestAsync(DicomAssociation association)
|
||||||
|
{
|
||||||
|
CallingAE = association.CallingAE;
|
||||||
|
CalledAE = association.CalledAE;
|
||||||
|
|
||||||
|
Logger.LogInformation($"Received association request from AE: {CallingAE} with IP: {association.RemoteHost} ");
|
||||||
|
|
||||||
|
DicomSCPServiceConfig = _serviceProvider.GetService<IOptionsMonitor<DicomSCPServiceOption>>().CurrentValue;
|
||||||
|
var calledAEList = DicomSCPServiceConfig.CalledAEList;
|
||||||
|
|
||||||
|
//不支持三方服务 或者CallAE不对,那么拒绝连接
|
||||||
|
if (!calledAEList.Contains(CalledAE) || DicomSCPServiceConfig.IsSupportThirdService == false || CallingAE != DicomSCPServiceConfig.ThirdCallningAE)
|
||||||
|
{
|
||||||
|
Logger.LogError($"Association with {CallingAE} rejected since called aet {CalledAE} is unknown");
|
||||||
|
return SendAssociationRejectAsync(DicomRejectResult.Permanent, DicomRejectSource.ServiceUser, DicomRejectReason.CalledAENotRecognized);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var pc in association.PresentationContexts)
|
||||||
|
{
|
||||||
|
if (pc.AbstractSyntax == DicomUID.Verification
|
||||||
|
|| pc.AbstractSyntax == DicomUID.PatientRootQueryRetrieveInformationModelFind
|
||||||
|
|| pc.AbstractSyntax == DicomUID.PatientRootQueryRetrieveInformationModelMove
|
||||||
|
|| pc.AbstractSyntax == DicomUID.StudyRootQueryRetrieveInformationModelFind
|
||||||
|
|| pc.AbstractSyntax == DicomUID.StudyRootQueryRetrieveInformationModelMove)
|
||||||
|
{
|
||||||
|
pc.AcceptTransferSyntaxes(_acceptedTransferSyntaxes);
|
||||||
|
}
|
||||||
|
else if (pc.AbstractSyntax == DicomUID.PatientRootQueryRetrieveInformationModelGet
|
||||||
|
|| pc.AbstractSyntax == DicomUID.StudyRootQueryRetrieveInformationModelGet)
|
||||||
|
{
|
||||||
|
pc.AcceptTransferSyntaxes(_acceptedImageTransferSyntaxes);
|
||||||
|
}
|
||||||
|
else if (pc.AbstractSyntax.StorageCategory != DicomStorageCategory.None)
|
||||||
|
{
|
||||||
|
pc.AcceptTransferSyntaxes(_acceptedImageTransferSyntaxes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.LogWarning($"Requested abstract syntax {pc.AbstractSyntax} from {CallingAE} not supported");
|
||||||
|
pc.SetResult(DicomPresentationContextResult.RejectAbstractSyntaxNotSupported);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.LogInformation($"Accepted association request from {CallingAE}");
|
||||||
|
return SendAssociationAcceptAsync(association);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<DicomCEchoResponse> OnCEchoRequestAsync(DicomCEchoRequest request)
|
||||||
|
{
|
||||||
|
Logger.LogInformation("Received verification request from AE {0} with IP: {1}", CallingAE, Association.RemoteHost);
|
||||||
|
return Task.FromResult(new DicomCEchoResponse(request, DicomStatus.Success));
|
||||||
|
}
|
||||||
|
public async IAsyncEnumerable<DicomCFindResponse> OnCFindRequestAsync(DicomCFindRequest request)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Received C-FIND request, forwarding to real PACS...");
|
||||||
|
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
var _dicomAERepository = _serviceProvider.GetService<IRepository<DicomAE>>();
|
||||||
|
|
||||||
|
var find = await _dicomAERepository.FirstOrDefaultAsync(t => t.PacsTypeEnum == PacsType.PacsServer && t.CalledAE == DicomSCPServiceConfig.ThirdSearchPacsAE);
|
||||||
|
|
||||||
|
var hirClient = await _dicomAERepository.FirstOrDefaultAsync(t => t.PacsTypeEnum == PacsType.HIRClient);
|
||||||
|
|
||||||
|
|
||||||
|
if (find == null || hirClient == null)
|
||||||
|
{
|
||||||
|
Logger.LogInformation("客户端和Pacs配置未查询到");
|
||||||
|
|
||||||
|
yield return new DicomCFindResponse(request, DicomStatus.ProcessingFailure);
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string patientID = request.Dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
|
||||||
|
string patientName = request.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
|
||||||
|
string studyDate = request.Dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty);
|
||||||
|
string studyInstanceUID = request.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty);
|
||||||
|
string accessionNumber = request.Dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty);
|
||||||
|
|
||||||
|
|
||||||
|
if (patientID.IsNullOrEmpty() && patientName.IsNullOrEmpty() && studyInstanceUID.IsNullOrEmpty() && studyDate.IsNullOrEmpty() && accessionNumber.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
yield return new DicomCFindResponse(request, DicomStatus.MissingAttribute);
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 创建 channel 用于异步传递响应
|
||||||
|
var channel = Channel.CreateUnbounded<DicomCFindResponse>();
|
||||||
|
|
||||||
|
// 克隆 dataset 避免线程/状态冲突
|
||||||
|
var clonedDataset = request.Dataset?.Clone() ?? new DicomDataset();
|
||||||
|
var forward = new DicomCFindRequest(request.SOPClassUID, request.Level)
|
||||||
|
{
|
||||||
|
Dataset = clonedDataset
|
||||||
|
};
|
||||||
|
|
||||||
|
var receivedCount = 0;
|
||||||
|
|
||||||
|
// 标记是否已收到 final 状态(Success/Failure/Cancel)
|
||||||
|
var finalReceived = false;
|
||||||
|
|
||||||
|
// 当远端 PACS 返回响应时,异步写入 channel
|
||||||
|
forward.OnResponseReceived += (rq, rp) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
#region 取消,现在不行
|
||||||
|
|
||||||
|
////100条的时候直接取消
|
||||||
|
//if (receivedCount >= 10)
|
||||||
|
//{
|
||||||
|
// rp.Status = DicomStatus.Cancel;
|
||||||
|
|
||||||
|
// cts.Cancel(); // 触发取消
|
||||||
|
|
||||||
|
// Logger.LogWarning("超过100条,剩余的取消!");
|
||||||
|
//}
|
||||||
|
|
||||||
|
//receivedCount++;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
var dsCopy = rp.Dataset?.Clone();
|
||||||
|
var proxyResp = new DicomCFindResponse(request, rp.Status)
|
||||||
|
{
|
||||||
|
Dataset = dsCopy
|
||||||
|
};
|
||||||
|
channel.Writer.TryWrite(proxyResp);
|
||||||
|
|
||||||
|
if (!rp.Status.Equals(DicomStatus.Pending))
|
||||||
|
{
|
||||||
|
finalReceived = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 异步发送到真实 PACS
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var client = DicomClientFactory.Create(find.IP, find.Port, false, hirClient.CalledAE, find.CalledAE);
|
||||||
|
await client.AddRequestAsync(forward);
|
||||||
|
await client.SendAsync(cancellationToken: cts.Token);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Error forwarding C-FIND: " + ex.Message);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
channel.Writer.Complete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 异步 yield 返回给上游
|
||||||
|
await foreach (var resp in channel.Reader.ReadAllAsync())
|
||||||
|
{
|
||||||
|
yield return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兜底:如果没有 final 响应,返回 Success
|
||||||
|
if (!finalReceived)
|
||||||
|
{
|
||||||
|
yield return new DicomCFindResponse(request, DicomStatus.Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async IAsyncEnumerable<DicomCMoveResponse> OnCMoveRequestAsync(DicomCMoveRequest request)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Received C-Move request, forwarding to real PACS...");
|
||||||
|
|
||||||
|
var _dicomAERepository = _serviceProvider.GetService<IRepository<DicomAE>>();
|
||||||
|
var _cmoveStudyRepository = _serviceProvider.GetService<IRepository<CmoveStudy>>();
|
||||||
|
|
||||||
|
var find = await _dicomAERepository.FirstOrDefaultAsync(t => t.PacsTypeEnum == PacsType.PacsServer && t.CalledAE == DicomSCPServiceConfig.ThirdSearchPacsAE);
|
||||||
|
|
||||||
|
|
||||||
|
var hirServer = await _dicomAERepository.FirstOrDefaultAsync(t => t.PacsTypeEnum == PacsType.HIRServer);
|
||||||
|
|
||||||
|
var hirClient = await _dicomAERepository.FirstOrDefaultAsync(t => t.PacsTypeEnum == PacsType.HIRClient);
|
||||||
|
|
||||||
|
|
||||||
|
if (find == null || hirClient == null || hirServer == null)
|
||||||
|
{
|
||||||
|
Logger.LogInformation("客户端和Pacs配置未查询到");
|
||||||
|
}
|
||||||
|
|
||||||
|
var studyInstanceUid = request.Dataset?.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty);
|
||||||
|
|
||||||
|
if (studyInstanceUid.IsNotNullOrEmpty())
|
||||||
|
{
|
||||||
|
await _cmoveStudyRepository.AddAsync(new CmoveStudy() { CallingAE = CallingAE, CalledAE = CalledAE, DestinationAE = request.DestinationAE, StudyInstanceUIDList = new List<string>() { studyInstanceUid }, HopitalGroupIdList = new List<Guid>() }, true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var channel = Channel.CreateUnbounded<DicomCMoveResponse>();
|
||||||
|
var clonedDataset = request.Dataset?.Clone() ?? new DicomDataset();
|
||||||
|
|
||||||
|
var forward = new DicomCMoveRequest(hirServer.CalledAE, studyInstanceUid)
|
||||||
|
{
|
||||||
|
Dataset = clonedDataset
|
||||||
|
};
|
||||||
|
|
||||||
|
bool finalReceived = false;
|
||||||
|
|
||||||
|
// PACS 返回响应时写入 channel
|
||||||
|
forward.OnResponseReceived += (rq, rp) =>
|
||||||
|
{
|
||||||
|
var dsCopy = rp.Dataset?.Clone();
|
||||||
|
var proxyResp = new DicomCMoveResponse(request, rp.Status)
|
||||||
|
{
|
||||||
|
Dataset = dsCopy,
|
||||||
|
Remaining = rp.Remaining,
|
||||||
|
Completed = rp.Completed,
|
||||||
|
Failures = rp.Failures,
|
||||||
|
Warnings = rp.Warnings,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Logger.LogInformation($"Completed:{rp.Completed}");
|
||||||
|
|
||||||
|
|
||||||
|
channel.Writer.TryWrite(proxyResp);
|
||||||
|
|
||||||
|
if (!rp.Status.Equals(DicomStatus.Pending))
|
||||||
|
{
|
||||||
|
finalReceived = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// 异步发送到真实 PACS
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var client = DicomClientFactory.Create(find.IP, find.Port, false, hirClient.CalledAE, find.CalledAE);
|
||||||
|
await client.AddRequestAsync(forward);
|
||||||
|
await client.SendAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Error forwarding C-MOVE: " + ex.Message);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
channel.Writer.Complete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 异步 yield 回上游
|
||||||
|
await foreach (var resp in channel.Reader.ReadAllAsync())
|
||||||
|
{
|
||||||
|
yield return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兜底
|
||||||
|
if (!finalReceived)
|
||||||
|
{
|
||||||
|
yield return new DicomCMoveResponse(request, DicomStatus.Success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,8 +20,6 @@ namespace IRaCIS.Core.API.HostService;
|
|||||||
|
|
||||||
public class HangfireHostService(IRecurringMessageScheduler _recurringMessageScheduler,
|
public class HangfireHostService(IRecurringMessageScheduler _recurringMessageScheduler,
|
||||||
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
|
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
|
||||||
|
|
||||||
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
|
|
||||||
IMediator _mediator,
|
IMediator _mediator,
|
||||||
ILogger<HangfireHostService> _logger) : IHostedService
|
ILogger<HangfireHostService> _logger) : IHostedService
|
||||||
{
|
{
|
||||||
@@ -57,20 +55,6 @@ public class HangfireHostService(IRecurringMessageScheduler _recurringMessageSch
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 系统邮件定时任务
|
|
||||||
var systemTaskInfoList = await _emailNoticeConfigrepository.Where(t => t.EmailCron != string.Empty && t.IsAutoSend)
|
|
||||||
.Select(t => new { t.Id, t.Code, t.EmailCron, t.BusinessScenarioEnum, })
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
foreach (var task in systemTaskInfoList)
|
|
||||||
{
|
|
||||||
//利用主键作为任务Id
|
|
||||||
var jobId = $"{task.Id}_({task.BusinessScenarioEnum})";
|
|
||||||
|
|
||||||
HangfireJobHelper.AddOrUpdateSystemCronJob(jobId, task.BusinessScenarioEnum, task.EmailCron);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//await _recurringMessageScheduler.ScheduleRecurringPublish(new QCImageQuestionSchedule() { CronExpression = "0/3 * * * * ? " }, new MasstransiTestCommand { value = "message at " + DateTime.Now.ToString() });
|
//await _recurringMessageScheduler.ScheduleRecurringPublish(new QCImageQuestionSchedule() { CronExpression = "0/3 * * * * ? " }, new MasstransiTestCommand { value = "message at " + DateTime.Now.ToString() });
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -69,23 +69,22 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.14" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.19" />
|
||||||
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.15">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="ConfigMapFileProvider" Version="2.0.1" />
|
<PackageReference Include="ConfigMapFileProvider" Version="2.0.1" />
|
||||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.18" />
|
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.20" />
|
||||||
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
|
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
|
||||||
<PackageReference Include="Hangfire.InMemory" Version="1.0.0" />
|
<PackageReference Include="Hangfire.InMemory" Version="1.0.0" />
|
||||||
<PackageReference Include="Hangfire.SqlServer" Version="1.8.18" />
|
<PackageReference Include="Hangfire.SqlServer" Version="1.8.20" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
|
||||||
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" />
|
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Email" Version="4.0.0" />
|
<PackageReference Include="Serilog.Sinks.Email" Version="4.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="8.1.1" />
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="9.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -111,6 +110,54 @@
|
|||||||
<Content Update="Resources\zh-CN.json">
|
<Content Update="Resources\zh-CN.json">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\downLoad\file.txt">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\ReportTemplate_IRECIST_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\ReportTemplate_PCWG3_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\ReportTemplate_RECIST1.1_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\TumorEvaluation_IRECIST1.1_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\TumorEvaluation_IRECIST1.1_EN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\TumorEvaluation_RECIST1.1_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\协和\ReportTemplate_IRECIST_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\协和\ReportTemplate_PCWG3_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\协和\ReportTemplate_RECIST1.1_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\同济\ReportTemplate_IRECIST_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\同济\ReportTemplate_PCWG3_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\同济\ReportTemplate_RECIST1.1_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\复旦大学肿瘤附属医院\ReportTemplate_IRECIST_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\复旦大学肿瘤附属医院\ReportTemplate_PCWG3_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\ReadReoprtTemplate\医院模板\复旦大学肿瘤附属医院\ReportTemplate_RECIST1.1_CN_V1.docx">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -275,13 +275,7 @@
|
|||||||
<param name="opt"></param>
|
<param name="opt"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.UserConfirm(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.UserConfirmCommand})">
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.ConfirmReReading(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.ViewModel.ConfirmReReadingCommand},IRaCIS.Core.Application.Service.IVisitTaskHelpeService,IRaCIS.Core.Application.Service.IVisitTaskService)">
|
||||||
<summary>
|
|
||||||
用户 签名某个文档
|
|
||||||
</summary>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.ConfirmReReading(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.ViewModel.ConfirmReReadingCommand},IRaCIS.Core.Application.Service.IVisitTaskService)">
|
|
||||||
<summary>
|
<summary>
|
||||||
重阅同意
|
重阅同意
|
||||||
</summary>
|
</summary>
|
||||||
@@ -343,6 +337,16 @@
|
|||||||
</summary>
|
</summary>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.DownloadReadingReportAndImage(IRaCIS.Core.Application.Contracts.IReadingImageTaskService,IRaCIS.Core.Application.Helper.IOSSService,Microsoft.AspNetCore.SignalR.IHubContext{IRaCIS.Core.API.DownloadHub,IRaCIS.Core.API.IDownloadClient},IRaCIS.Core.Application.Service.Reading.Dto.GetReadingReportAndImageInDto)">
|
||||||
|
<summary>
|
||||||
|
下载阅片报告和图片
|
||||||
|
</summary>
|
||||||
|
<param name="_readingImageTaskService"></param>
|
||||||
|
<param name="_oSSService"></param>
|
||||||
|
<param name="_downLoadHub"></param>
|
||||||
|
<param name="inCommand"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
<member name="T:IRaCIS.Core.API.IpPolicyRateLimitSetup">
|
<member name="T:IRaCIS.Core.API.IpPolicyRateLimitSetup">
|
||||||
<summary>
|
<summary>
|
||||||
IPLimit限流 启动服务
|
IPLimit限流 启动服务
|
||||||
|
|||||||
+26
-21
@@ -1,4 +1,6 @@
|
|||||||
using IRaCIS.Core.API;
|
using FellowOakDicom.Network;
|
||||||
|
using FellowOakDicom;
|
||||||
|
using IRaCIS.Core.API;
|
||||||
using IRaCIS.Core.API.HostService;
|
using IRaCIS.Core.API.HostService;
|
||||||
using IRaCIS.Core.Application.BusinessFilter;
|
using IRaCIS.Core.Application.BusinessFilter;
|
||||||
using IRaCIS.Core.Application.Filter;
|
using IRaCIS.Core.Application.Filter;
|
||||||
@@ -24,6 +26,9 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using FellowOakDicom.Imaging.NativeCodec;
|
||||||
|
using FellowOakDicom.Imaging;
|
||||||
|
using IRaCIS.Core.Application.Contracts;
|
||||||
|
|
||||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||||
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
|
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
|
||||||
@@ -36,11 +41,6 @@ var config = new ConfigurationBuilder()
|
|||||||
|
|
||||||
var enviromentName = config["ASPNETCORE_ENVIRONMENT"];
|
var enviromentName = config["ASPNETCORE_ENVIRONMENT"];
|
||||||
|
|
||||||
var openSwaggerStr = config["ASPNETCORE_OpenSwagger"];
|
|
||||||
|
|
||||||
var isOpenSwagger= openSwaggerStr == null|| openSwaggerStr?.ToLower()=="true";
|
|
||||||
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(enviromentName))
|
if (string.IsNullOrWhiteSpace(enviromentName))
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -104,6 +104,8 @@ builder.Services.AddControllers(options =>
|
|||||||
})
|
})
|
||||||
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
|
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
|
||||||
|
|
||||||
|
builder.Services.AddOptions().Configure<DicomSCPServiceOption>(_configuration.GetSection("DicomSCPServiceConfig"));
|
||||||
|
|
||||||
// Panda动态WebApi + UnifiedApiResultFilter + 省掉控制器代码
|
// Panda动态WebApi + UnifiedApiResultFilter + 省掉控制器代码
|
||||||
builder.Services.AddDynamicWebApiSetup();
|
builder.Services.AddDynamicWebApiSetup();
|
||||||
//MinimalAPI
|
//MinimalAPI
|
||||||
@@ -115,13 +117,8 @@ builder.Services.AddAutoMapperSetup();
|
|||||||
builder.Services.AddEFSetup(_configuration, enviromentName);
|
builder.Services.AddEFSetup(_configuration, enviromentName);
|
||||||
//Http 响应压缩
|
//Http 响应压缩
|
||||||
builder.Services.AddResponseCompressionSetup();
|
builder.Services.AddResponseCompressionSetup();
|
||||||
|
|
||||||
if (isOpenSwagger)
|
|
||||||
{
|
|
||||||
//Swagger Api 文档
|
//Swagger Api 文档
|
||||||
builder.Services.AddSwaggerSetup();
|
builder.Services.AddSwaggerSetup();
|
||||||
}
|
|
||||||
|
|
||||||
//JWT Token 验证
|
//JWT Token 验证
|
||||||
builder.Services.AddJWTAuthSetup(_configuration);
|
builder.Services.AddJWTAuthSetup(_configuration);
|
||||||
|
|
||||||
@@ -134,11 +131,17 @@ builder.Services.AddFusionCache();
|
|||||||
// hangfire 定时任务框架 有界面,更友好~
|
// hangfire 定时任务框架 有界面,更友好~
|
||||||
builder.Services.AddhangfireSetup(_configuration);
|
builder.Services.AddhangfireSetup(_configuration);
|
||||||
|
|
||||||
//Serilog 日志可视化 LogDashboard日志
|
|
||||||
//builder.Services.AddLogDashboardSetup();
|
|
||||||
|
|
||||||
//Dicom影像渲染图片 跨平台
|
//Dicom影像渲染图片 跨平台
|
||||||
builder.Services.AddDicomSetup();
|
|
||||||
|
builder.Services.AddFellowOakDicom().AddTranscoderManager<NativeTranscoderManager>()
|
||||||
|
//.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
||||||
|
.AddImageManager<ImageSharpImageManager>();
|
||||||
|
//builder.Services.AddDicomSetup();
|
||||||
|
|
||||||
|
new DicomSetupBuilder()
|
||||||
|
.SkipValidation()
|
||||||
|
.Build();
|
||||||
|
|
||||||
// 实时应用
|
// 实时应用
|
||||||
builder.Services.AddSignalR();
|
builder.Services.AddSignalR();
|
||||||
@@ -153,6 +156,7 @@ builder.Services.AddSignalR();
|
|||||||
|
|
||||||
//builder.Services.AddAntiforgery();
|
//builder.Services.AddAntiforgery();
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
@@ -219,19 +223,12 @@ app.UseResponseCompression();
|
|||||||
//不需要 token 访问的静态文件 wwwroot css, JavaScript, and images don't require authentication.
|
//不需要 token 访问的静态文件 wwwroot css, JavaScript, and images don't require authentication.
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
|
||||||
//LogDashboard
|
|
||||||
//app.UseLogDashboard("/LogDashboard");
|
|
||||||
|
|
||||||
//hangfire
|
//hangfire
|
||||||
app.UseHangfireConfig(env);
|
app.UseHangfireConfig(env);
|
||||||
|
|
||||||
// Swagger
|
// Swagger
|
||||||
|
|
||||||
if (isOpenSwagger)
|
|
||||||
{
|
|
||||||
SwaggerSetup.Configure(app, env);
|
SwaggerSetup.Configure(app, env);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//serilog 记录请求的用户信息
|
//serilog 记录请求的用户信息
|
||||||
app.UseSerilogConfig(env);
|
app.UseSerilogConfig(env);
|
||||||
@@ -250,6 +247,7 @@ app.MapMasaMinimalAPIs();
|
|||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|
||||||
app.MapHub<UploadHub>("/UploadHub");
|
app.MapHub<UploadHub>("/UploadHub");
|
||||||
|
app.MapHub<DownloadHub>("/DownloadHub");
|
||||||
app.MapHealthChecks("/health");
|
app.MapHealthChecks("/health");
|
||||||
|
|
||||||
|
|
||||||
@@ -291,6 +289,13 @@ try
|
|||||||
//Log.Logger.Warning($"ContentRootPath——xx:{Path.GetDirectoryName(Path.GetDirectoryName(env.ContentRootPath))}");
|
//Log.Logger.Warning($"ContentRootPath——xx:{Path.GetDirectoryName(Path.GetDirectoryName(env.ContentRootPath))}");
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
DicomSetupBuilder.UseServiceProvider(app.Services);
|
||||||
|
|
||||||
|
var logger = app.Services.GetService<Microsoft.Extensions.Logging.ILogger<Program>>();
|
||||||
|
|
||||||
|
var server = DicomServerFactory.Create<DicomSCPService>(_configuration.GetSection("DicomSCPServiceConfig").GetValue<int>("ServerPort"), userState: app.Services, logger: logger);
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,69 +16,39 @@
|
|||||||
"ASPNETCORE_ENVIRONMENT": "Test_IRC"
|
"ASPNETCORE_ENVIRONMENT": "Test_IRC"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"IRaCIS.Test_IRC": {
|
"Uat_HIR": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Test_IRC",
|
"ASPNETCORE_ENVIRONMENT": "Uat_HIR"
|
||||||
"ASPNETCORE_OpenSwagger": "true"
|
|
||||||
},
|
},
|
||||||
"applicationUrl": "http://localhost:6100"
|
"applicationUrl": "http://localhost:6100"
|
||||||
},
|
},
|
||||||
"IRaCIS.Test_IRC_PGSQL": {
|
"Prod_HIR": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Test_IRC_PGSQL"
|
"ASPNETCORE_ENVIRONMENT": "Prod_HIR"
|
||||||
},
|
},
|
||||||
"applicationUrl": "http://localhost:6100"
|
"applicationUrl": "http://localhost:6100"
|
||||||
},
|
},
|
||||||
"IRaCIS.Event_IRC": {
|
"US_HIR": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Event_IRC"
|
"ASPNETCORE_ENVIRONMENT": "US_HIR"
|
||||||
},
|
},
|
||||||
"applicationUrl": "http://localhost:6100"
|
"applicationUrl": "http://localhost:6100"
|
||||||
},
|
},
|
||||||
"Docker": {
|
"Test_HIR": {
|
||||||
"commandName": "Docker",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
|
|
||||||
"publishAllPorts": true
|
|
||||||
},
|
|
||||||
"IRaCIS.Uat_IRC": {
|
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Uat_IRC"
|
"ASPNETCORE_ENVIRONMENT": "Test_HIR"
|
||||||
},
|
|
||||||
"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"
|
|
||||||
},
|
|
||||||
"applicationUrl": "http://localhost:6100"
|
|
||||||
},
|
|
||||||
"IRaCIS.US_Prod_IRC": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "US_Prod_IRC"
|
|
||||||
},
|
},
|
||||||
"applicationUrl": "http://localhost:6100"
|
"applicationUrl": "http://localhost:6100"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,14 +3,12 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Cors;
|
using Microsoft.AspNetCore.Cors;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace IRaCIS.Core.API
|
namespace IRaCIS.Core.API
|
||||||
{
|
{
|
||||||
public interface IUploadClient
|
|
||||||
{
|
|
||||||
Task ReceivProgressAsync(string studyInstanceUid, int haveReceivedCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class IRaCISUserIdProvider : IUserIdProvider
|
public class IRaCISUserIdProvider : IUserIdProvider
|
||||||
@@ -21,6 +19,11 @@ namespace IRaCIS.Core.API
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IUploadClient
|
||||||
|
{
|
||||||
|
Task ReceivProgressAsync(string studyInstanceUid, int haveReceivedCount);
|
||||||
|
}
|
||||||
|
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[DisableCors]
|
[DisableCors]
|
||||||
public class UploadHub : Hub<IUploadClient>
|
public class UploadHub : Hub<IUploadClient>
|
||||||
@@ -53,5 +56,34 @@ namespace IRaCIS.Core.API
|
|||||||
// await Clients.All.ReceivProgressAsync(studyInstanceUid, haveReceivedCount);
|
// await Clients.All.ReceivProgressAsync(studyInstanceUid, haveReceivedCount);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface IDownloadClient
|
||||||
|
{
|
||||||
|
Task ReceivProgressAsync(string downloadId, object percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[AllowAnonymous]
|
||||||
|
[DisableCors]
|
||||||
|
public class DownloadHub : Hub<IDownloadClient>
|
||||||
|
{
|
||||||
|
|
||||||
|
public ILogger<DownloadHub> _logger { get; set; }
|
||||||
|
public DownloadHub(ILogger<DownloadHub> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task OnConnectedAsync()
|
||||||
|
{
|
||||||
|
_logger.LogError("连接: " + Context.ConnectionId);
|
||||||
|
|
||||||
|
return base.OnConnectedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
//using LogDashboard;
|
|
||||||
//using LogDashboard.Authorization;
|
|
||||||
|
|
||||||
//namespace IRaCIS.Core.API.Filter
|
|
||||||
//{
|
|
||||||
|
|
||||||
// public class LogDashBoardAuthFilter : ILogDashboardAuthorizationFilter
|
|
||||||
// {
|
|
||||||
// //在此可以利用 本系统的UerTypeEnum 判断
|
|
||||||
// public bool Authorization(LogDashboardContext context)
|
|
||||||
// {
|
|
||||||
// return context.HttpContext.User.Identity.IsAuthenticated;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
@@ -21,6 +21,7 @@ namespace IRaCIS.Core.API
|
|||||||
=>
|
=>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
opts.MessageTemplate = "{FullName} {UserType} {UserIp} {Host} {RequestMethod} {RequestPath} {RequestBody} responded {StatusCode} in {Elapsed:0.0000} ms";
|
opts.MessageTemplate = "{FullName} {UserType} {UserIp} {Host} {RequestMethod} {RequestPath} {RequestBody} responded {StatusCode} in {Elapsed:0.0000} ms";
|
||||||
|
|
||||||
opts.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
|
opts.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ namespace IRaCIS.Core.API
|
|||||||
OnMessageReceived = (context) =>
|
OnMessageReceived = (context) =>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (context.Request.Query.TryGetValue("access_token", out StringValues values))
|
if (context.Request.Query.TryGetValue("access_token", out StringValues values))
|
||||||
{
|
{
|
||||||
var queryToken = values.FirstOrDefault();
|
var queryToken = values.FirstOrDefault();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using FellowOakDicom;
|
using FellowOakDicom;
|
||||||
using FellowOakDicom.Imaging;
|
using FellowOakDicom.Imaging;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace IRaCIS.Core.API
|
namespace IRaCIS.Core.API
|
||||||
{
|
{
|
||||||
@@ -9,12 +10,14 @@ namespace IRaCIS.Core.API
|
|||||||
public static void AddDicomSetup(this IServiceCollection services)
|
public static void AddDicomSetup(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
new DicomSetupBuilder()
|
new DicomSetupBuilder()
|
||||||
.RegisterServices(s => s.AddFellowOakDicom()
|
.RegisterServices(s => s.AddFellowOakDicom().AddLogging(config => config.AddConsole())
|
||||||
.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
||||||
.AddImageManager<ImageSharpImageManager>()
|
//.AddImageManager<ImageSharpImageManager>()
|
||||||
)
|
)
|
||||||
.SkipValidation()
|
.SkipValidation()
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,12 +40,12 @@ namespace IRaCIS.Core.API
|
|||||||
var dbType = configuration.GetSection("ConnectionStrings:Db_Type").Value;
|
var dbType = configuration.GetSection("ConnectionStrings:Db_Type").Value;
|
||||||
if (!string.IsNullOrWhiteSpace(dbType) && dbType == "pgsql")
|
if (!string.IsNullOrWhiteSpace(dbType) && dbType == "pgsql")
|
||||||
{
|
{
|
||||||
options.UseNpgsql(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
|
options.UseNpgsql(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure().CommandTimeout(90));
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
|
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure().CommandTimeout(90));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -82,13 +82,16 @@ namespace IRaCIS.Core.API
|
|||||||
|
|
||||||
triggerOptions.AddTrigger<UserAddTrigger>();
|
triggerOptions.AddTrigger<UserAddTrigger>();
|
||||||
|
|
||||||
|
triggerOptions.AddTrigger<IdenttiyUserRoleInfoTrigger>();
|
||||||
|
|
||||||
triggerOptions.AddTrigger<UserLogAfterTrigger>();
|
triggerOptions.AddTrigger<UserLogAfterTrigger>();
|
||||||
|
|
||||||
triggerOptions.AddTrigger<IdenttiyUserRoleInfoTrigger>();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Register an additional context factory as a Scoped service, which gets a pooled context from the Singleton factory we registered above,
|
// Register an additional context factory as a Scoped service, which gets a pooled context from the Singleton factory we registered above,
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
//using LogDashboard;
|
|
||||||
//using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
//namespace IRaCIS.Core.API
|
|
||||||
//{
|
|
||||||
// public static class LogDashboardSetup
|
|
||||||
// {
|
|
||||||
// public static void AddLogDashboardSetup(this IServiceCollection services)
|
|
||||||
// {
|
|
||||||
// //IIS 配置虚拟路径部署,会出现IIS静态文件404
|
|
||||||
// services.AddLogDashboard(opt =>
|
|
||||||
// {
|
|
||||||
// //opt.PathMatch = "/api/LogDashboard";
|
|
||||||
// opt.PathMatch = "/LogDashboard";
|
|
||||||
|
|
||||||
// //opt.AddAuthorizationFilter(new LogDashboardBasicAuthFilter("admin", "zhizhun2018"));
|
|
||||||
|
|
||||||
// //opt.AddAuthorizationFilter(new LogDashBoardAuthFilter());
|
|
||||||
|
|
||||||
// });
|
|
||||||
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
@@ -22,6 +22,9 @@ namespace IRaCIS.Core.API
|
|||||||
var config = new LoggerConfiguration()
|
var config = new LoggerConfiguration()
|
||||||
.MinimumLevel.Information()
|
.MinimumLevel.Information()
|
||||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
||||||
|
.MinimumLevel.Override("MassTransit", LogEventLevel.Warning)
|
||||||
|
//https://github.com/ZiggyCreatures/FusionCache/blob/main/docs/Logging.md
|
||||||
|
.MinimumLevel.Override("ZiggyCreatures.Caching.Fusion", LogEventLevel.Warning)
|
||||||
// Filter out ASP.NET Core infrastructre logs that are Information and below 日志太多了 一个请求 记录好几条
|
// Filter out ASP.NET Core infrastructre logs that are Information and below 日志太多了 一个请求 记录好几条
|
||||||
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
||||||
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting", LogEventLevel.Warning)
|
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting", LogEventLevel.Warning)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using IP2Region.Net.Abstractions;
|
using IP2Region.Net.Abstractions;
|
||||||
using IP2Region.Net.XDB;
|
using IP2Region.Net.XDB;
|
||||||
|
using IRaCIS.Application.Contracts;
|
||||||
using IRaCIS.Core.Application.BackGroundJob;
|
using IRaCIS.Core.Application.BackGroundJob;
|
||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using IRaCIS.Core.Application.Service;
|
using IRaCIS.Core.Application.Service;
|
||||||
|
|||||||
@@ -16,30 +16,31 @@ namespace IRaCIS.Core.API;
|
|||||||
|
|
||||||
public enum SwaggerVersion
|
public enum SwaggerVersion
|
||||||
{
|
{
|
||||||
[Description("文件记录(FileRecord)")]
|
[Description("HIR修改")]
|
||||||
FileRecord = -1,
|
HIR = -1,
|
||||||
|
|
||||||
[Description("医生模块(Reviewer)")]
|
[Description("医生模块")]
|
||||||
Reviewer = 1,
|
Reviewer = 1,
|
||||||
[Description("项目模块(Trial)")]
|
|
||||||
|
[Description("项目模块")]
|
||||||
Trial = 2,
|
Trial = 2,
|
||||||
[Description("入组模块(Enroll)")]
|
[Description("入组模块")]
|
||||||
Enroll = 3,
|
Enroll = 3,
|
||||||
[Description("工作量模块(Workload)")]
|
[Description("工作量模块")]
|
||||||
Workload = 4,
|
Workload = 4,
|
||||||
[Description("通用信息获取(Common)")]
|
[Description("通用信息获取")]
|
||||||
Common = 5,
|
Common = 5,
|
||||||
[Description("机构信息模块(Institution)")]
|
[Description("机构信息模块")]
|
||||||
Institution = 6,
|
Institution = 6,
|
||||||
[Description("统计模块(DashboardStatistics)")]
|
[Description("统计模块")]
|
||||||
DashboardStatistics = 7,
|
DashboardStatistics = 7,
|
||||||
[Description("财务模块(Financial)")]
|
[Description("财务模块")]
|
||||||
Financial = 8,
|
Financial = 8,
|
||||||
[Description("管理模块(Management)")]
|
[Description("管理模块")]
|
||||||
Management = 9,
|
Management = 9,
|
||||||
[Description("影像模块(Image)")]
|
[Description("影像模块")]
|
||||||
Image = 10,
|
Image = 10,
|
||||||
[Description("读片模块(Reading)")]
|
[Description("读片模块")]
|
||||||
Reading = 11
|
Reading = 11
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -118,6 +119,9 @@ public static class SwaggerSetup
|
|||||||
|
|
||||||
//DefaultModelsExpandDepth设置为 - 1 可不显示models
|
//DefaultModelsExpandDepth设置为 - 1 可不显示models
|
||||||
options.DefaultModelsExpandDepth(-1);
|
options.DefaultModelsExpandDepth(-1);
|
||||||
|
|
||||||
|
// 关键一句:关闭外网校验
|
||||||
|
options.ConfigObject.ValidatorUrl = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"RemoteNew": "Server=101.132.253.119,1435;Database=irc_Prpd_bak;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=101.132.253.119,1435;Database=irc_Hangfire_bak;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
"ObjectStoreService": {
|
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
|
||||||
"AliyunOSS": {
|
|
||||||
"RegionId": "cn-shanghai",
|
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"AccessKeyId": "LTAI5tNRTsqL6aWmHkDmTwoH",
|
|
||||||
"AccessKeySecret": "7mtGz3qrYWI6JMMBZiLeC119VWicZH",
|
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/irc-oss-access",
|
|
||||||
"BucketName": "zy-irc-store",
|
|
||||||
"ViewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"Region": "oss-cn-shanghai",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
},
|
|
||||||
"MinIO": {
|
|
||||||
"endpoint": "http://192.168.3.68",
|
|
||||||
"port": "8001",
|
|
||||||
"useSSL": false,
|
|
||||||
"accessKey": "IDFkwEpWej0b4DtiuThL",
|
|
||||||
"secretKey": "Lhuu83yMhVwu7c1SnjvGY6lq74jzpYqifK6Qtj4h",
|
|
||||||
"bucketName": "test"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"BasicSystemConfig": {
|
|
||||||
|
|
||||||
"OpenUserComplexPassword": true,
|
|
||||||
|
|
||||||
"OpenSignDocumentBeforeWork": true,
|
|
||||||
|
|
||||||
"OpenLoginLimit": true,
|
|
||||||
"LoginMaxFailCount": 5,
|
|
||||||
|
|
||||||
"LoginFailLockMinutes": 30,
|
|
||||||
"AutoLoginOutMinutes": 60,
|
|
||||||
|
|
||||||
"ContinuousReadingTimeMin": 120,
|
|
||||||
|
|
||||||
"ReadingRestTimeMin": 10,
|
|
||||||
|
|
||||||
"IsNeedChangePassWord": true,
|
|
||||||
|
|
||||||
"ChangePassWordDays": 90,
|
|
||||||
|
|
||||||
// 模板类型 1 Elevate 2 Extensive
|
|
||||||
"TemplateType": 2
|
|
||||||
},
|
|
||||||
"SystemEmailSendConfig": {
|
|
||||||
"Port": 465,
|
|
||||||
"Host": "smtp.qiye.aliyun.com",
|
|
||||||
"FromEmail": "uat@extimaging.com",
|
|
||||||
"FromName": "UAT_IRC",
|
|
||||||
"AuthorizationCode": "SHzyyl2021",
|
|
||||||
"SiteUrl": "http://irc.event.extimaging.com/login",
|
|
||||||
"CompanyName": "Extensive Imaging",
|
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
|
||||||
"CompanyShortName": "Extensive Imaging",
|
|
||||||
"CompanyShortNameCN": "展影医疗",
|
|
||||||
"IsEnv_US": false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ObjectStoreService": {
|
||||||
|
"ObjectStoreUse": "MinIO",
|
||||||
|
"MinIO": {
|
||||||
|
"EndPoint": "hir-oss.tres.extimaging.com",
|
||||||
|
"Port": "443",
|
||||||
|
"UseSSL": true,
|
||||||
|
"AccessKeyId": "fbStsVYCIPKHQneeqMwD",
|
||||||
|
"SecretAccessKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
|
||||||
|
"BucketName": "hir-images",
|
||||||
|
"ViewEndpoint": "https://hir-oss.tres.extimaging.com/hir-images"
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"RemoteNew": "Server=mssql,1433;Database=HIR_Prod;User ID=sa;Password=xc_123456;TrustServerCertificate=true",
|
||||||
|
"Hangfire": "Server=mssql,1433;Database=HIR_Prod_Hangfire;User ID=sa;Password=xc_123456;TrustServerCertificate=true"
|
||||||
|
},
|
||||||
|
"BasicSystemConfig": {
|
||||||
|
"OpenUserComplexPassword": true,
|
||||||
|
"OpenSignDocumentBeforeWork": true,
|
||||||
|
"OpenTrialRelationDelete": true,
|
||||||
|
"OpenLoginLimit": false,
|
||||||
|
"LoginMaxFailCount": 5,
|
||||||
|
"LoginFailLockMinutes": 30,
|
||||||
|
"AutoLoginOutMinutes": 120,
|
||||||
|
"AESKey": "HIR_System_AES_Key_Info",
|
||||||
|
"CmoveIntervalMinutes": 1,
|
||||||
|
"CmoveInstanceIntervalMinutes": 1,
|
||||||
|
// 是否强制用户定期修改密码
|
||||||
|
"IsNeedChangePassWord": true,
|
||||||
|
// 密码有效期(天),到期后必须修改
|
||||||
|
"ChangePassWordDays": 1000,
|
||||||
|
"OpenImageShare": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"SystemEmailSendConfig": {
|
||||||
|
"Port": 465,
|
||||||
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
|
"FromEmail": "test@extimaging.com",
|
||||||
|
"FromName": "BCTOP",
|
||||||
|
"AuthorizationCode": "SHzyyl2021",
|
||||||
|
"SiteUrl": "https://bctop.tres.extimaging.com/login",
|
||||||
|
"CompanyName": "BCTOP",
|
||||||
|
"CompanyNameCN": "BCTOP",
|
||||||
|
"CompanyShortName": "BCTOP",
|
||||||
|
"CompanyShortNameCN": "BCTOP",
|
||||||
|
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
|
||||||
|
},
|
||||||
|
"DicomSCPServiceConfig": {
|
||||||
|
"IsSupportThirdService": true,
|
||||||
|
"ThirdSearchPacsAE": "XCPACS",
|
||||||
|
"ThirdCallningAE": "LYAE",
|
||||||
|
"CalledAEList": [
|
||||||
|
"HIRSCUAE",
|
||||||
|
"HIRSCPAE"
|
||||||
|
],
|
||||||
|
"ServerPort": 11112
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ConnectionStrings": {
|
|
||||||
//"RemoteNew": "Server=101.132.193.237,1434;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
|
||||||
//"Hangfire": "Server=101.132.193.237,1434;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
|
||||||
"RemoteNew": "Server=prod_mssql_standard,1433;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=prod_mssql_standard,1433;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
"ObjectStoreService": {
|
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
|
||||||
"AliyunOSS": {
|
|
||||||
"RegionId": "cn-shanghai",
|
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"AccessKeyId": "LTAI5tNRTsqL6aWmHkDmTwoH",
|
|
||||||
"AccessKeySecret": "7mtGz3qrYWI6JMMBZiLeC119VWicZH",
|
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/irc-oss-access",
|
|
||||||
"BucketName": "zy-irc-store",
|
|
||||||
"ViewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"Region": "oss-cn-shanghai",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
},
|
|
||||||
"MinIO": {
|
|
||||||
"endpoint": "http://192.168.3.68",
|
|
||||||
"port": "8001",
|
|
||||||
"useSSL": false,
|
|
||||||
"accessKey": "IDFkwEpWej0b4DtiuThL",
|
|
||||||
"secretKey": "Lhuu83yMhVwu7c1SnjvGY6lq74jzpYqifK6Qtj4h",
|
|
||||||
"bucketName": "test"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"BasicSystemConfig": {
|
|
||||||
|
|
||||||
"OpenUserComplexPassword": true,
|
|
||||||
"OpenSignDocumentBeforeWork": true,
|
|
||||||
|
|
||||||
"OpenLoginLimit": true,
|
|
||||||
"LoginMaxFailCount": 5,
|
|
||||||
"LoginFailLockMinutes": 30,
|
|
||||||
"AutoLoginOutMinutes": 120,
|
|
||||||
|
|
||||||
"OpenLoginMFA": false,
|
|
||||||
|
|
||||||
"ContinuousReadingTimeMin": 120,
|
|
||||||
"ReadingRestTimeMin": 10,
|
|
||||||
|
|
||||||
"IsNeedChangePassWord": true,
|
|
||||||
"ChangePassWordDays": 90,
|
|
||||||
// 模板类型 1 Elevate 2 Extensive
|
|
||||||
"TemplateType": 2
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemEmailSendConfig": {
|
|
||||||
"Port": 465,
|
|
||||||
"Host": "smtp.qiye.aliyun.com",
|
|
||||||
"FromEmail": "irc@extimaging.com",
|
|
||||||
"FromName": "irc",
|
|
||||||
"AuthorizationCode": "ExtImg@2022",
|
|
||||||
"SiteUrl": "http://irc.extimaging.com/login",
|
|
||||||
"SystemShortName": "IRC",
|
|
||||||
"OrganizationName": "Extlmaging",
|
|
||||||
"OrganizationNameCN": "Extlmaging",
|
|
||||||
"CompanyName": "Extensive Imaging",
|
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
|
||||||
"CompanyShortName": "Extensive Imaging",
|
|
||||||
"CompanyShortNameCN": "展影医疗",
|
|
||||||
"IsEnv_US": false,
|
|
||||||
"IsOpenErrorNoticeEmail": false,
|
|
||||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
|
||||||
},
|
|
||||||
"SystemPacsConfig": {
|
|
||||||
"Port": "11113",
|
|
||||||
"IP": "101.132.193.237"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ObjectStoreService": {
|
||||||
|
"ObjectStoreUse": "MinIO",
|
||||||
|
"MinIO": {
|
||||||
|
"EndPoint": "192.168.40.99",
|
||||||
|
"Port": "9000",
|
||||||
|
"UseSSL": false,
|
||||||
|
"AccessKeyId": "Jnywl9aIw83yewZIJKod",
|
||||||
|
"SecretAccessKey": "N83bTzoJGkg4OLW8x54IZRwwSvdxcdYi9UZ2BYII",
|
||||||
|
"BucketName": "tj-hir",
|
||||||
|
"ViewEndpoint": "http://192.168.40.99:9000/tj-hir"
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"RemoteNew": "Server=192.168.40.98,1433;Database=TJ_Prod_HIR;User ID=sa;Password=xc_123456;TrustServerCertificate=true",
|
||||||
|
"Hangfire": "Server=192.168.40.98,1433;Database=TJ_Prod_HIR_Hangfire;User ID=sa;Password=xc_123456;TrustServerCertificate=true"
|
||||||
|
},
|
||||||
|
"BasicSystemConfig": {
|
||||||
|
"OpenUserComplexPassword": true,
|
||||||
|
"OpenSignDocumentBeforeWork": false,
|
||||||
|
"OpenTrialRelationDelete": false,
|
||||||
|
"OpenLoginLimit": true,
|
||||||
|
"LoginMaxFailCount": 5,
|
||||||
|
"LoginFailLockMinutes": 30,
|
||||||
|
"AutoLoginOutMinutes": 120,
|
||||||
|
"AESKey": "HIR_System_AES_Key_Info",
|
||||||
|
"CmoveIntervalMinutes": 1,
|
||||||
|
"CmoveInstanceIntervalMinutes": 1
|
||||||
|
},
|
||||||
|
"SystemHospitalConfig": {
|
||||||
|
"HospitalCode": "EI",
|
||||||
|
"HospitalLogoPath": "/System/GeneralDocuments/1716453306898_图片2.png",
|
||||||
|
"TrialKeepCount": 60,
|
||||||
|
"HospitalName": "上海展影医疗科技有限公司",
|
||||||
|
"HospitalAliasName": "展影医疗",
|
||||||
|
"Country": "中国",
|
||||||
|
"City": "上海",
|
||||||
|
"Province": "上海",
|
||||||
|
"Address": "上海市杨浦区国泰路复旦科技园",
|
||||||
|
"Phone": "021-60702575",
|
||||||
|
"IsCanConnectInternet": false
|
||||||
|
},
|
||||||
|
"SystemEmailSendConfig": {
|
||||||
|
"Port": 465,
|
||||||
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
|
"FromEmail": "test-study@extimaging.com",
|
||||||
|
"FromName": "Test_HIR",
|
||||||
|
"AuthorizationCode": "zhanying123",
|
||||||
|
"SiteUrl": "http://hir.test.extimaging.com/login"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ObjectStoreService": {
|
||||||
|
"ObjectStoreUse": "MinIO",
|
||||||
|
"MinIO": {
|
||||||
|
"EndPoint": "hir-oss.test.extimaging.com",
|
||||||
|
"Port": "443",
|
||||||
|
"UseSSL": true,
|
||||||
|
//"endPoint": "106.14.89.110",
|
||||||
|
//"port": "9001",
|
||||||
|
//"useSSL": false,
|
||||||
|
"AccessKeyId": "fbStsVYCIPKHQneeqMwD",
|
||||||
|
"SecretAccessKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
|
||||||
|
"BucketName": "hir-test",
|
||||||
|
//"viewEndpoint": "https://hir.test.extimaging.com/oss/hir-test"
|
||||||
|
"ViewEndpoint": "https://hir-oss.test.extimaging.com/hir-test"
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_HIR_New;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
|
"Hangfire": "Server=106.14.89.110,1435;Database=Test_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
|
},
|
||||||
|
"BasicSystemConfig": {
|
||||||
|
"OpenUserComplexPassword": true,
|
||||||
|
"OpenSignDocumentBeforeWork": true,
|
||||||
|
"OpenTrialRelationDelete": true,
|
||||||
|
"OpenLoginLimit": false,
|
||||||
|
"LoginMaxFailCount": 5,
|
||||||
|
"LoginFailLockMinutes": 30,
|
||||||
|
"AutoLoginOutMinutes": 120,
|
||||||
|
"AESKey": "HIR_System_AES_Key_Info",
|
||||||
|
"CmoveIntervalMinutes": 1,
|
||||||
|
"CmoveInstanceIntervalMinutes": 1,
|
||||||
|
// 是否强制用户定期修改密码
|
||||||
|
"IsNeedChangePassWord": true,
|
||||||
|
// 密码有效期(天),到期后必须修改
|
||||||
|
"ChangePassWordDays": 1000,
|
||||||
|
"OpenImageShare": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"SystemEmailSendConfig": {
|
||||||
|
"Port": 465,
|
||||||
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
|
"FromEmail": "test-study@extimaging.com",
|
||||||
|
"FromName": "Test_HIR",
|
||||||
|
"AuthorizationCode": "zhanying123",
|
||||||
|
"SiteUrl": "http://hir.test.extimaging.com/login",
|
||||||
|
"CompanyName": "Extensive Imaging",
|
||||||
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
|
"CompanyShortName": "Extensive Imaging",
|
||||||
|
"CompanyShortNameCN": "展影医疗",
|
||||||
|
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
|
||||||
|
},
|
||||||
|
"DicomSCPServiceConfig": {
|
||||||
|
"IsSupportThirdService": true,
|
||||||
|
"ThirdSearchPacsAE": "XCPACS",
|
||||||
|
"ThirdCallningAE": "LYAE",
|
||||||
|
"CalledAEList": [
|
||||||
|
"HIRSCUAE",
|
||||||
|
"HIRSCPAE"
|
||||||
|
],
|
||||||
|
"ServerPort": 11112
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,11 +23,9 @@
|
|||||||
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
|
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
|
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
|
||||||
"BucketName": "zy-irc-test-store",
|
"BucketName": "zy-irc-test-store",
|
||||||
//"ViewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
|
"ViewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
|
||||||
"ViewEndpoint": "https://zy-irc-test-dev-cache.oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"Region": "oss-cn-shanghai",
|
"Region": "oss-cn-shanghai",
|
||||||
"DurationSeconds": 7200,
|
"DurationSeconds": 7200
|
||||||
"PreviewEndpoint": "https://test-oss.test.extimaging.com"
|
|
||||||
},
|
},
|
||||||
"MinIO": {
|
"MinIO": {
|
||||||
"EndPoint": "hir-oss.test.extimaging.com",
|
"EndPoint": "hir-oss.test.extimaging.com",
|
||||||
@@ -54,26 +52,28 @@
|
|||||||
"BasicSystemConfig": {
|
"BasicSystemConfig": {
|
||||||
|
|
||||||
"OpenUserComplexPassword": false,
|
"OpenUserComplexPassword": false,
|
||||||
|
|
||||||
"OpenSignDocumentBeforeWork": false,
|
"OpenSignDocumentBeforeWork": false,
|
||||||
|
|
||||||
|
"OpenTrialRelationDelete": true,
|
||||||
|
|
||||||
"OpenLoginLimit": false,
|
"OpenLoginLimit": false,
|
||||||
|
|
||||||
"LoginMaxFailCount": 5,
|
"LoginMaxFailCount": 5,
|
||||||
|
|
||||||
"LoginFailLockMinutes": 1,
|
"LoginFailLockMinutes": 1,
|
||||||
"AutoLoginOutMinutes": 10,
|
|
||||||
|
"AutoLoginOutMinutes": 1,
|
||||||
|
|
||||||
"OpenLoginMFA": false,
|
"OpenLoginMFA": false,
|
||||||
|
|
||||||
"ContinuousReadingTimeMin": 120,
|
"ContinuousReadingTimeMin": 120,
|
||||||
|
|
||||||
"ReadingRestTimeMin": 10,
|
"ReadingRestTimeMin": 10,
|
||||||
|
|
||||||
"IsNeedChangePassWord": true,
|
"IsNeedChangePassWord": true,
|
||||||
|
|
||||||
"ChangePassWordDays": 90,
|
"ChangePassWordDays": 90,
|
||||||
|
|
||||||
// 模板类型 1 Elevate 2 Extensive
|
|
||||||
"TemplateType": 2,
|
|
||||||
|
|
||||||
"OpenTrialRelationDelete": true,
|
|
||||||
|
|
||||||
"ThirdPdfUrl": "http://106.14.89.110:30088/api/v1/convert/file/pdf"
|
"ThirdPdfUrl": "http://106.14.89.110:30088/api/v1/convert/file/pdf"
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -85,7 +85,6 @@
|
|||||||
"AuthorizationCode": "SHzyyl2021",
|
"AuthorizationCode": "SHzyyl2021",
|
||||||
"SiteUrl": "http://irc.test.extimaging.com/login",
|
"SiteUrl": "http://irc.test.extimaging.com/login",
|
||||||
|
|
||||||
"SystemShortName": "IRC",
|
|
||||||
"OrganizationName": "Extlmaging",
|
"OrganizationName": "Extlmaging",
|
||||||
"OrganizationNameCN": "Extlmaging",
|
"OrganizationNameCN": "Extlmaging",
|
||||||
"CompanyName": "Extensive Imaging",
|
"CompanyName": "Extensive Imaging",
|
||||||
|
|||||||
@@ -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": "l+yjtvV7Z4jiwm/7xCYv30UeUj/SvuqqYzAwjJHf",
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ObjectStoreService": {
|
||||||
|
"ObjectStoreUse": "MinIO",
|
||||||
|
"MinIO": {
|
||||||
|
"EndPoint": "hir-minio.uat.elevateimaging.ai",
|
||||||
|
"Port": "443",
|
||||||
|
"UseSSL": true,
|
||||||
|
"AccessKeyId": "7rvVIHs7D6pbyscRcJhz",
|
||||||
|
"SecretAccessKey": "DQsCQldHFL3QRjlnaLWV7oM4E9PtsO21QPC2h9BD",
|
||||||
|
"BucketName": "hir-us",
|
||||||
|
//"viewEndpoint": "https://hir.test.extimaging.com/oss/hir-test"
|
||||||
|
"ViewEndpoint": "https://hir-minio.uat.elevateimaging.ai/hir-us"
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"RemoteNew": "Server=3.226.182.187,1435;Database=US_HIR;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
|
"Hangfire": "Server=3.226.182.187,1435;Database=US_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
|
},
|
||||||
|
"BasicSystemConfig": {
|
||||||
|
"OpenUserComplexPassword": true,
|
||||||
|
"OpenSignDocumentBeforeWork": true,
|
||||||
|
"OpenTrialRelationDelete": true,
|
||||||
|
"OpenLoginLimit": true,
|
||||||
|
"LoginMaxFailCount": 5,
|
||||||
|
"LoginFailLockMinutes": 30,
|
||||||
|
"AutoLoginOutMinutes": 120,
|
||||||
|
"AESKey": "HIR_System_AES_Key_Info",
|
||||||
|
"CmoveIntervalMinutes": 1,
|
||||||
|
"CmoveInstanceIntervalMinutes": 1,
|
||||||
|
// 是否强制用户定期修改密码
|
||||||
|
"IsNeedChangePassWord": true,
|
||||||
|
// 密码有效期(天),到期后必须修改
|
||||||
|
"ChangePassWordDays": 1000,
|
||||||
|
"OpenImageShare": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"SystemEmailSendConfig": {
|
||||||
|
"Port": 465,
|
||||||
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
|
"FromEmail": "uat-study@extimaging.com",
|
||||||
|
"FromName": "Uat_HIR",
|
||||||
|
"AuthorizationCode": "zhanying123",
|
||||||
|
"SiteUrl": "https://hir.uat.elevateimaging.ai/login",
|
||||||
|
"CompanyName": "Extensive Imaging",
|
||||||
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
|
"CompanyShortName": "Extensive Imaging",
|
||||||
|
"CompanyShortNameCN": "展影医疗",
|
||||||
|
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
|
||||||
|
},
|
||||||
|
"DicomSCPServiceConfig": {
|
||||||
|
"IsSupportThirdService": true,
|
||||||
|
"ThirdSearchPacsAE": "XCPACS",
|
||||||
|
"ThirdCallningAE": "LYAE",
|
||||||
|
"CalledAEList": [
|
||||||
|
"HIRSCUAE",
|
||||||
|
"HIRSCPAE"
|
||||||
|
],
|
||||||
|
"ServerPort": 11112
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"RemoteNew": "Server=us-mssql-prod,1433;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=us-mssql-prod,1433;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
//"RemoteNew": "Server=44.210.231.169,1435;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
//"Hangfire": "Server=44.210.231.169,1435;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
},
|
|
||||||
|
|
||||||
"ObjectStoreService": {
|
|
||||||
"ObjectStoreUse": "AWS",
|
|
||||||
"MinIO": {
|
|
||||||
"endPoint": "44.210.231.169",
|
|
||||||
"port": "9001",
|
|
||||||
"useSSL": false,
|
|
||||||
"accessKey": "e9bT1isTOqSAUxb6wd4n",
|
|
||||||
"secretKey": "b5TaDzNdQCBtCvfm8eZ3dR6yY7tfZu2JYze2Po1i",
|
|
||||||
"bucketName": "prod-irc-us",
|
|
||||||
"viewEndpoint": "http://44.210.231.169:9001/prod-irc-us/"
|
|
||||||
},
|
|
||||||
|
|
||||||
"AWS": {
|
|
||||||
"Region": "us-east-1",
|
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
|
||||||
"UseSSL": true,
|
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/lili_s3_access",
|
|
||||||
"AccessKeyId": "AKIAW3MEAFJXZ2TZK7GM",
|
|
||||||
"SecretAccessKey": "9MLQCQ1HifEVW1gf068zBRAOb4wNnfrOkvBVByth",
|
|
||||||
"BucketName": "ei-med-s3-lili-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-store.s3.amazonaws.com",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"BasicSystemConfig": {
|
|
||||||
|
|
||||||
"OpenUserComplexPassword": true,
|
|
||||||
"OpenSignDocumentBeforeWork": true,
|
|
||||||
|
|
||||||
"OpenLoginLimit": true,
|
|
||||||
"LoginMaxFailCount": 5,
|
|
||||||
"LoginFailLockMinutes": 30,
|
|
||||||
"AutoLoginOutMinutes": 120,
|
|
||||||
|
|
||||||
"OpenLoginMFA": true,
|
|
||||||
|
|
||||||
"ContinuousReadingTimeMin": 120,
|
|
||||||
"ReadingRestTimeMin": 10,
|
|
||||||
|
|
||||||
"IsNeedChangePassWord": true,
|
|
||||||
"ChangePassWordDays": 90,
|
|
||||||
// 模板类型 1 Elevate 2 Extensive
|
|
||||||
"TemplateType": 1,
|
|
||||||
|
|
||||||
"OpenTrialRelationDelete": false
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemEmailSendConfig": {
|
|
||||||
"Port": 587,
|
|
||||||
"Host": "smtp-mail.outlook.com",
|
|
||||||
"FromEmail": "donotreply@elevateimaging.ai",
|
|
||||||
"FromName": "LiLi",
|
|
||||||
"AuthorizationCode": "Q#669869497420ul",
|
|
||||||
|
|
||||||
"SystemShortName": "LiLi",
|
|
||||||
"OrganizationName": "Elevate Imaging",
|
|
||||||
"OrganizationNameCN": "Elevate Imaging",
|
|
||||||
"CompanyName": "Elevate Imaging Inc.",
|
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
|
||||||
"CompanyShortName": "Elevate Imaging",
|
|
||||||
"CompanyShortNameCN": "展影医疗",
|
|
||||||
"SiteUrl": "https://lili.elevateimaging.ai/login",
|
|
||||||
"IsEnv_US": true,
|
|
||||||
"IsOpenErrorNoticeEmail": false,
|
|
||||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemPacsConfig": {
|
|
||||||
"Port": "104",
|
|
||||||
"IP": "44.210.231.169"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
|
|
||||||
"ObjectStoreService": {
|
|
||||||
|
|
||||||
"ObjectStoreUse": "AWS",
|
|
||||||
"MinIO": {
|
|
||||||
//"endPoint": "hir-oss.uat.extimaging.com",
|
|
||||||
//"port": "443",
|
|
||||||
//"useSSL": true,
|
|
||||||
//"viewEndpoint": "https://hir-oss.uat.extimaging.com/hir-uat",
|
|
||||||
|
|
||||||
"endPoint": "47.117.164.182",
|
|
||||||
"port": "9001",
|
|
||||||
"useSSL": false,
|
|
||||||
"viewEndpoint": "http://47.117.164.182:9001/test-irc-us",
|
|
||||||
|
|
||||||
"accessKey": "b9Ul0e98xPzt6PwRXA1Q",
|
|
||||||
"secretKey": "DzMaU2L4OXl90uytwOmDXF2encN0Jf4Nxu2XkYqQ",
|
|
||||||
"bucketName": "test-irc-us"
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
"AWS": {
|
|
||||||
"Region": "us-east-1",
|
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
|
||||||
"UseSSL": true,
|
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
|
|
||||||
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
|
|
||||||
"SecretAccessKey": "Pgrg3le5jPxZQ7MR1yYNS30J0XRyJeKVyIIjElXc",
|
|
||||||
"BucketName": "ei-med-s3-lili-uat-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"BasicSystemConfig": {
|
|
||||||
|
|
||||||
"OpenUserComplexPassword": true,
|
|
||||||
|
|
||||||
"OpenSignDocumentBeforeWork": true,
|
|
||||||
|
|
||||||
"OpenTrialRelationDelete": true,
|
|
||||||
|
|
||||||
"OpenLoginLimit": true,
|
|
||||||
|
|
||||||
"LoginMaxFailCount": 5,
|
|
||||||
|
|
||||||
"LoginFailLockMinutes": 30,
|
|
||||||
"AutoLoginOutMinutes": 60,
|
|
||||||
|
|
||||||
"ContinuousReadingTimeMin": 120,
|
|
||||||
|
|
||||||
"ReadingRestTimeMin": 10,
|
|
||||||
"IsNeedChangePassWord": true,
|
|
||||||
|
|
||||||
"ChangePassWordDays": 90,
|
|
||||||
// 模板类型 1 Elevate 2 Extensive
|
|
||||||
"TemplateType": 1,
|
|
||||||
"OpenLoginMFA": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemEmailSendConfig": {
|
|
||||||
"Port": 587,
|
|
||||||
"Host": "smtp-mail.outlook.com",
|
|
||||||
"FromEmail": "donotreply@elevateimaging.ai",
|
|
||||||
"FromName": "LiLi",
|
|
||||||
"AuthorizationCode": "Q#669869497420ul",
|
|
||||||
|
|
||||||
"SystemShortName": "LiLi",
|
|
||||||
"OrganizationName": "Elevate Imaging",
|
|
||||||
"OrganizationNameCN": "Elevate Imaging",
|
|
||||||
"CompanyName": "Elevate Imaging Inc.",
|
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
|
||||||
"CompanyShortName": "Elevate Imaging",
|
|
||||||
"CompanyShortNameCN": "展影医疗",
|
|
||||||
"SiteUrl": "https://lili.test.elevateimaging.ai/login",
|
|
||||||
"IsEnv_US": true,
|
|
||||||
"IsOpenErrorNoticeEmail": false,
|
|
||||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemPacsConfig": {
|
|
||||||
"Port": "104",
|
|
||||||
"IP": "3.226.182.187"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ConnectionStrings": {
|
|
||||||
//"RemoteNew": "Server=us-mssql-service,1433;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
//"Hangfire": "Server=us-mssql-service,1433;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
|
|
||||||
"RemoteNew": "Server=3.226.182.187,1435;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=3.226.182.187,1435;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
|
|
||||||
"ObjectStoreService": {
|
|
||||||
|
|
||||||
"ObjectStoreUse": "AWS",
|
|
||||||
|
|
||||||
"MinIO": {
|
|
||||||
//"endPoint": "hir-minio.uat.elevateimaging.ai",
|
|
||||||
//"port": "443",
|
|
||||||
//"useSSL": true,
|
|
||||||
//"viewEndpoint": "https://hir-minio.uat.elevateimaging.ai/uat-irc-us",
|
|
||||||
|
|
||||||
"endPoint": "3.226.182.187",
|
|
||||||
"port": "9001",
|
|
||||||
"useSSL": false,
|
|
||||||
"viewEndpoint": "http://44.218.11.19:9001/uat-irc-us",
|
|
||||||
|
|
||||||
"accessKey": "lH8DkKskLuDqPaiubuSQ",
|
|
||||||
"secretKey": "pdPdicvvLeH7xAC5yFUrI7odMyBfOXxvVWMvKYV4",
|
|
||||||
"bucketName": "uat-irc-us"
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
"AWS": {
|
|
||||||
"Region": "us-east-1",
|
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
|
||||||
"UseSSL": true,
|
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
|
|
||||||
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
|
|
||||||
"SecretAccessKey": "Pgrg3le5jPxZQ7MR1yYNS30J0XRyJeKVyIIjElXc",
|
|
||||||
"BucketName": "ei-med-s3-lili-uat-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"BasicSystemConfig": {
|
|
||||||
|
|
||||||
"OpenUserComplexPassword": true,
|
|
||||||
"OpenSignDocumentBeforeWork": true,
|
|
||||||
|
|
||||||
"OpenLoginLimit": true,
|
|
||||||
"LoginMaxFailCount": 5,
|
|
||||||
"LoginFailLockMinutes": 30,
|
|
||||||
"AutoLoginOutMinutes": 120,
|
|
||||||
|
|
||||||
"OpenLoginMFA": true,
|
|
||||||
|
|
||||||
"ContinuousReadingTimeMin": 120,
|
|
||||||
"ReadingRestTimeMin": 10,
|
|
||||||
|
|
||||||
"IsNeedChangePassWord": true,
|
|
||||||
"ChangePassWordDays": 90,
|
|
||||||
// 模板类型 1 Elevate 2 Extensive
|
|
||||||
"TemplateType": 1
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemEmailSendConfig": {
|
|
||||||
"Port": 587,
|
|
||||||
"Host": "smtp-mail.outlook.com",
|
|
||||||
"FromEmail": "donotreply@elevateimaging.ai",
|
|
||||||
"FromName": "LiLi",
|
|
||||||
"AuthorizationCode": "Q#669869497420ul",
|
|
||||||
|
|
||||||
"SystemShortName": "LiLi",
|
|
||||||
"OrganizationName": "Elevate Imaging",
|
|
||||||
"OrganizationNameCN": "Elevate Imaging",
|
|
||||||
"CompanyName": "Elevate Imaging Inc.",
|
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
|
||||||
"CompanyShortName": "Elevate Imaging",
|
|
||||||
"CompanyShortNameCN": "展影医疗",
|
|
||||||
"SiteUrl": "https://lili.uat.elevateimaging.ai/login",
|
|
||||||
"IsEnv_US": true,
|
|
||||||
"IsOpenErrorNoticeEmail": false,
|
|
||||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemPacsConfig": {
|
|
||||||
"Port": "104",
|
|
||||||
"IP": "3.226.182.187"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ObjectStoreService": {
|
||||||
|
"ObjectStoreUse": "MinIO",
|
||||||
|
"MinIO": {
|
||||||
|
"EndPoint": "hir-oss.uat.extimaging.com",
|
||||||
|
"Port": "443",
|
||||||
|
"UseSSL": true,
|
||||||
|
//"endPoint": "106.14.89.110",
|
||||||
|
//"port": "9001",
|
||||||
|
//"useSSL": false,
|
||||||
|
"AccessKeyId": "L6owzRVeDJJw3PcRmK2c",
|
||||||
|
"SecretAccessKey": "2XvFDYSH7EyHQNtpDCgk4efgdsdarQmRKgx1LlOI",
|
||||||
|
"BucketName": "hir-uat",
|
||||||
|
"ViewEndpoint": "https://hir-oss.uat.extimaging.com/hir-uat"
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"RemoteNew": "Server=101.132.253.119,1435;Database=Uat_HIR_New;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
|
"Hangfire": "Server=101.132.253.119,1435;Database=Uat_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
|
},
|
||||||
|
"BasicSystemConfig": {
|
||||||
|
"OpenUserComplexPassword": true,
|
||||||
|
"OpenSignDocumentBeforeWork": false,
|
||||||
|
"OpenTrialRelationDelete": false,
|
||||||
|
"OpenLoginLimit": true,
|
||||||
|
"LoginMaxFailCount": 5,
|
||||||
|
"LoginFailLockMinutes": 30,
|
||||||
|
"AutoLoginOutMinutes": 120,
|
||||||
|
"AESKey": "HIR_System_AES_Key_Info",
|
||||||
|
"CmoveIntervalMinutes": 1,
|
||||||
|
"CmoveInstanceIntervalMinutes": 1,
|
||||||
|
// 是否强制用户定期修改密码
|
||||||
|
"IsNeedChangePassWord": true,
|
||||||
|
// 密码有效期(天),到期后必须修改
|
||||||
|
"ChangePassWordDays": 1000,
|
||||||
|
"OpenImageShare": true
|
||||||
|
},
|
||||||
|
"SystemEmailSendConfig": {
|
||||||
|
"Port": 465,
|
||||||
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
|
"FromEmail": "test-study@extimaging.com",
|
||||||
|
"FromName": "Test_HIR",
|
||||||
|
"AuthorizationCode": "zhanying123",
|
||||||
|
"SiteUrl": "http://hir.test.extimaging.com/login",
|
||||||
|
"CompanyName": "Extensive Imaging",
|
||||||
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
|
"CompanyShortName": "Extensive Imaging",
|
||||||
|
"CompanyShortNameCN": "展影医疗",
|
||||||
|
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
|
||||||
|
},
|
||||||
|
"DicomSCPServiceConfig": {
|
||||||
|
"IsSupportThirdService": true,
|
||||||
|
"ThirdSearchPacsAE": "XCPACS",
|
||||||
|
"ThirdCallningAE": "LYAE",
|
||||||
|
"CalledAEList": [
|
||||||
|
"HIRSCUAE",
|
||||||
|
"HIRSCPAE"
|
||||||
|
],
|
||||||
|
"ServerPort": 11112
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"RemoteNew": "Server=101.132.253.119,1435;Database=Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=101.132.253.119,1435;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": "LTAI5tFUCCmz5TwghZHsj45Y",
|
|
||||||
"AccessKeySecret": "8evrBy1fVfzJG25i67Jm0xqn9Xcw2T",
|
|
||||||
"RoleArn": "acs:ram::1078130221702011:role/uat-oss-access",
|
|
||||||
"BucketName": "tl-med-irc-uat-store",
|
|
||||||
"ViewEndpoint": "https://tl-med-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"Region": "oss-cn-shanghai",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
},
|
|
||||||
|
|
||||||
"MinIO": {
|
|
||||||
"endPoint": "hir-oss.uat.extimaging.com",
|
|
||||||
"port": "80",
|
|
||||||
"useSSL": false,
|
|
||||||
"viewEndpoint": "http://hir-oss.uat.extimaging.com/irc-uat",
|
|
||||||
//"port": "443",
|
|
||||||
//"useSSL": true,
|
|
||||||
//"viewEndpoint": "https://hir-oss.uat.extimaging.com/irc-uat",
|
|
||||||
"accessKey": "b9Ul0e98xPzt6PwRXA1Q",
|
|
||||||
"secretKey": "DzMaU2L4OXl90uytwOmDXF2encN0Jf4Nxu2XkYqQ",
|
|
||||||
"bucketName": "irc-uat"
|
|
||||||
|
|
||||||
},
|
|
||||||
"AWS": {
|
|
||||||
"Region": "us-east-1",
|
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
|
||||||
"UseSSL": true,
|
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/sts_s3_upload",
|
|
||||||
"AccessKeyId": "AKIAW3MEAFJXWRCGSX5Z",
|
|
||||||
"SecretAccessKey": "miais4jQGSd37A+TfBEP11AQM5u/CvotSmznJd8k",
|
|
||||||
"BucketName": "ei-med-s3-lili-uat-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com/",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"BasicSystemConfig": {
|
|
||||||
|
|
||||||
"OpenUserComplexPassword": true,
|
|
||||||
"OpenSignDocumentBeforeWork": true,
|
|
||||||
|
|
||||||
"OpenLoginLimit": true,
|
|
||||||
"LoginMaxFailCount": 5,
|
|
||||||
|
|
||||||
"LoginFailLockMinutes": 30,
|
|
||||||
"AutoLoginOutMinutes": 120,
|
|
||||||
|
|
||||||
"OpenLoginMFA": false,
|
|
||||||
|
|
||||||
"ContinuousReadingTimeMin": 120,
|
|
||||||
"ReadingRestTimeMin": 10,
|
|
||||||
|
|
||||||
"IsNeedChangePassWord": true,
|
|
||||||
"ChangePassWordDays": 90,
|
|
||||||
// 模板类型 1 Elevate 2 Extensive
|
|
||||||
"TemplateType": 2
|
|
||||||
|
|
||||||
},
|
|
||||||
"SystemEmailSendConfig": {
|
|
||||||
"Port": 465,
|
|
||||||
"Host": "smtp.qiye.aliyun.com",
|
|
||||||
"FromEmail": "uat@extimaging.com",
|
|
||||||
"FromName": "UAT_IRC",
|
|
||||||
"AuthorizationCode": "SHzyyl2021",
|
|
||||||
"SiteUrl": "http://irc.uat.extimaging.com/login",
|
|
||||||
|
|
||||||
"SystemShortName": "IRC",
|
|
||||||
"OrganizationName": "Extlmaging",
|
|
||||||
"OrganizationNameCN": "Extlmaging",
|
|
||||||
"CompanyName": "Extensive Imaging",
|
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
|
||||||
"CompanyShortName": "Extensive Imaging",
|
|
||||||
"CompanyShortNameCN": "展影医疗",
|
|
||||||
"IsEnv_US": false,
|
|
||||||
"IsOpenErrorNoticeEmail": false,
|
|
||||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemPacsConfig": {
|
|
||||||
"Port": "11113",
|
|
||||||
"IP": "101.132.253.119"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1,8 +1,6 @@
|
|||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Auth
|
|
||||||
{
|
|
||||||
public class JwtSetting
|
public class JwtSetting
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -39,4 +37,3 @@ namespace IRaCIS.Core.Application.Auth
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ namespace IRaCIS.Core.Application.Auth
|
|||||||
new Claim(JwtIRaCISClaimType.UserTypeShortName,user.UserTypeShortName),
|
new Claim(JwtIRaCISClaimType.UserTypeShortName,user.UserTypeShortName),
|
||||||
new Claim(JwtIRaCISClaimType.PermissionStr,user.PermissionStr),
|
new Claim(JwtIRaCISClaimType.PermissionStr,user.PermissionStr),
|
||||||
new Claim(JwtIRaCISClaimType.IsZhiZhun,user.IsZhiZhun.ToString()),
|
new Claim(JwtIRaCISClaimType.IsZhiZhun,user.IsZhiZhun.ToString()),
|
||||||
new Claim(JwtIRaCISClaimType.IsTestUser,user.IsTestUser.ToString())
|
new Claim(JwtIRaCISClaimType.IsTestUser,user.IsTestUser.ToString()),
|
||||||
|
new Claim(JwtIRaCISClaimType.HospitalGroupList,user.HospitalGroupList.ToJsonStr())
|
||||||
};
|
};
|
||||||
|
|
||||||
////创建令牌
|
////创建令牌
|
||||||
|
|||||||
@@ -23,5 +23,7 @@ namespace IRaCIS.Core.Application.Auth
|
|||||||
public bool IsZhiZhun { get; set; }
|
public bool IsZhiZhun { get; set; }
|
||||||
|
|
||||||
public string UserTypeShortName { get; set; } = string.Empty;
|
public string UserTypeShortName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public List<HospitalGroupInfo> HospitalGroupList { get; set; } = new List<HospitalGroupInfo>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ public class EncryptionRequestMiddleware
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var decryptedSegment = AesEncryption.Decrypt(pathSegments[i], decryptedSymmetricKey);
|
var decryptedSegment = Infrastructure.Encryption.AesEncryption.Decrypt(pathSegments[i], decryptedSymmetricKey);
|
||||||
pathSegments[i] = decryptedSegment;
|
pathSegments[i] = decryptedSegment;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -74,7 +74,7 @@ public class EncryptionRequestMiddleware
|
|||||||
foreach (var param in queryParams)
|
foreach (var param in queryParams)
|
||||||
{
|
{
|
||||||
var encryptedValue = param.Value;
|
var encryptedValue = param.Value;
|
||||||
var decryptedValue = AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
|
var decryptedValue = Infrastructure.Encryption.AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
|
||||||
decryptedQueryParams[param.Key] = decryptedValue;
|
decryptedQueryParams[param.Key] = decryptedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ public class EncryptionRequestMiddleware
|
|||||||
foreach (var property in encryptedJson.Properties())
|
foreach (var property in encryptedJson.Properties())
|
||||||
{
|
{
|
||||||
var encryptedValue = property.Value.ToString();
|
var encryptedValue = property.Value.ToString();
|
||||||
var decryptedValue = AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
|
var decryptedValue = Infrastructure.Encryption.AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
|
||||||
decryptedJson[property.Name] = decryptedValue;
|
decryptedJson[property.Name] = decryptedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+73
-5
@@ -1,8 +1,12 @@
|
|||||||
using IRaCIS.Core.Application.BusinessFilter;
|
using IRaCIS.Application.Contracts;
|
||||||
|
using IRaCIS.Core.Application.BusinessFilter;
|
||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
|
using IRaCIS.Core.Infrastructure.Encryption;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -13,7 +17,10 @@ using static IRaCIS.Core.Domain.Share.StaticData;
|
|||||||
|
|
||||||
namespace IRaCIS.Core.Application.Filter;
|
namespace IRaCIS.Core.Application.Filter;
|
||||||
|
|
||||||
public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _userInfo, IRepository<Trial> _trialRepository) : IAsyncActionFilter
|
public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _userInfo, IRepository<Trial> _trialRepository,
|
||||||
|
IOptionsMonitor<ServiceVerifyConfigOption> _basicSystemConfigConfig,
|
||||||
|
IRepository<HIRHospital> _hirHospitalRepository,
|
||||||
|
IStringLocalizer _localizer) : IAsyncActionFilter
|
||||||
{
|
{
|
||||||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||||
{
|
{
|
||||||
@@ -113,9 +120,9 @@ public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _
|
|||||||
|
|
||||||
trialIdStr = matchResult.Value;
|
trialIdStr = matchResult.Value;
|
||||||
|
|
||||||
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
var trialInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(trialStatusStr))
|
if (string.IsNullOrWhiteSpace(trialInfo?.TrialStatusStr))
|
||||||
{
|
{
|
||||||
|
|
||||||
//数据库 检查该项目Id不对
|
//数据库 检查该项目Id不对
|
||||||
@@ -145,7 +152,66 @@ public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _
|
|||||||
//通过path 或者body 找到trialId 了
|
//通过path 或者body 找到trialId 了
|
||||||
if (!string.IsNullOrWhiteSpace(trialIdStr))
|
if (!string.IsNullOrWhiteSpace(trialIdStr))
|
||||||
{
|
{
|
||||||
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
var trialInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||||
|
|
||||||
|
var hospitalInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Hospital, _ => CacheHelper.GetHospitalCode(_hirHospitalRepository), TimeSpan.FromDays(7));
|
||||||
|
|
||||||
|
var trialStatusStr = string.Empty;
|
||||||
|
|
||||||
|
if (trialInfo != null)
|
||||||
|
{
|
||||||
|
trialStatusStr = trialInfo.TrialStatusStr;
|
||||||
|
|
||||||
|
var activationCode = trialInfo.AuthorizationEncrypt;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(activationCode))
|
||||||
|
{
|
||||||
|
//context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["项目未进行授权之前,不能进行操作"]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
var decodedText = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//解析加密信息
|
||||||
|
decodedText = AesEncryption.Decrypt(activationCode, _basicSystemConfigConfig.CurrentValue.AESKey, "Trial_AuthorizationEncrypt");
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
//该授权码与该项目不匹配(无法解密)
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialGlobalLimit_AuthorizationCodeError"]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var hospitalCode = hospitalInfo.HospitalCode;
|
||||||
|
var authInfo = JsonConvert.DeserializeObject<TrialAuthorizationInfo>(decodedText);
|
||||||
|
|
||||||
|
if (authInfo != null)
|
||||||
|
{
|
||||||
|
if (authInfo.TrialCode != trialInfo.TrialCode || authInfo.CreateUserId != trialInfo.CreateUserId || authInfo.TrialId != trialInfo.TrialId
|
||||||
|
|| authInfo.HospitalCode != hospitalCode || trialInfo.CriterionTypeList.Except(authInfo.CriterionTypeList).Count() != 0)
|
||||||
|
{
|
||||||
|
// 您的操作被禁止,系统检测到该项目授权码与该项目授权配置信息不一致,请还原项目授权配置信息!
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialGlobalLimit_AuthorizationCodeInfoError"]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DateTime.Now > authInfo.AuthorizationDeadLineDate.Value.AddDays(15))
|
||||||
|
{
|
||||||
|
//当前时间已经超过项目授权截止时间半个月,请重新获取项目授权后再进行操作!
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialGlobalLimit_AuthorizationCodeAfterDeadLine15Days"]));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["该授权码与该项目不匹配"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方,比如项目配置(有的在多种状态(初始化,ongoing)都可以操作,有的仅仅在Initializing)还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
|
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方,比如项目配置(有的在多种状态(初始化,ongoing)都可以操作,有的仅仅在Initializing)还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
|
||||||
if (trialStatusStr == StaticData.TrialState.TrialOngoing || optActions.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
|
if (trialStatusStr == StaticData.TrialState.TrialOngoing || optActions.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
|
||||||
@@ -161,6 +227,8 @@ public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _
|
|||||||
context.Result = new JsonResult(ResponseOutput.NotOk(I18n.T("TrialResource_InterceptedProjectStatusRule")));
|
context.Result = new JsonResult(ResponseOutput.NotOk(I18n.T("TrialResource_InterceptedProjectStatusRule")));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//添加项目 签名系统文档的时候 不做拦截 但是更新项目 签名项目文档的时候需要拦截
|
//添加项目 签名系统文档的时候 不做拦截 但是更新项目 签名项目文档的时候需要拦截
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Service.BusinessFilter;
|
namespace IRaCIS.Core.Application.Service.BusinessFilter;
|
||||||
|
|
||||||
|
|||||||
+71
-5
@@ -1,6 +1,10 @@
|
|||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Application.Contracts;
|
||||||
|
using IRaCIS.Core.Application.Helper;
|
||||||
|
using IRaCIS.Core.Infrastructure.Encryption;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -24,7 +28,10 @@ public class TrialGlobalLimitAttribute : Attribute
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo _userInfo, IRepository<Trial> _trialRepository) : IEndpointFilter
|
public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo _userInfo, IRepository<Trial> _trialRepository,
|
||||||
|
IOptionsMonitor<ServiceVerifyConfigOption> _basicSystemConfigConfig,
|
||||||
|
IRepository<HIRHospital> _hirHospitalRepository,
|
||||||
|
IStringLocalizer _localizer) : IEndpointFilter
|
||||||
|
|
||||||
{
|
{
|
||||||
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
|
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
|
||||||
@@ -121,9 +128,9 @@ public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo
|
|||||||
|
|
||||||
trialIdStr = matchResult.Value;
|
trialIdStr = matchResult.Value;
|
||||||
|
|
||||||
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
var trialInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(trialStatusStr))
|
if (string.IsNullOrWhiteSpace(trialInfo?.TrialStatusStr))
|
||||||
{
|
{
|
||||||
|
|
||||||
//数据库 检查该项目Id不对
|
//数据库 检查该项目Id不对
|
||||||
@@ -151,7 +158,62 @@ public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo
|
|||||||
//通过path 或者body 找到trialId 了
|
//通过path 或者body 找到trialId 了
|
||||||
if (!string.IsNullOrWhiteSpace(trialIdStr))
|
if (!string.IsNullOrWhiteSpace(trialIdStr))
|
||||||
{
|
{
|
||||||
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
var trialInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||||
|
|
||||||
|
var hospitalInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Hospital, _ => CacheHelper.GetHospitalCode(_hirHospitalRepository), TimeSpan.FromDays(7));
|
||||||
|
|
||||||
|
var trialStatusStr = string.Empty;
|
||||||
|
|
||||||
|
|
||||||
|
if (trialInfo != null)
|
||||||
|
{
|
||||||
|
trialStatusStr = trialInfo.TrialStatusStr;
|
||||||
|
|
||||||
|
var activationCode = trialInfo.AuthorizationEncrypt;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(activationCode))
|
||||||
|
{
|
||||||
|
//context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["项目未进行授权之前,不能进行操作"]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
var decodedText = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//解析加密信息
|
||||||
|
decodedText = AesEncryption.Decrypt(activationCode, _basicSystemConfigConfig.CurrentValue.AESKey, "Trial_AuthorizationEncrypt");
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
|
||||||
|
return Results.Json(ResponseOutput.NotOk(_localizer["该授权码与该项目不匹配"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var hospitalCode = hospitalInfo.HospitalCode;
|
||||||
|
var authInfo = JsonConvert.DeserializeObject<TrialAuthorizationInfo>(decodedText);
|
||||||
|
|
||||||
|
if (authInfo != null)
|
||||||
|
{
|
||||||
|
if (authInfo.TrialCode != trialInfo.TrialCode || authInfo.CreateUserId != trialInfo.CreateUserId || authInfo.TrialId != trialInfo.TrialId
|
||||||
|
|| authInfo.HospitalCode != hospitalCode || trialInfo.CriterionTypeList.Except(authInfo.CriterionTypeList).Count() != 0)
|
||||||
|
{
|
||||||
|
return Results.Json(ResponseOutput.NotOk(_localizer["您的操作被禁止,系统检测到该项目授权码与该项目授权配置信息不一致,请还原项目授权配置信息!"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DateTime.Now > authInfo.AuthorizationDeadLineDate.Value.AddDays(15))
|
||||||
|
{
|
||||||
|
return Results.Json(ResponseOutput.NotOk(_localizer["当前时间已经超过项目授权截止时间半个月,请重新获取项目授权后再进行操作!"]));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["该授权码与该项目不匹配"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方,比如项目配置(有的在多种状态(初始化,ongoing)都可以操作,有的仅仅在Initializing)还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
|
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方,比如项目配置(有的在多种状态(初始化,ongoing)都可以操作,有的仅仅在Initializing)还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
|
||||||
if (trialStatusStr == StaticData.TrialState.TrialOngoing || optActions.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
|
if (trialStatusStr == StaticData.TrialState.TrialOngoing || optActions.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
|
||||||
@@ -167,6 +229,10 @@ public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo
|
|||||||
return Results.Json(ResponseOutput.NotOk(I18n.T("TrialResource_InterceptedProjectStatusRule")));
|
return Results.Json(ResponseOutput.NotOk(I18n.T("TrialResource_InterceptedProjectStatusRule")));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//添加项目 签名系统文档的时候 不做拦截 但是更新项目 签名项目文档的时候需要拦截
|
//添加项目 签名系统文档的时候 不做拦截 但是更新项目 签名项目文档的时候需要拦截
|
||||||
|
|||||||
@@ -34,10 +34,17 @@ public class ServiceVerifyConfigOption
|
|||||||
[Description("修改密码的天数")]
|
[Description("修改密码的天数")]
|
||||||
public int ChangePassWordDays { get; set; }
|
public int ChangePassWordDays { get; set; }
|
||||||
|
|
||||||
public SysTemplateType TemplateType { get; set; }
|
|
||||||
|
|
||||||
public string ThirdPdfUrl { get; set; }
|
public string ThirdPdfUrl { get; set; }
|
||||||
|
|
||||||
|
public string AESKey { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public int CmoveIntervalMinutes { get; set; }
|
||||||
|
|
||||||
|
public int CmoveInstanceIntervalMinutes { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public bool OpenImageShare { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SystemEmailSendConfig
|
public class SystemEmailSendConfig
|
||||||
@@ -70,6 +77,8 @@ public class SystemEmailSendConfig
|
|||||||
|
|
||||||
public bool IsOpenErrorNoticeEmail { get; set; }
|
public bool IsOpenErrorNoticeEmail { get; set; }
|
||||||
|
|
||||||
|
public string EmailRegexStr { get; set; }
|
||||||
|
|
||||||
public List<string> ErrorNoticeEmailList { get; set; } = new List<string>();
|
public List<string> ErrorNoticeEmailList { get; set; } = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +92,10 @@ public class SystemEmailSendConfigView
|
|||||||
public string CompanyShortName { get; set; } = string.Empty;
|
public string CompanyShortName { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string CompanyShortNameCN { get; set; } = string.Empty;
|
public string CompanyShortNameCN { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string EmailRegexStr { get; set; }
|
||||||
|
|
||||||
|
public bool OpenImageShare { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SystemPacsConfig
|
public class SystemPacsConfig
|
||||||
|
|||||||
@@ -10,6 +10,6 @@ global using Microsoft.Extensions.Localization;
|
|||||||
global using AutoMapper;
|
global using AutoMapper;
|
||||||
global using IRaCIS.Core.Domain.Share;
|
global using IRaCIS.Core.Domain.Share;
|
||||||
global using IRaCIS.Core.Application.BusinessFilter;
|
global using IRaCIS.Core.Application.BusinessFilter;
|
||||||
global using IdentityUser = IRaCIS.Core.Domain.Models.IdentityUser;
|
global using Serilog;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace IRaCIS.Core.Application.Helper;
|
using IRaCIS.Application.Contracts;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Helper;
|
||||||
|
|
||||||
|
|
||||||
public static class CacheKeys
|
public static class CacheKeys
|
||||||
@@ -61,13 +63,20 @@ public static class CacheKeys
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string StartRestTime(Guid userId) => $"{userId}StartRestTime";
|
public static string StartRestTime(Guid userId) => $"{userId}StartRestTime";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static string CmoveStudyId(string studyIdStr) => $"CmoveStudyId:{studyIdStr}";
|
||||||
|
|
||||||
|
public static string Hospital => $"Hospital";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CacheHelper
|
public static class CacheHelper
|
||||||
{
|
{
|
||||||
public static async Task<string?> GetTrialStatusAsync(Guid trialId, IRepository<Trial> _trialRepository)
|
public static async Task<TrialCacheInfo> GetTrialStatusAsync(Guid trialId, IRepository<Trial> _trialRepository)
|
||||||
{
|
{
|
||||||
var statusStr = await _trialRepository.Where(t => t.Id == trialId, ignoreQueryFilters: true).Select(t => t.TrialStatusStr).FirstOrDefaultAsync();
|
var statusStr = await _trialRepository.Where(t => t.Id == trialId, ignoreQueryFilters: true).Select(t => new TrialCacheInfo { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr, CriterionTypes = t.CriterionTypes, AuthorizationEncrypt = t.AuthorizationEncrypt, AuthorizationDate = t.AuthorizationDate, CreateUserId = t.CreateUserId, TrialCode = t.TrialCode })
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
return statusStr;
|
return statusStr;
|
||||||
}
|
}
|
||||||
@@ -78,4 +87,10 @@ public static class CacheHelper
|
|||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<HIRHospital> GetHospitalCode(IRepository<HIRHospital> _hirHospitalRepository)
|
||||||
|
{
|
||||||
|
return await _hirHospitalRepository.Where(t => t.IsDefault == true).FirstNotNullAsync();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,197 @@
|
|||||||
|
using FellowOakDicom;
|
||||||
|
using FellowOakDicom.Media;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Helper
|
||||||
|
{
|
||||||
|
|
||||||
|
public class StudyDIRInfo
|
||||||
|
{
|
||||||
|
public Guid SubjectId { get; set; }
|
||||||
|
public Guid TrialId { get; set; }
|
||||||
|
public Guid SubjectVisitId { get; set; }
|
||||||
|
// Study
|
||||||
|
public Guid DicomStudyId { get; set; }
|
||||||
|
|
||||||
|
public string PatientId { get; set; }
|
||||||
|
public string PatientName { get; set; }
|
||||||
|
public string PatientBirthDate { get; set; }
|
||||||
|
public string PatientSex { get; set; }
|
||||||
|
|
||||||
|
public string StudyInstanceUid { get; set; }
|
||||||
|
public string StudyId { get; set; }
|
||||||
|
public string DicomStudyDate { get; set; }
|
||||||
|
public string DicomStudyTime { get; set; }
|
||||||
|
public string AccessionNumber { get; set; }
|
||||||
|
public string StudyDescription { get; set; }
|
||||||
|
|
||||||
|
// Series
|
||||||
|
public string SeriesInstanceUid { get; set; }
|
||||||
|
public string Modality { get; set; }
|
||||||
|
public string DicomSeriesDate { get; set; }
|
||||||
|
public string DicomSeriesTime { get; set; }
|
||||||
|
public int SeriesNumber { get; set; }
|
||||||
|
public string SeriesDescription { get; set; }
|
||||||
|
|
||||||
|
// Instance
|
||||||
|
public Guid InstanceId { get; set; }
|
||||||
|
public string SopInstanceUid { get; set; }
|
||||||
|
public string SOPClassUID { get; set; }
|
||||||
|
public int InstanceNumber { get; set; }
|
||||||
|
public string MediaStorageSOPClassUID { get; set; }
|
||||||
|
public string MediaStorageSOPInstanceUID { get; set; }
|
||||||
|
public string TransferSyntaxUID { get; set; }
|
||||||
|
}
|
||||||
|
public static class DicomDIRHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
public static async Task GenerateStudyDIRAndUploadAsync(List<StudyDIRInfo> list, Dictionary<string, string> dic, string ossFolder, IOSSService _oSSService)
|
||||||
|
{
|
||||||
|
var mappings = new List<string>();
|
||||||
|
int index = 1;
|
||||||
|
// 全局关闭所有 VR 字段验证
|
||||||
|
|
||||||
|
var studyUid = list.FirstOrDefault()?.StudyInstanceUid;
|
||||||
|
|
||||||
|
var dicomDir = new DicomDirectory();
|
||||||
|
|
||||||
|
foreach (var item in list.OrderBy(t => t.SeriesNumber).ThenBy(t => t.InstanceNumber))
|
||||||
|
{
|
||||||
|
var dicomUid = DicomUID.Enumerate().FirstOrDefault(uid => uid.UID == item.TransferSyntaxUID);
|
||||||
|
|
||||||
|
if (dicomUid != null)
|
||||||
|
{
|
||||||
|
var ts = DicomTransferSyntax.Query(dicomUid);
|
||||||
|
|
||||||
|
var dataset = new DicomDataset(ts)
|
||||||
|
{
|
||||||
|
{ DicomTag.PatientID, item.PatientId ?? string.Empty },
|
||||||
|
{ DicomTag.PatientName, item.PatientName ?? string.Empty },
|
||||||
|
{ DicomTag.PatientBirthDate, item.PatientBirthDate?.Replace("-","") ?? string.Empty },
|
||||||
|
{ DicomTag.PatientSex, item.PatientSex ?? string.Empty },
|
||||||
|
|
||||||
|
{ DicomTag.StudyInstanceUID, item.StudyInstanceUid ?? string.Empty },
|
||||||
|
{ DicomTag.StudyID, item.StudyId ?? string.Empty },
|
||||||
|
{ DicomTag.StudyDate, item.DicomStudyDate ?? string.Empty },
|
||||||
|
{ DicomTag.StudyTime, item.DicomStudyTime ?? string.Empty },
|
||||||
|
{ DicomTag.AccessionNumber, item.AccessionNumber ?? string.Empty },
|
||||||
|
{ DicomTag.StudyDescription, item.StudyDescription ?? string.Empty },
|
||||||
|
|
||||||
|
{ DicomTag.SeriesInstanceUID, item.SeriesInstanceUid ?? string.Empty },
|
||||||
|
{ DicomTag.Modality, item.Modality ?? string.Empty },
|
||||||
|
{ DicomTag.SeriesDate, item.DicomSeriesDate ?? string.Empty },
|
||||||
|
{ DicomTag.SeriesTime, item.DicomSeriesTime ?? string.Empty },
|
||||||
|
{ DicomTag.SeriesNumber, item.SeriesNumber.ToString() ?? string.Empty },
|
||||||
|
{ DicomTag.SeriesDescription, item.SeriesDescription ?? string.Empty },
|
||||||
|
|
||||||
|
{ DicomTag.SOPInstanceUID, item.SopInstanceUid ?? string.Empty },
|
||||||
|
{ DicomTag.SOPClassUID, item.SOPClassUID ?? string.Empty },
|
||||||
|
{ DicomTag.InstanceNumber, item.InstanceNumber.ToString() ?? string.Empty },
|
||||||
|
{ DicomTag.MediaStorageSOPClassUID, item.MediaStorageSOPClassUID ?? string.Empty },
|
||||||
|
{ DicomTag.MediaStorageSOPInstanceUID, item.MediaStorageSOPInstanceUID ?? string.Empty },
|
||||||
|
{ DicomTag.TransferSyntaxUID, item.TransferSyntaxUID ?? string.Empty },
|
||||||
|
};
|
||||||
|
|
||||||
|
var dicomFile = new DicomFile(dataset);
|
||||||
|
|
||||||
|
// 文件名递增格式:IM_00001, IM_00002, ...
|
||||||
|
string filename = $@"IMAGE\IM_{index:D5}"; // :D5 表示补足5位
|
||||||
|
|
||||||
|
mappings.Add($"{filename} => {item.InstanceId}");
|
||||||
|
|
||||||
|
dic.Add(item.InstanceId.ToString(), filename.TrimEnd('/', '\\').Split('/', '\\').Last());
|
||||||
|
|
||||||
|
dicomDir.AddFile(dicomFile, filename);
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//有实际的文件
|
||||||
|
if (mappings.Count > 0)
|
||||||
|
{
|
||||||
|
#region 写入临时路径
|
||||||
|
var tempFilePath = Path.GetTempFileName();
|
||||||
|
|
||||||
|
// 保存 DICOMDIR 到临时文件 不能直接写入到流种
|
||||||
|
await dicomDir.SaveAsync(tempFilePath);
|
||||||
|
|
||||||
|
using (var memoryStream = new MemoryStream(File.ReadAllBytes(tempFilePath)))
|
||||||
|
{
|
||||||
|
// 重置流位置
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
|
||||||
|
var relativePath = await _oSSService.UploadToOSSAsync(memoryStream, ossFolder, "DICOMDIR", true);
|
||||||
|
|
||||||
|
|
||||||
|
dic.Add($"{studyUid}_DICOMDIR", relativePath.Split('/').Last());
|
||||||
|
}
|
||||||
|
|
||||||
|
//清理临时文件
|
||||||
|
File.Delete(tempFilePath);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 映射上传
|
||||||
|
|
||||||
|
// 将映射写入内存流
|
||||||
|
var mappingText = string.Join(Environment.NewLine, mappings);
|
||||||
|
await using var mappingStream = new MemoryStream(Encoding.UTF8.GetBytes(mappingText));
|
||||||
|
|
||||||
|
await _oSSService.UploadToOSSAsync(mappingStream, ossFolder, $"Download_{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}", false);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static StudyDIRInfo ReadDicomDIRInfo(DicomFile dicomFile)
|
||||||
|
{
|
||||||
|
var dataset = dicomFile.Dataset;
|
||||||
|
|
||||||
|
|
||||||
|
var info = new StudyDIRInfo
|
||||||
|
{
|
||||||
|
PatientId = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
|
||||||
|
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
|
||||||
|
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
|
||||||
|
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
|
||||||
|
|
||||||
|
StudyInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty),
|
||||||
|
StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
|
||||||
|
DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty),
|
||||||
|
DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty),
|
||||||
|
AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),
|
||||||
|
StudyDescription = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
|
||||||
|
|
||||||
|
SeriesInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty),
|
||||||
|
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||||
|
DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty),
|
||||||
|
DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty),
|
||||||
|
SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
|
||||||
|
SeriesDescription = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
|
||||||
|
|
||||||
|
SopInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty),
|
||||||
|
SOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty),
|
||||||
|
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
|
||||||
|
|
||||||
|
MediaStorageSOPClassUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty),
|
||||||
|
MediaStorageSOPInstanceUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty),
|
||||||
|
|
||||||
|
TransferSyntaxUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty)
|
||||||
|
};
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,12 +11,6 @@ public static class SendEmailHelper
|
|||||||
|
|
||||||
public static async Task SendEmailAsync(MimeMessage messageToSend, SystemEmailSendConfig _systemEmailConfig, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
|
public static async Task SendEmailAsync(MimeMessage messageToSend, SystemEmailSendConfig _systemEmailConfig, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
|
||||||
{
|
{
|
||||||
//没有收件人 那么不发送
|
|
||||||
if (messageToSend.To.Count == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var smtp = new MailKit.Net.Smtp.SmtpClient())
|
using (var smtp = new MailKit.Net.Smtp.SmtpClient())
|
||||||
|
|||||||
@@ -243,6 +243,7 @@ public static class ExcelExportHelper
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class DynamicColumnConfig
|
public class DynamicColumnConfig
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -260,7 +261,9 @@ public static class ExcelExportHelper
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int TempalteLastColumnIndex { get; set; }
|
public int TempalteLastColumnIndex { get; set; }
|
||||||
|
|
||||||
public List<string> CDISCList { get; set; } = new List<string>();
|
public bool IsCDISCExport { get; set; } = false;
|
||||||
|
|
||||||
|
//public List<string> CDISCList { get; set; } = new List<string>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 动态的列名 如果Id 重复,那么就按照名称填充,否则就按照Id 填充列数据
|
/// 动态的列名 如果Id 重复,那么就按照名称填充,否则就按照Id 填充列数据
|
||||||
@@ -301,6 +304,8 @@ public static class ExcelExportHelper
|
|||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string CDISCCode { get; set; }
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
if (obj is not ColumItem other) return false;
|
if (obj is not ColumItem other) return false;
|
||||||
@@ -489,7 +494,9 @@ public static class ExcelExportHelper
|
|||||||
|
|
||||||
if (dynamicColumnConfig != null)
|
if (dynamicColumnConfig != null)
|
||||||
{
|
{
|
||||||
var isCdics = dynamicColumnConfig.CDISCList.Count > 0;
|
//var isCdics = dynamicColumnConfig.CDISCList.Count > 0;
|
||||||
|
|
||||||
|
var isCdics = dynamicColumnConfig.IsCDISCExport;
|
||||||
|
|
||||||
var sheet = workbook.GetSheetAt(0);
|
var sheet = workbook.GetSheetAt(0);
|
||||||
|
|
||||||
@@ -544,7 +551,7 @@ public static class ExcelExportHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
//创建新的列
|
//创建新的列
|
||||||
for (int i = originTotalEndIndex; i < originTotalEndIndex + needAddCount; i++)
|
for (int i = originRemoveEndIndex; i < originRemoveEndIndex + needAddCount; i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
titelRow.CreateCell(i + 1);
|
titelRow.CreateCell(i + 1);
|
||||||
@@ -565,6 +572,11 @@ public static class ExcelExportHelper
|
|||||||
titelRow.GetCell(i).SetCellValue(titelRow.GetCell(i - gap).StringCellValue);
|
titelRow.GetCell(i).SetCellValue(titelRow.GetCell(i - gap).StringCellValue);
|
||||||
|
|
||||||
templateRow.GetCell(i).SetCellValue(templateRow.GetCell(i - gap).StringCellValue);
|
templateRow.GetCell(i).SetCellValue(templateRow.GetCell(i - gap).StringCellValue);
|
||||||
|
|
||||||
|
if (isCdics)
|
||||||
|
{
|
||||||
|
cdicsRow.GetCell(i).SetCellValue(cdicsRow.GetCell(i - gap).StringCellValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -573,6 +585,7 @@ public static class ExcelExportHelper
|
|||||||
|
|
||||||
for (int i = dynamicColunmStartIndex; i < dynamicColunmStartIndex + needAddCount; i++)
|
for (int i = dynamicColunmStartIndex; i < dynamicColunmStartIndex + needAddCount; i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
var name = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].Name;
|
var name = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].Name;
|
||||||
|
|
||||||
titelRow.GetCell(i).SetCellValue(name);
|
titelRow.GetCell(i).SetCellValue(name);
|
||||||
@@ -580,13 +593,15 @@ public static class ExcelExportHelper
|
|||||||
|
|
||||||
if (isCdics)
|
if (isCdics)
|
||||||
{
|
{
|
||||||
var cdicsCode = dynamicColumnConfig.CDISCList[i - dynamicColunmStartIndex];
|
var cdicsCode = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].CDISCCode;
|
||||||
|
|
||||||
cdicsRow.GetCell(i).SetCellValue(cdicsCode);
|
cdicsRow.GetCell(i).SetCellValue(cdicsCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
using (var memoryStream2 = new MemoryStream())
|
using (var memoryStream2 = new MemoryStream())
|
||||||
{
|
{
|
||||||
workbook.Write(memoryStream2, true);
|
workbook.Write(memoryStream2, true);
|
||||||
@@ -609,8 +624,11 @@ public static class ExcelExportHelper
|
|||||||
IgnoreTemplateParameterMissing = true,
|
IgnoreTemplateParameterMissing = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//await MiniExcel.SaveAsByTemplateAsync("testmini.xlsx", templateStream.ToArray(), translateData);
|
||||||
|
|
||||||
await MiniExcel.SaveAsByTemplateAsync(memoryStream, templateStream.ToArray(), translateData, config);
|
await MiniExcel.SaveAsByTemplateAsync(memoryStream, templateStream.ToArray(), translateData, config);
|
||||||
|
|
||||||
|
|
||||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
if (dynamicColumnConfig != null)
|
if (dynamicColumnConfig != null)
|
||||||
@@ -643,7 +661,7 @@ public static class ExcelExportHelper
|
|||||||
|
|
||||||
var iteObjDic = itemObj.ToDictionary();
|
var iteObjDic = itemObj.ToDictionary();
|
||||||
|
|
||||||
var itemDicName = iteObjDic[dynamicColumnConfig.DynamicItemDicName]?.ToString();
|
var itemDicName = iteObjDic.ContainsKey(dynamicColumnConfig.DynamicItemDicName) ? iteObjDic[dynamicColumnConfig.DynamicItemDicName]?.ToString() : "";
|
||||||
var itemValue = iteObjDic[dynamicColumnConfig.DynamicItemValueName]?.ToString();
|
var itemValue = iteObjDic[dynamicColumnConfig.DynamicItemValueName]?.ToString();
|
||||||
|
|
||||||
//var writeIndex = itemList.IndexOf(itemObj) + dynamicColumnConfig.AutoColumnStartIndex;
|
//var writeIndex = itemList.IndexOf(itemObj) + dynamicColumnConfig.AutoColumnStartIndex;
|
||||||
@@ -907,7 +925,7 @@ public static class ExcelExportHelper
|
|||||||
{
|
{
|
||||||
var name = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].Name;
|
var name = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].Name;
|
||||||
|
|
||||||
var cdicsCode = dynamicColumnConfig.CDISCList[i - dynamicColunmStartIndex];
|
var cdicsCode = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].CDISCCode;
|
||||||
|
|
||||||
cdicsRow.GetCell(i).SetCellValue(cdicsCode);
|
cdicsRow.GetCell(i).SetCellValue(cdicsCode);
|
||||||
titelRow.GetCell(i).SetCellValue(name);
|
titelRow.GetCell(i).SetCellValue(name);
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public static class FileStoreHelper
|
|||||||
{
|
{
|
||||||
var rootPath = GetIRaCISRootPath(_hostEnvironment);
|
var rootPath = GetIRaCISRootPath(_hostEnvironment);
|
||||||
|
|
||||||
var physicalFilePath = Path.Combine(rootPath, relativePath.TrimStart('/'));
|
var physicalFilePath = Path.Combine(rootPath, StaticData.Folder.IRaCISDataFolder, relativePath.TrimStart('/'));
|
||||||
|
|
||||||
return physicalFilePath;
|
return physicalFilePath;
|
||||||
}
|
}
|
||||||
@@ -142,6 +142,7 @@ public static class FileStoreHelper
|
|||||||
|
|
||||||
if (!System.IO.File.Exists(filePath))
|
if (!System.IO.File.Exists(filePath))
|
||||||
{
|
{
|
||||||
|
Log.Error( $"文件存储路径上未找对应文件,{filePath}");
|
||||||
//---数据模板文件存储路径上未找对应文件,请联系系统运维人员。
|
//---数据模板文件存储路径上未找对应文件,请联系系统运维人员。
|
||||||
throw new BusinessValidationFailedException(I18n.T("FileStore_TemplateFileStoragePathInvalid"));
|
throw new BusinessValidationFailedException(I18n.T("FileStore_TemplateFileStoragePathInvalid"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ namespace IRaCIS.Core.Application.Helper
|
|||||||
//添加 或者更新定时任务 Id 要唯一标识一个定义任务
|
//添加 或者更新定时任务 Id 要唯一标识一个定义任务
|
||||||
public static void AddOrUpdateCronJob<T>(string jobId, Expression<Action<T>> methodCall, string cron, string queueName = "default")
|
public static void AddOrUpdateCronJob<T>(string jobId, Expression<Action<T>> methodCall, string cron, string queueName = "default")
|
||||||
{
|
{
|
||||||
RecurringJob.AddOrUpdate<T>(jobId, queueName, methodCall, cron, new RecurringJobOptions() { TimeZone = TimeZoneInfo.Local });
|
RecurringJob.AddOrUpdate<T>(jobId, queueName, methodCall, cron);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddOrUpdateInitCronJob<T>(string jobId, Expression<Action<T>> methodCall, string cron)
|
public static void AddOrUpdateInitCronJob<T>(string jobId, Expression<Action<T>> methodCall, string cron)
|
||||||
{
|
{
|
||||||
RecurringJob.AddOrUpdate<T>(jobId, "sys_init", methodCall, cron, new RecurringJobOptions() { TimeZone = TimeZoneInfo.Local });
|
RecurringJob.AddOrUpdate<T>(jobId, "sys_init", methodCall, cron);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RemoveCronJob(string jobId)
|
public static void RemoveCronJob(string jobId)
|
||||||
@@ -77,26 +77,13 @@ namespace IRaCIS.Core.Application.Helper
|
|||||||
case EmailBusinessScenario.ExpeditedReading:
|
case EmailBusinessScenario.ExpeditedReading:
|
||||||
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new UrgentIRUnReadTaskRecurringEvent() { TrialId = trialId }, default), emailCron);
|
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new UrgentIRUnReadTaskRecurringEvent() { TrialId = trialId }, default), emailCron);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddOrUpdateSystemCronJob(string jobId, EmailBusinessScenario businessScenario, string emailCron)
|
|
||||||
{
|
|
||||||
switch (businessScenario)
|
|
||||||
{
|
|
||||||
|
|
||||||
case EmailBusinessScenario.GeneralTraining_ExpirationNotification:
|
|
||||||
|
|
||||||
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new SystemDocumentErverDayEvent() { }, default), emailCron);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using AlibabaCloud.SDK.Sts20150401;
|
using AlibabaCloud.SDK.Sts20150401;
|
||||||
using Aliyun.OSS;
|
using Aliyun.OSS;
|
||||||
using Aliyun.OSS.Common;
|
using Aliyun.OSS.Common;
|
||||||
using Amazon;
|
using Amazon;
|
||||||
@@ -16,8 +16,10 @@ using Minio;
|
|||||||
using Minio.DataModel;
|
using Minio.DataModel;
|
||||||
using Minio.DataModel.Args;
|
using Minio.DataModel.Args;
|
||||||
using Minio.Exceptions;
|
using Minio.Exceptions;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Web;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Helper;
|
namespace IRaCIS.Core.Application.Helper;
|
||||||
|
|
||||||
@@ -111,6 +113,8 @@ public class AliyunOSSTempToken
|
|||||||
|
|
||||||
public string PreviewEndpoint { get; set; }
|
public string PreviewEndpoint { get; set; }
|
||||||
|
|
||||||
|
public string DownloadEndPoint => EndPoint.Insert(EndPoint.IndexOf("//") + 2, BucketName + ".");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[LowerCamelCaseJson]
|
[LowerCamelCaseJson]
|
||||||
@@ -123,7 +127,7 @@ public class AWSTempToken
|
|||||||
public string SecretAccessKey { get; set; }
|
public string SecretAccessKey { get; set; }
|
||||||
public string BucketName { get; set; }
|
public string BucketName { get; set; }
|
||||||
public string ViewEndpoint { get; set; }
|
public string ViewEndpoint { get; set; }
|
||||||
public DateTime Expiration { get; set; }
|
public DateTime? Expiration { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ObjectStoreUse
|
public enum ObjectStoreUse
|
||||||
@@ -144,6 +148,8 @@ public interface IOSSService
|
|||||||
|
|
||||||
public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);
|
public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);
|
||||||
|
|
||||||
|
public Task<Stream> GetStreamFromOSSAsync(string ossRelativePath);
|
||||||
|
|
||||||
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
|
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
|
||||||
|
|
||||||
public Task<string> GetSignedUrl(string ossRelativePath);
|
public Task<string> GetSignedUrl(string ossRelativePath);
|
||||||
@@ -189,7 +195,7 @@ public class OSSService : IOSSService
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
|
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
BackBatchGetToken();
|
||||||
|
|
||||||
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
|
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
|
||||||
|
|
||||||
@@ -221,8 +227,14 @@ public class OSSService : IOSSService
|
|||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
|
||||||
|
var httpClientHandler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
|
||||||
|
};
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
||||||
|
.WithHttpClient(new HttpClient(httpClientHandler))
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var putObjectArgs = new PutObjectArgs()
|
var putObjectArgs = new PutObjectArgs()
|
||||||
@@ -279,6 +291,37 @@ public class OSSService : IOSSService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//后端批量上传 或者下载,不每个文件获取临时token
|
||||||
|
private void BackBatchGetToken()
|
||||||
|
{
|
||||||
|
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||||
|
{
|
||||||
|
if (AliyunOSSTempToken == null)
|
||||||
|
{
|
||||||
|
GetObjectStoreTempToken();
|
||||||
|
}
|
||||||
|
//token 过期了
|
||||||
|
else if (AliyunOSSTempToken.Expiration.AddSeconds(10) <= DateTime.Now)
|
||||||
|
{
|
||||||
|
GetObjectStoreTempToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
|
{
|
||||||
|
if (AWSTempToken == null)
|
||||||
|
{
|
||||||
|
GetObjectStoreTempToken();
|
||||||
|
}
|
||||||
|
//token 过期了
|
||||||
|
else if (AWSTempToken.Expiration?.AddSeconds(10) <= DateTime.Now)
|
||||||
|
{
|
||||||
|
GetObjectStoreTempToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
||||||
@@ -290,7 +333,7 @@ public class OSSService : IOSSService
|
|||||||
/// <exception cref="BusinessValidationFailedException"></exception>
|
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||||
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
|
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
BackBatchGetToken();
|
||||||
|
|
||||||
var localFileName = Path.GetFileName(localFilePath);
|
var localFileName = Path.GetFileName(localFilePath);
|
||||||
|
|
||||||
@@ -311,9 +354,14 @@ public class OSSService : IOSSService
|
|||||||
{
|
{
|
||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
var httpClientHandler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
|
||||||
|
};
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
||||||
|
.WithHttpClient(new HttpClient(httpClientHandler))
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var putObjectArgs = new PutObjectArgs()
|
var putObjectArgs = new PutObjectArgs()
|
||||||
@@ -360,7 +408,7 @@ public class OSSService : IOSSService
|
|||||||
|
|
||||||
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
|
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
BackBatchGetToken();
|
||||||
|
|
||||||
ossRelativePath = ossRelativePath.TrimStart('/');
|
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||||
try
|
try
|
||||||
@@ -373,23 +421,29 @@ public class OSSService : IOSSService
|
|||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||||
|
|
||||||
// 上传文件
|
|
||||||
var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
|
var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
|
||||||
|
|
||||||
// 将下载的文件流保存到本地文件
|
// 将下载的文件流保存到本地文件
|
||||||
using (var fs = File.OpenWrite(localFilePath))
|
using (var fs = File.OpenWrite(localFilePath))
|
||||||
{
|
{
|
||||||
result.Content.CopyTo(fs);
|
await result.Content.CopyToAsync(fs);
|
||||||
fs.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||||
{
|
{
|
||||||
|
var httpClientHandler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
|
||||||
|
};
|
||||||
|
|
||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
//Console.WriteLine(minIOConfig.ToJsonStr() +$"ossRelativePath:{ossRelativePath} localFilePath:{localFilePath} ");
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
||||||
|
.WithHttpClient(new HttpClient(httpClientHandler))
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var getObjectArgs = new GetObjectArgs()
|
var getObjectArgs = new GetObjectArgs()
|
||||||
@@ -444,6 +498,148 @@ public class OSSService : IOSSService
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Stream> GetStreamFromOSSAsync(string ossRelativePath)
|
||||||
|
{
|
||||||
|
BackBatchGetToken();
|
||||||
|
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||||
|
{
|
||||||
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
|
||||||
|
var _ossClient = new OssClient(
|
||||||
|
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint,
|
||||||
|
AliyunOSSTempToken.AccessKeyId,
|
||||||
|
AliyunOSSTempToken.AccessKeySecret,
|
||||||
|
AliyunOSSTempToken.SecurityToken
|
||||||
|
);
|
||||||
|
|
||||||
|
var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
|
||||||
|
|
||||||
|
return result.Content;
|
||||||
|
//// 将OSS返回的流复制到内存流中并返回
|
||||||
|
//var memoryStream = new MemoryStream();
|
||||||
|
//await result.Content.CopyToAsync(memoryStream);
|
||||||
|
//memoryStream.Position = 0; // 重置位置以便读取
|
||||||
|
//return memoryStream;
|
||||||
|
}
|
||||||
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||||
|
{
|
||||||
|
|
||||||
|
var httpClientHandler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
|
||||||
|
};
|
||||||
|
|
||||||
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
var minioClient = new MinioClient()
|
||||||
|
.WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey)
|
||||||
|
.WithSSL(minIOConfig.UseSSL)
|
||||||
|
.WithHttpClient(new HttpClient(httpClientHandler))
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region 废弃2
|
||||||
|
|
||||||
|
var pipe = new System.IO.Pipelines.Pipe();
|
||||||
|
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var args = new GetObjectArgs()
|
||||||
|
.WithBucket(minIOConfig.BucketName)
|
||||||
|
.WithObject(ossRelativePath)
|
||||||
|
.WithCallbackStream(stream =>
|
||||||
|
{
|
||||||
|
stream.CopyTo(pipe.Writer.AsStream());
|
||||||
|
pipe.Writer.FlushAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
await minioClient.GetObjectAsync(args);
|
||||||
|
await pipe.Writer.CompleteAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"minio 获取流错误:{ex.Message}");
|
||||||
|
await pipe.Writer.CompleteAsync(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return pipe.Reader.AsStream();
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region 废弃
|
||||||
|
|
||||||
|
//var memoryStream = new MemoryStream();
|
||||||
|
|
||||||
|
//var getObjectArgs = new GetObjectArgs()
|
||||||
|
// .WithBucket(minIOConfig.BucketName)
|
||||||
|
// .WithObject(ossRelativePath)
|
||||||
|
// .WithCallbackStream(async stream => await stream.CopyToAsync(memoryStream));
|
||||||
|
|
||||||
|
//await minioClient.GetObjectAsync(getObjectArgs);
|
||||||
|
//memoryStream.Position = 0;
|
||||||
|
//return memoryStream;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
|
{
|
||||||
|
var awsConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
|
var credentials = new SessionAWSCredentials(
|
||||||
|
AWSTempToken.AccessKeyId,
|
||||||
|
AWSTempToken.SecretAccessKey,
|
||||||
|
AWSTempToken.SessionToken
|
||||||
|
);
|
||||||
|
|
||||||
|
var clientConfig = new AmazonS3Config
|
||||||
|
{
|
||||||
|
RegionEndpoint = RegionEndpoint.USEast1,
|
||||||
|
UseHttp = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||||
|
|
||||||
|
var getObjectRequest = new Amazon.S3.Model.GetObjectRequest
|
||||||
|
{
|
||||||
|
BucketName = awsConfig.BucketName,
|
||||||
|
Key = ossRelativePath
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await amazonS3Client.GetObjectAsync(getObjectRequest);
|
||||||
|
|
||||||
|
// ⭐ 直接返回流
|
||||||
|
return response.ResponseStream;
|
||||||
|
|
||||||
|
//var memoryStream = new MemoryStream();
|
||||||
|
//await response.ResponseStream.CopyToAsync(memoryStream);
|
||||||
|
//memoryStream.Position = 0;
|
||||||
|
//return memoryStream;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new BusinessValidationFailedException("oss流获取失败! " + ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<string> GetSignedUrl(string ossRelativePath)
|
public async Task<string> GetSignedUrl(string ossRelativePath)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
GetObjectStoreTempToken();
|
||||||
@@ -837,8 +1033,14 @@ public class OSSService : IOSSService
|
|||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
|
||||||
|
var httpClientHandler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
|
||||||
|
};
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
||||||
|
.WithHttpClient(new HttpClient(httpClientHandler))
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
|
||||||
@@ -946,8 +1148,15 @@ public class OSSService : IOSSService
|
|||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
|
||||||
|
var httpClientHandler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
||||||
|
.WithHttpClient(new HttpClient(httpClientHandler))
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
|
||||||
@@ -1000,14 +1209,9 @@ public class OSSService : IOSSService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool isFirstCall = true;
|
|
||||||
public async Task<long> GetObjectSizeAsync(string sourcePath)
|
public async Task<long> GetObjectSizeAsync(string sourcePath)
|
||||||
{
|
{
|
||||||
if (isFirstCall)
|
BackBatchGetToken();
|
||||||
{
|
|
||||||
GetObjectStoreTempToken();
|
|
||||||
isFirstCall = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var objectkey = sourcePath.Trim('/');
|
var objectkey = sourcePath.Trim('/');
|
||||||
@@ -1018,9 +1222,10 @@ public class OSSService : IOSSService
|
|||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||||
|
|
||||||
var metadata = _ossClient.GetObjectMetadata(aliConfig.BucketName, objectkey);
|
var key = HttpUtility.UrlDecode(objectkey);
|
||||||
|
var metadata = _ossClient.GetObjectMetadata(aliConfig.BucketName, key);
|
||||||
|
|
||||||
long fileSize = metadata.ContentLength; // 文件大小(字节)
|
long fileSize = metadata?.ContentLength ?? 0; // 文件大小(字节)
|
||||||
|
|
||||||
return fileSize;
|
return fileSize;
|
||||||
}
|
}
|
||||||
@@ -1029,8 +1234,15 @@ public class OSSService : IOSSService
|
|||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
|
||||||
|
var httpClientHandler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
||||||
|
.WithHttpClient(new HttpClient(httpClientHandler))
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,20 +15,14 @@ public static class ImageHelper
|
|||||||
|
|
||||||
fileStorePath = fileStorePath ?? filePath + ".preview.jpeg";
|
fileStorePath = fileStorePath ?? filePath + ".preview.jpeg";
|
||||||
|
|
||||||
// 读取 DICOM 文件
|
using (var image = SixLabors.ImageSharp.Image.Load(filePath))
|
||||||
var dicomImage = new DicomImage(filePath);
|
|
||||||
|
|
||||||
// 渲染 DICOM 图像到 ImageSharp 格式
|
|
||||||
using (var image = dicomImage.RenderImage().AsSharpImage())
|
|
||||||
{
|
{
|
||||||
// 生成缩略图(调整大小)
|
|
||||||
image.Mutate(x => x.Resize(500, 500));
|
image.Mutate(x => x.Resize(500, 500));
|
||||||
|
|
||||||
// 保存缩略图为 JPEG
|
image.Save(fileStorePath);
|
||||||
image.Save(fileStorePath, new JpegEncoder());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user