Compare commits
693 Commits
Test_IRC_N
...
Test_HIR_N
| Author | SHA1 | Date |
|---|---|---|
|
|
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(); });
|
||||
var logFactory = LoggerFactory.Create(builder => { builder.AddDebug(); });
|
||||
|
||||
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value,
|
||||
contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
|
||||
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value);
|
||||
|
||||
options.UseLoggerFactory(logFactory);
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<BaseOutputPath></BaseOutputPath>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<DocumentationFile>.\IRC.Core.SCP.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.4" />
|
||||
<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="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
||||
<PackageReference Include="AWSSDK.S3" Version="3.7.405" />
|
||||
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.400.36" />
|
||||
<PackageReference Include="DistributedLock.Core" Version="1.0.7" />
|
||||
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.5" />
|
||||
<PackageReference Include="fo-dicom" Version="5.1.3" />
|
||||
<PackageReference Include="fo-dicom.Codecs" Version="5.15.1" />
|
||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.1.3" />
|
||||
<PackageReference Include="AWSSDK.S3" Version="4.0.6.9" />
|
||||
<PackageReference Include="AWSSDK.SecurityToken" Version="4.0.2" />
|
||||
<PackageReference Include="DistributedLock.Core" Version="1.0.8" />
|
||||
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
|
||||
<PackageReference Include="fo-dicom" Version="5.2.2" />
|
||||
<PackageReference Include="fo-dicom.Codecs" Version="5.16.4" />
|
||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
|
||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||
<PackageReference Include="Minio" Version="6.0.3" />
|
||||
<PackageReference Include="Minio" Version="7.0.0" />
|
||||
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
||||
<TreatAsUsed>true</TreatAsUsed>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
||||
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.1.2" />
|
||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.4.0" />
|
||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||
<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>
|
||||
|
|
@ -36,4 +56,12 @@
|
|||
<ProjectReference Include="..\IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="appsettings.Prod_HIR_SCP.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>IRC.Core.SCP</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<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>
|
||||
|
|
@ -6,6 +6,7 @@ using FellowOakDicom;
|
|||
using FellowOakDicom.Imaging;
|
||||
using FellowOakDicom.Imaging.NativeCodec;
|
||||
using FellowOakDicom.Network;
|
||||
using IRaCIS.Core.API;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.SCP;
|
||||
using IRaCIS.Core.SCP.Filter;
|
||||
|
|
@ -14,6 +15,7 @@ using MassTransit;
|
|||
using MassTransit.NewIdProviders;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Identity.Client;
|
||||
using Panda.DynamicWebApi;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
|
|
@ -82,7 +84,6 @@ builder.Services.AddControllers(options =>
|
|||
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
|
||||
|
||||
|
||||
builder.Services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
|
||||
builder.Services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
|
||||
builder.Services.AddOptions().Configure<DicomSCPServiceOption>(_configuration.GetSection("DicomSCPServiceConfig"));
|
||||
|
||||
|
|
@ -126,37 +127,54 @@ builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
|||
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||
});
|
||||
|
||||
//Dicom影像渲染图片 跨平台
|
||||
//builder.Services.AddDicomSetup();
|
||||
new DicomSetupBuilder()
|
||||
.RegisterServices(s =>
|
||||
s.AddFellowOakDicom()
|
||||
.AddTranscoderManager<NativeTranscoderManager>()
|
||||
builder.Services.AddFellowOakDicom().AddTranscoderManager<NativeTranscoderManager>()
|
||||
//.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
||||
.AddImageManager<ImageSharpImageManager>())
|
||||
.SkipValidation()
|
||||
.Build();
|
||||
.AddImageManager<ImageSharpImageManager>();
|
||||
|
||||
|
||||
|
||||
////Dicom影像渲染图片 跨平台
|
||||
////builder.Services.AddDicomSetup();
|
||||
//new DicomSetupBuilder()
|
||||
// .RegisterServices(s =>
|
||||
// s.AddFellowOakDicom()
|
||||
// .AddTranscoderManager<NativeTranscoderManager>()
|
||||
// //.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
||||
// .AddImageManager<ImageSharpImageManager>())
|
||||
// .SkipValidation()
|
||||
|
||||
// .Build();
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
// Add services to the container.
|
||||
|
||||
builder.Services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
//builder.Services.AddEndpointsApiExplorer();
|
||||
//builder.Services.AddSwaggerGen();
|
||||
|
||||
//Swagger Api 文档
|
||||
builder.Services.AddSwaggerSetup();
|
||||
|
||||
// FusionCache
|
||||
builder.Services.AddFusionCache();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
//if (app.Environment.IsDevelopment())
|
||||
//{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
//app.UseSwagger();
|
||||
//app.UseSwaggerUI();
|
||||
//}
|
||||
|
||||
//不需要 token 访问的静态文件 wwwroot css, JavaScript, and images don't require authentication.
|
||||
app.UseStaticFiles();
|
||||
|
||||
SwaggerSetup.Configure(app, app.Environment);
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
|
@ -185,6 +203,7 @@ app.MapControllers();
|
|||
Log.Logger = new LoggerConfiguration()
|
||||
//.MinimumLevel.Information()
|
||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("ZiggyCreatures.Caching.Fusion", LogEventLevel.Warning)
|
||||
.WriteTo.Console()
|
||||
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day)
|
||||
.CreateLogger();
|
||||
|
|
@ -211,9 +230,17 @@ else
|
|||
|
||||
#endregion
|
||||
|
||||
DicomSetupBuilder.UseServiceProvider(app.Services);
|
||||
|
||||
// Program.cs
|
||||
IRCAppConfig.Configuration = builder.Configuration;
|
||||
|
||||
|
||||
var logger = app.Services.GetService<Microsoft.Extensions.Logging.ILogger<Program>>();
|
||||
|
||||
var server = DicomServerFactory.Create<CStoreSCPService>(_configuration.GetSection("DicomSCPServiceConfig").GetValue<int>("ServerPort"), userState: app.Services,logger: logger);
|
||||
|
||||
|
||||
|
||||
|
||||
app.Run();
|
||||
|
|
|
|||
|
|
@ -1,24 +1,34 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"Test_IRC_SCP": {
|
||||
"Test_HIR_SCP": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:6200",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Test_IRC_SCP"
|
||||
"ASPNETCORE_ENVIRONMENT": "Test_HIR_SCP"
|
||||
}
|
||||
},
|
||||
"Uat_IRC_SCP": {
|
||||
"Uat_HIR_SCP": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:6200",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Uat_IRC_SCP"
|
||||
"ASPNETCORE_ENVIRONMENT": "Uat_HIR_SCP"
|
||||
}
|
||||
},
|
||||
"Prod_HIR_SCP": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:6200",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Prod_HIR_SCP"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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,37 +11,19 @@ using FellowOakDicom.Network;
|
|||
using IRaCIS.Core.SCP.Service;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using MassTransit;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using Serilog.Sinks.File;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using ZiggyCreatures.Caching.Fusion;
|
||||
|
||||
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,18 +34,20 @@ namespace IRaCIS.Core.SCP.Service
|
|||
/// <param name="dataset"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public async Task<Guid> ArchiveDicomFileAsync(DicomDataset dataset, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize)
|
||||
public async Task<Guid> ArchiveDicomFileAsync(DicomFile dicomFile, string fileRelativePath, string callingAE, string calledAE, long fileSize)
|
||||
{
|
||||
var dataset = dicomFile.Dataset;
|
||||
|
||||
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
||||
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
|
||||
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
|
||||
|
||||
string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID,string.Empty);
|
||||
string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
|
||||
|
||||
//Guid patientId= IdentifierHelper.CreateGuid(patientIdStr);
|
||||
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid,trialId.ToString());
|
||||
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, trialId.ToString());
|
||||
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, trialId.ToString());
|
||||
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid);
|
||||
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid);
|
||||
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid);
|
||||
|
||||
var isStudyNeedAdd = false;
|
||||
var isSeriesNeedAdd = false;
|
||||
|
|
@ -74,15 +58,16 @@ namespace IRaCIS.Core.SCP.Service
|
|||
|
||||
//using (@lock.Acquire())
|
||||
{
|
||||
var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr && t.TrialSiteId==trialSiteId );
|
||||
var findStudy = await _studyRepository.FirstOrDefaultAsync(t=>t.Id== studyId);
|
||||
var findSerice = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
|
||||
var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr);
|
||||
var findStudy = await _studyRepository.FirstOrDefaultAsync(t => t.Id == studyId);
|
||||
var findSerice = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
|
||||
var findInstance = await _instanceRepository.FirstOrDefaultAsync(t => t.Id == instanceId);
|
||||
|
||||
|
||||
DateTime? studyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.StudyTime).TimeOfDay);
|
||||
|
||||
//先传输了修改了患者编号的,又传输了没有修改患者编号的,导致后传输的没有修改患者编号的下面的检查为0
|
||||
if (findPatient == null && findStudy==null)
|
||||
//先传输了,修改了患者编号的,又传输了没有修改患者编号的,导致后传输的没有修改患者编号的下面的检查为0
|
||||
if (findPatient == null /*&& findStudy == null*/)
|
||||
{
|
||||
isPatientNeedAdd = true;
|
||||
|
||||
|
|
@ -90,8 +75,6 @@ namespace IRaCIS.Core.SCP.Service
|
|||
findPatient = new SCPPatient()
|
||||
{
|
||||
Id = NewId.NextSequentialGuid(),
|
||||
TrialId=trialId,
|
||||
TrialSiteId=trialSiteId,
|
||||
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
|
||||
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
|
||||
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
|
||||
|
|
@ -117,20 +100,6 @@ namespace IRaCIS.Core.SCP.Service
|
|||
{
|
||||
findPatient.PatientBirthDate = birthDateStr;
|
||||
|
||||
DateTime birthDate;
|
||||
|
||||
if (findPatient.PatientAge == string.Empty && studyTime.HasValue && DateTime.TryParse(findPatient.PatientBirthDate,out birthDate))
|
||||
{
|
||||
var patientAge = studyTime.Value.Year - birthDate.Year;
|
||||
// 如果生日还未到,年龄减去一岁
|
||||
if (studyTime.Value < birthDate.AddYears(patientAge))
|
||||
{
|
||||
patientAge--;
|
||||
}
|
||||
|
||||
findPatient.PatientAge = patientAge.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -151,6 +120,32 @@ namespace IRaCIS.Core.SCP.Service
|
|||
}
|
||||
|
||||
findPatient.LatestPushTime = DateTime.Now;
|
||||
findPatient.PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
|
||||
findPatient.PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty);
|
||||
findPatient.PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty);
|
||||
findPatient.PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty);
|
||||
|
||||
if (findPatient.PatientBirthDate.Length == 8)
|
||||
{
|
||||
var birthDateStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}-{findPatient.PatientBirthDate[4]}{findPatient.PatientBirthDate[5]}-{findPatient.PatientBirthDate[6]}{findPatient.PatientBirthDate[7]}";
|
||||
|
||||
var yearStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}";
|
||||
|
||||
int year = 0;
|
||||
|
||||
var canParse = int.TryParse(yearStr, out year);
|
||||
|
||||
if (canParse && year > 1900)
|
||||
{
|
||||
findPatient.PatientBirthDate = birthDateStr;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
findPatient.PatientBirthDate = string.Empty;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (findStudy == null)
|
||||
|
|
@ -163,10 +158,12 @@ namespace IRaCIS.Core.SCP.Service
|
|||
|
||||
PatientId = findPatient.Id,
|
||||
Id = studyId,
|
||||
TrialId = trialId,
|
||||
TrialSiteId = trialSiteId,
|
||||
StudyInstanceUid = studyInstanceUid,
|
||||
StudyTime = studyTime,
|
||||
DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty),
|
||||
DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty),
|
||||
|
||||
|
||||
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||
//ModalityForEdit = modalityForEdit,
|
||||
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
|
||||
|
|
@ -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]}";
|
||||
}
|
||||
}
|
||||
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)
|
||||
|
|
@ -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 = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.SeriesDate) + dataset.GetSingleValue<string>(DicomTag.SeriesTime), out DateTime dt) ? dt : null,
|
||||
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay),
|
||||
DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty),
|
||||
DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty),
|
||||
|
||||
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
|
||||
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
||||
|
|
@ -239,7 +253,20 @@ namespace IRaCIS.Core.SCP.Service
|
|||
|
||||
++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)
|
||||
{
|
||||
|
|
@ -253,6 +280,12 @@ namespace IRaCIS.Core.SCP.Service
|
|||
SeriesInstanceUid = findSerice.SeriesInstanceUid,
|
||||
|
||||
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),
|
||||
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,
|
||||
|
|
@ -264,7 +297,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||
SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0),
|
||||
|
||||
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),
|
||||
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
||||
FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty),
|
||||
|
|
@ -273,13 +306,21 @@ namespace IRaCIS.Core.SCP.Service
|
|||
|
||||
Path = fileRelativePath,
|
||||
|
||||
FileSize= fileSize,
|
||||
|
||||
FileSize = fileSize,
|
||||
};
|
||||
|
||||
++findStudy.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)
|
||||
{
|
||||
|
|
@ -298,13 +339,14 @@ namespace IRaCIS.Core.SCP.Service
|
|||
{
|
||||
await _seriesRepository.AddAsync(findSerice);
|
||||
}
|
||||
|
||||
if (isInstanceNeedAdd)
|
||||
{
|
||||
await _instanceRepository.AddAsync(findInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath,FileSize=fileSize });
|
||||
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath, FileSize = fileSize });
|
||||
}
|
||||
|
||||
await _studyRepository.SaveChangesAsync();
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||
{
|
||||
public interface IDicomArchiveService
|
||||
{
|
||||
Task<Guid> ArchiveDicomFileAsync(DicomDataset dicomDataset,Guid trialId,Guid trialSiteId, string fileRelativePath,string callingAE,string calledAE,long fileSize);
|
||||
Task<Guid> ArchiveDicomFileAsync(DicomFile dicomFile,string fileRelativePath,string callingAE,string calledAE,long fileSize);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using MassTransit;
|
|||
using Microsoft.Extensions.Options;
|
||||
using Minio;
|
||||
using Minio.DataModel.Args;
|
||||
using System.Net;
|
||||
using System.Reactive.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
|
@ -118,7 +119,7 @@ public class AWSTempToken
|
|||
public string SecretAccessKey { get; set; }
|
||||
public string BucketName { get; set; }
|
||||
public string ViewEndpoint { get; set; }
|
||||
public DateTime Expiration { get; set; }
|
||||
public DateTime? Expiration { get; set; }
|
||||
}
|
||||
|
||||
public enum ObjectStoreUse
|
||||
|
|
@ -216,9 +217,19 @@ public class OSSService : IOSSService
|
|||
.WithBucket(minIOConfig.BucketName)
|
||||
.WithObject(ossRelativePath)
|
||||
.WithStreamData(memoryStream)
|
||||
|
||||
.WithObjectSize(memoryStream.Length);
|
||||
|
||||
await minioClient.PutObjectAsync(putObjectArgs);
|
||||
var putResponse = await minioClient.PutObjectAsync(putObjectArgs);
|
||||
|
||||
if (putResponse.ResponseStatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException($"上传失败ResponseStatusCode:{putResponse.ResponseStatusCode}{putResponse.ResponseContent}");
|
||||
}
|
||||
}
|
||||
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": 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/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-prod-mssql-service,1433;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
"Hangfire": "Server=us-prod-mssql-service,1433;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||
},
|
||||
"DicomSCPServiceConfig": {
|
||||
"CalledAEList": [
|
||||
"STORESCP"
|
||||
],
|
||||
"ServerPort": 11112
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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": 11112
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ObjectStoreService": {
|
||||
"ObjectStoreUse": "AliyunOSS",
|
||||
"AliyunOSS": {
|
||||
"RegionId": "cn-shanghai",
|
||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||
"AccessKeyId": "LTAI5tRRZehUp2V9pyTPtAJm",
|
||||
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
|
||||
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
|
||||
"BucketName": "zy-irc-uat-store",
|
||||
"ViewEndpoint": "https://zy-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
|
||||
"Region": "oss-cn-shanghai",
|
||||
"DurationSeconds": 7200
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"RemoteNew": "Server=47.117.164.182,1434;Database=Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
"Hangfire": "Server=47.117.164.182,1434;Database=Uat_IRC.Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||
},
|
||||
"DicomSCPServiceConfig": {
|
||||
"CalledAEList": [
|
||||
"STORESCP"
|
||||
],
|
||||
"ServerPort": 11112
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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,4 +1,5 @@
|
|||
using Amazon.Auth.AccessControlPolicy;
|
||||
using AlibabaCloud.SDK.Sts20150401;
|
||||
using Amazon.Auth.AccessControlPolicy;
|
||||
using Amazon.SecurityToken;
|
||||
using Azure.Core;
|
||||
using IdentityModel.Client;
|
||||
|
|
@ -24,6 +25,7 @@ using RestSharp;
|
|||
using RestSharp.Authenticators;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
|
|
@ -100,201 +102,6 @@ namespace IRaCIS.Api.Controllers
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary> 系统用户登录接口[New] </summary>
|
||||
[HttpPost, Route("user/login")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IResponseOutput> Login(UserLoginDTO loginUser,
|
||||
[FromServices] IFusionCache _fusionCache,
|
||||
[FromServices] IUserService _userService,
|
||||
[FromServices] ITokenService _tokenService,
|
||||
[FromServices] IReadingImageTaskService readingImageTaskService,
|
||||
[FromServices] IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig,
|
||||
[FromServices] IOptionsMonitor<SystemEmailSendConfig> _emailConfig,
|
||||
|
||||
[FromServices] IMailVerificationService _mailVerificationService)
|
||||
{
|
||||
var emailConfig = _emailConfig.CurrentValue;
|
||||
var companyInfo = new SystemEmailSendConfigView() { CompanyName = emailConfig.CompanyName, CompanyNameCN = emailConfig.CompanyNameCN, CompanyShortName = emailConfig.CompanyShortName, CompanyShortNameCN = emailConfig.CompanyShortNameCN };
|
||||
|
||||
//MFA 邮箱验证 前端传递用户Id 和MFACode
|
||||
if (loginUser.UserId != null && _verifyConfig.CurrentValue.OpenLoginMFA)
|
||||
{
|
||||
Guid userId = (Guid)loginUser.UserId;
|
||||
|
||||
//验证MFA 编码是否有问题 ,前端要拆开,自己调用验证的逻辑
|
||||
//await _userService.VerifyMFACodeAsync(userId, loginUser.MFACode);
|
||||
|
||||
//var loginUser = await _userRepository.Where(u => u.UserName.Equals(userName) && u.Password == password).ProjectTo<UserBasicInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
|
||||
|
||||
var basicInfo = await _userService.GetUserBasicInfo(userId, loginUser.Password);
|
||||
|
||||
var loginReturn = new LoginReturnDTO() { BasicInfo = basicInfo };
|
||||
|
||||
loginReturn.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(loginReturn.BasicInfo));
|
||||
|
||||
|
||||
// 创建一个 CookieOptions 对象,用于设置 Cookie 的属性
|
||||
var option = new CookieOptions
|
||||
{
|
||||
Expires = DateTime.Now.AddMonths(1), // 设置过期时间为 30 分钟之后
|
||||
HttpOnly = false, // 确保 cookie 只能通过 HTTP 访问
|
||||
SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None, // 设置 SameSite 属性
|
||||
Secure = false // 确保 cookie 只能通过 HTTPS 访问
|
||||
};
|
||||
|
||||
HttpContext.Response.Cookies.Append("access_token", loginReturn.JWTStr, option);
|
||||
|
||||
// 验证阅片休息时间
|
||||
await readingImageTaskService.ResetReadingRestTime(userId);
|
||||
|
||||
await _fusionCache.SetAsync(CacheKeys.UserToken(userId), loginReturn.JWTStr, TimeSpan.FromDays(7));
|
||||
|
||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(userId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(_verifyConfig.CurrentValue.AutoLoginOutMinutes));
|
||||
|
||||
loginReturn.CompanyInfo = companyInfo;
|
||||
return ResponseOutput.Ok(loginReturn);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var returnModel = await _userService.Login(loginUser.UserName, loginUser.Password);
|
||||
|
||||
if (returnModel.IsSuccess)
|
||||
{
|
||||
#region GRPC 调用鉴权中心,因为服务器IIS问题 http/2 故而没法使用
|
||||
|
||||
////重试策略
|
||||
//var defaultMethodConfig = new MethodConfig
|
||||
//{
|
||||
// Names = { MethodName.Default },
|
||||
// RetryPolicy = new RetryPolicy
|
||||
// {
|
||||
// MaxAttempts = 3,
|
||||
// InitialBackoff = TimeSpan.FromSeconds(1),
|
||||
// MaxBackoff = TimeSpan.FromSeconds(5),
|
||||
// BackoffMultiplier = 1.5,
|
||||
// RetryableStatusCodes = { Grpc.Core.StatusCode.Unavailable }
|
||||
// }
|
||||
//};
|
||||
|
||||
//#region unable to trust the certificate then the gRPC client can be configured to ignore the invalid certificate
|
||||
|
||||
//var httpHandler = new HttpClientHandler();
|
||||
//// Return `true` to allow certificates that are untrusted/invalid
|
||||
//httpHandler.ServerCertificateCustomValidationCallback =
|
||||
// HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
|
||||
|
||||
|
||||
//////这一句是让grpc支持本地 http 如果本地访问部署在服务器上,那么是访问不成功的
|
||||
//AppContext.SetSwitch(
|
||||
// "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
//var grpcAdress = configuration.GetValue<string>("GrpcAddress");
|
||||
////var grpcAdress = "http://localhost:7200";
|
||||
|
||||
//var channel = GrpcChannel.ForAddress(grpcAdress, new GrpcChannelOptions
|
||||
//{
|
||||
// HttpHandler = httpHandler,
|
||||
// ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
|
||||
|
||||
//});
|
||||
////var channel = GrpcChannel.ForAddress(grpcAdress);
|
||||
//var grpcClient = new TokenGrpcService.TokenGrpcServiceClient(channel);
|
||||
|
||||
//var userInfo = returnModel.Data.BasicInfo;
|
||||
|
||||
//var tokenResponse = grpcClient.GetUserToken(new GetTokenReuqest()
|
||||
//{
|
||||
// Id = userInfo.Id.ToString(),
|
||||
// ReviewerCode = userInfo.ReviewerCode,
|
||||
// IsAdmin = userInfo.IsAdmin,
|
||||
// RealName = userInfo.RealName,
|
||||
// UserTypeEnumInt = (int)userInfo.UserTypeEnum,
|
||||
// UserTypeShortName = userInfo.UserTypeShortName,
|
||||
// UserName = userInfo.UserName
|
||||
//});
|
||||
|
||||
//returnModel.Data.JWTStr = tokenResponse.Token;
|
||||
|
||||
#endregion
|
||||
|
||||
var userId = returnModel.Data.BasicInfo.Id;
|
||||
|
||||
if (_verifyConfig.CurrentValue.OpenLoginMFA)
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
//MFA 发送邮件
|
||||
|
||||
returnModel.Data.IsMFA = true;
|
||||
|
||||
var email = returnModel.Data.BasicInfo.EMail;
|
||||
|
||||
var hiddenEmail = IRCEmailPasswordHelper.MaskEmail(email);
|
||||
|
||||
returnModel.Data.BasicInfo.EMail = hiddenEmail;
|
||||
|
||||
//修改密码
|
||||
if (returnModel.Data.BasicInfo.IsFirstAdd || returnModel.Data.BasicInfo.LoginState == 1)
|
||||
{
|
||||
returnModel.Data.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(returnModel.Data.BasicInfo));
|
||||
}
|
||||
else
|
||||
{
|
||||
//正常登录才发送邮件
|
||||
await _userService.SendMFAEmail(userId);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
returnModel.Data.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(returnModel.Data.BasicInfo));
|
||||
|
||||
// 创建一个 CookieOptions 对象,用于设置 Cookie 的属性
|
||||
var option = new CookieOptions
|
||||
{
|
||||
Expires = DateTime.Now.AddMonths(1), // 设置过期时间为 30 分钟之后
|
||||
HttpOnly = false, // 确保 cookie 只能通过 HTTP 访问
|
||||
SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None, // 设置 SameSite 属性
|
||||
Secure = false // 确保 cookie 只能通过 HTTPS 访问
|
||||
};
|
||||
|
||||
HttpContext.Response.Cookies.Append("access_token", returnModel.Data.JWTStr, option);
|
||||
|
||||
|
||||
|
||||
// 验证阅片休息时间
|
||||
await readingImageTaskService.ResetReadingRestTime(returnModel.Data.BasicInfo.Id);
|
||||
|
||||
await _fusionCache.SetAsync(CacheKeys.UserToken(userId), returnModel.Data.JWTStr, TimeSpan.FromDays(7));
|
||||
|
||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(userId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(_verifyConfig.CurrentValue.AutoLoginOutMinutes));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
returnModel.Data.CompanyInfo = companyInfo;
|
||||
return returnModel;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet, Route("user/getPublicKey")]
|
||||
public IResponseOutput GetPublicKey([FromServices] IOptionsMonitor<IRCEncreptOption> _IRCEncreptOption)
|
||||
|
|
@ -309,22 +116,18 @@ namespace IRaCIS.Api.Controllers
|
|||
[AllowAnonymous]
|
||||
public IResponseOutput ShareImage([FromServices] ITokenService _tokenService)
|
||||
{
|
||||
var token = _tokenService.GetToken(IRaCISClaims.Create(new UserBasicInfo()
|
||||
var token = _tokenService.GetToken(new UserTokenInfo()
|
||||
{
|
||||
Id = Guid.Empty,
|
||||
IsReviewer = false,
|
||||
IsAdmin = false,
|
||||
RealName = "Share001",
|
||||
IdentityUserId = Guid.NewGuid(),
|
||||
UserName = "Share001",
|
||||
Sex = 0,
|
||||
//UserType = "ShareType",
|
||||
UserTypeEnum = UserTypeEnum.ShareImage,
|
||||
Code = "ShareCode001",
|
||||
}));
|
||||
|
||||
});
|
||||
return ResponseOutput.Ok("/showdicom?studyId=f7b67793-8155-0223-2f15-118f2642efb8&type=Share&token=" + token);
|
||||
}
|
||||
|
||||
[HttpGet("user/GetObjectStoreToken")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IResponseOutput> GetObjectStoreTokenAsync([FromServices] IOptionsMonitor<ObjectStoreServiceOptions> options, [FromServices] IOSSService _oSSService)
|
||||
{
|
||||
|
||||
|
|
@ -374,12 +177,58 @@ namespace IRaCIS.Api.Controllers
|
|||
return tempToken;
|
||||
}
|
||||
|
||||
#region 老项目依赖
|
||||
|
||||
[HttpGet("user/GenerateSTS")]
|
||||
public IResponseOutput GenerateSTS([FromServices] IOptionsMonitor<ObjectStoreServiceOptions> options)
|
||||
{
|
||||
|
||||
var ossOptions = options.CurrentValue.AliyunOSS;
|
||||
|
||||
var client = new Client(new AlibabaCloud.OpenApiClient.Models.Config()
|
||||
{
|
||||
AccessKeyId = ossOptions.AccessKeyId,
|
||||
AccessKeySecret = ossOptions.AccessKeySecret,
|
||||
Endpoint = "sts.cn-hangzhou.aliyuncs.com"
|
||||
});
|
||||
|
||||
var assumeRoleRequest = new AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleRequest();
|
||||
// 将<YOUR_ROLE_SESSION_NAME>设置为自定义的会话名称,例如oss-role-session。
|
||||
assumeRoleRequest.RoleSessionName = $"session-name-{NewId.NextGuid()}";
|
||||
// 将<YOUR_ROLE_ARN>替换为拥有上传文件到指定OSS Bucket权限的RAM角色的ARN。
|
||||
assumeRoleRequest.RoleArn = ossOptions.RoleArn;
|
||||
//assumeRoleRequest.RoleArn = "acs:ram::1899121822495495:role/webdirect";
|
||||
assumeRoleRequest.DurationSeconds = ossOptions.DurationSeconds;
|
||||
var runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
|
||||
var response = client.AssumeRoleWithOptions(assumeRoleRequest, runtime);
|
||||
var credentials = response.Body.Credentials;
|
||||
|
||||
|
||||
|
||||
// 返回STS令牌信息给前端
|
||||
var stsToken = new
|
||||
{
|
||||
AccessKeyId = credentials.AccessKeyId,
|
||||
AccessKeySecret = credentials.AccessKeySecret,
|
||||
SecurityToken = credentials.SecurityToken,
|
||||
Expiration = credentials.Expiration,
|
||||
|
||||
Region = ossOptions.Region,
|
||||
BucketName = ossOptions.BucketName,
|
||||
ViewEndpoint = ossOptions.ViewEndpoint,
|
||||
|
||||
};
|
||||
|
||||
return ResponseOutput.Ok(stsToken);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
[HttpGet("User/UserRedirect")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> UserRedirect([FromServices] IRepository<User> _userRepository, string url, [FromServices] ILogger<ExtraController> _logger)
|
||||
public async Task<IActionResult> UserRedirect([FromServices] IRepository<IdentityUser> _useRepository, string url, [FromServices] ILogger<ExtraController> _logger, [FromServices] ITokenService _tokenService)
|
||||
{
|
||||
|
||||
var decodeUrl = System.Web.HttpUtility.UrlDecode(url);
|
||||
|
|
@ -394,10 +243,22 @@ namespace IRaCIS.Api.Controllers
|
|||
|
||||
var errorUrl = domainStrList[0] + "//" + domainStrList[2] + "/error";
|
||||
|
||||
|
||||
if (!await _userRepository.AnyAsync(t => t.Id == Guid.Parse(userId) && t.EmailToken == token && t.IsFirstAdd))
|
||||
if (lang == "zh")
|
||||
{
|
||||
decodeUrl = errorUrl + $"?lang={lang}&ErrorMessage={System.Web.HttpUtility.UrlEncode(lang == "zh" ? "您的初始化链接已过期" : "Error!The initialization link has expired. Return")} ";
|
||||
CultureInfo.CurrentCulture = new CultureInfo(StaticData.CultureInfo.zh_CN);
|
||||
CultureInfo.CurrentUICulture = new CultureInfo(StaticData.CultureInfo.zh_CN);
|
||||
}
|
||||
else
|
||||
{
|
||||
CultureInfo.CurrentCulture = new CultureInfo(StaticData.CultureInfo.en_US);
|
||||
CultureInfo.CurrentUICulture = new CultureInfo(StaticData.CultureInfo.en_US);
|
||||
}
|
||||
|
||||
var isExpire = _tokenService.IsTokenExpired(token);
|
||||
|
||||
if (!await _useRepository.AnyAsync(t => t.Id == Guid.Parse(userId) && t.EmailToken == token && t.IsFirstAdd) || isExpire)
|
||||
{
|
||||
decodeUrl = errorUrl + $"?lang={lang}&ErrorMessage={System.Web.HttpUtility.UrlEncode(I18n.T("UserRedirect_InitializationLinkExpire"))} ";
|
||||
}
|
||||
|
||||
return Redirect(decodeUrl);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ namespace IRaCIS.Core.API.Controllers
|
|||
[ApiController, ApiExplorerSettings(GroupName = "Reviewer")]
|
||||
[UnitOfWork]
|
||||
public class InspectionController(
|
||||
ITrialDocumentService _trialDocumentService,
|
||||
IReadingImageTaskService _iReadingImageTaskService,
|
||||
ITrialConfigService _trialConfigService,
|
||||
IClinicalAnswerService _clinicalAnswerService,
|
||||
|
|
@ -497,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>
|
||||
|
|
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -69,24 +69,22 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.19" />
|
||||
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ConfigMapFileProvider" Version="2.0.1" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.14" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.20" />
|
||||
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
|
||||
<PackageReference Include="Hangfire.InMemory" Version="1.0.0" />
|
||||
<PackageReference Include="Hangfire.SqlServer" Version="1.8.14" />
|
||||
<PackageReference Include="Invio.Extensions.Authentication.JwtBearer" Version="2.0.1" />
|
||||
<PackageReference Include="LogDashboard" Version="1.4.8" />
|
||||
<PackageReference Include="Hangfire.SqlServer" Version="1.8.20" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
|
||||
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Email" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.9.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="9.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -112,6 +110,60 @@
|
|||
<Content Update="Resources\zh-CN.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\ReadReoprtTemplate\downLoad\file.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\ReadReoprtTemplate\ReportTemplate_IRECIST_CN_V1.docx">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\ReadReoprtTemplate\ReportTemplate_PCWG3_CN_V1.docx">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\ReadReoprtTemplate\ReportTemplate_RECIST1.1_CN_V1.docx">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\ReadReoprtTemplate\TumorEvaluation_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>
|
||||
<None Update="Resources\GeoLite2-City.mmdb">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ProjectExtensions>
|
||||
|
|
|
|||
|
|
@ -34,9 +34,6 @@
|
|||
<param name="doctorId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Api.Controllers.ExtraController.Login(IRaCIS.Application.Contracts.UserLoginDTO,ZiggyCreatures.Caching.Fusion.IFusionCache,IRaCIS.Core.Application.Service.IUserService,IRaCIS.Core.Application.Auth.ITokenService,IRaCIS.Core.Application.Contracts.IReadingImageTaskService,Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.ServiceVerifyConfigOption},Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.SystemEmailSendConfig},IRaCIS.Core.Application.Service.IMailVerificationService)">
|
||||
<summary> 系统用户登录接口[New] </summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Api.Controllers.ExtraController.OAuthCallBack(System.String,System.String)">
|
||||
<summary>
|
||||
回调到前端,前端调用后端的接口
|
||||
|
|
@ -278,12 +275,6 @@
|
|||
<param name="opt"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.UserConfirm(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.UserConfirmCommand})">
|
||||
<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.IVisitTaskHelpeService,IRaCIS.Core.Application.Service.IVisitTaskService)">
|
||||
<summary>
|
||||
重阅同意
|
||||
|
|
|
|||
|
|
@ -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.Application.BusinessFilter;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
|
|
@ -7,7 +9,6 @@ using IRaCIS.Core.Application.Service;
|
|||
using IRaCIS.Core.Application.Service.BusinessFilter;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using LogDashboard;
|
||||
using MassTransit;
|
||||
using MassTransit.NewIdProviders;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
|
@ -25,6 +26,9 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using FellowOakDicom.Imaging.NativeCodec;
|
||||
using FellowOakDicom.Imaging;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
|
||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
|
||||
|
|
@ -100,6 +104,8 @@ builder.Services.AddControllers(options =>
|
|||
})
|
||||
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
|
||||
|
||||
builder.Services.AddOptions().Configure<DicomSCPServiceOption>(_configuration.GetSection("DicomSCPServiceConfig"));
|
||||
|
||||
// Panda动态WebApi + UnifiedApiResultFilter + 省掉控制器代码
|
||||
builder.Services.AddDynamicWebApiSetup();
|
||||
//MinimalAPI
|
||||
|
|
@ -125,11 +131,17 @@ builder.Services.AddFusionCache();
|
|||
// hangfire 定时任务框架 有界面,更友好~
|
||||
builder.Services.AddhangfireSetup(_configuration);
|
||||
|
||||
//Serilog 日志可视化 LogDashboard日志
|
||||
builder.Services.AddLogDashboardSetup();
|
||||
|
||||
//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();
|
||||
|
|
@ -144,6 +156,7 @@ builder.Services.AddSignalR();
|
|||
|
||||
//builder.Services.AddAntiforgery();
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
var app = builder.Build();
|
||||
|
|
@ -210,8 +223,6 @@ app.UseResponseCompression();
|
|||
//不需要 token 访问的静态文件 wwwroot css, JavaScript, and images don't require authentication.
|
||||
app.UseStaticFiles();
|
||||
|
||||
//LogDashboard
|
||||
app.UseLogDashboard("/LogDashboard");
|
||||
|
||||
//hangfire
|
||||
app.UseHangfireConfig(env);
|
||||
|
|
@ -236,6 +247,7 @@ app.MapMasaMinimalAPIs();
|
|||
app.MapControllers();
|
||||
|
||||
app.MapHub<UploadHub>("/UploadHub");
|
||||
app.MapHub<DownloadHub>("/DownloadHub");
|
||||
app.MapHealthChecks("/health");
|
||||
|
||||
|
||||
|
|
@ -277,6 +289,13 @@ try
|
|||
//Log.Logger.Warning($"ContentRootPath——xx:{Path.GetDirectoryName(Path.GetDirectoryName(env.ContentRootPath))}");
|
||||
#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();
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,60 +16,39 @@
|
|||
"ASPNETCORE_ENVIRONMENT": "Test_IRC"
|
||||
}
|
||||
},
|
||||
"IRaCIS.Test_IRC": {
|
||||
"Uat_HIR": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Test_IRC"
|
||||
"ASPNETCORE_ENVIRONMENT": "Uat_HIR"
|
||||
},
|
||||
"applicationUrl": "http://localhost:6100"
|
||||
},
|
||||
"IRaCIS.Test_IRC_PGSQL": {
|
||||
"Prod_HIR": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Test_IRC_PGSQL"
|
||||
"ASPNETCORE_ENVIRONMENT": "Prod_HIR"
|
||||
},
|
||||
"applicationUrl": "http://localhost:6100"
|
||||
},
|
||||
"IRaCIS.Event_IRC": {
|
||||
"US_HIR": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Event_IRC"
|
||||
"ASPNETCORE_ENVIRONMENT": "US_HIR"
|
||||
},
|
||||
"applicationUrl": "http://localhost:6100"
|
||||
},
|
||||
"Docker": {
|
||||
"commandName": "Docker",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
|
||||
"publishAllPorts": true
|
||||
},
|
||||
"IRaCIS.Uat_IRC": {
|
||||
"Test_HIR": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Uat_IRC"
|
||||
},
|
||||
"applicationUrl": "http://localhost:6100"
|
||||
},
|
||||
"IRaCIS.Prod_IRC": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Prod_IRC"
|
||||
},
|
||||
"applicationUrl": "http://localhost:6100"
|
||||
},
|
||||
"IRaCIS.US_Uat_IRC": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "US_Uat_IRC"
|
||||
"ASPNETCORE_ENVIRONMENT": "Test_HIR"
|
||||
},
|
||||
"applicationUrl": "http://localhost:6100"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 73 MiB |
|
|
@ -3,24 +3,27 @@ using Microsoft.AspNetCore.Authorization;
|
|||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
public interface IUploadClient
|
||||
{
|
||||
Task ReceivProgressAsync(string studyInstanceUid, int haveReceivedCount);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class IRaCISUserIdProvider : IUserIdProvider
|
||||
{
|
||||
public virtual string GetUserId(HubConnectionContext connection)
|
||||
{
|
||||
return connection.User?.FindFirst(JwtIRaCISClaimType.Id)?.Value!;
|
||||
return connection.User?.FindFirst(JwtIRaCISClaimType.IdentityUserId)?.Value!;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IUploadClient
|
||||
{
|
||||
Task ReceivProgressAsync(string studyInstanceUid, int haveReceivedCount);
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[DisableCors]
|
||||
public class UploadHub : Hub<IUploadClient>
|
||||
|
|
@ -53,5 +56,34 @@ namespace IRaCIS.Core.API
|
|||
// 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.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
|
||||
|
|
@ -38,7 +39,7 @@ namespace IRaCIS.Core.API
|
|||
diagnosticContext.Set("QueryString", request.QueryString.Value);
|
||||
}
|
||||
|
||||
diagnosticContext.Set("FullName", httpContext?.User?.FindFirst(JwtIRaCISClaimType.RealName)?.Value);
|
||||
diagnosticContext.Set("FullName", httpContext?.User?.FindFirst(JwtIRaCISClaimType.FullName)?.Value);
|
||||
|
||||
diagnosticContext.Set("UserType", httpContext?.User?.FindFirst(JwtIRaCISClaimType.UserTypeShortName)?.Value);
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ namespace IRaCIS.Core.API
|
|||
OnMessageReceived = (context) =>
|
||||
{
|
||||
|
||||
|
||||
|
||||
if (context.Request.Query.TryGetValue("access_token", out StringValues values))
|
||||
{
|
||||
var queryToken = values.FirstOrDefault();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using FellowOakDicom;
|
||||
using FellowOakDicom.Imaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
|
|
@ -9,12 +10,14 @@ namespace IRaCIS.Core.API
|
|||
public static void AddDicomSetup(this IServiceCollection services)
|
||||
{
|
||||
new DicomSetupBuilder()
|
||||
.RegisterServices(s => s.AddFellowOakDicom()
|
||||
.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
||||
.AddImageManager<ImageSharpImageManager>()
|
||||
.RegisterServices(s => s.AddFellowOakDicom().AddLogging(config => config.AddConsole())
|
||||
.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
||||
//.AddImageManager<ImageSharpImageManager>()
|
||||
)
|
||||
.SkipValidation()
|
||||
.Build();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using EntityFramework.Exceptions.SqlServer;
|
||||
using IRaCIS.Core.Application.Triggers;
|
||||
using IRaCIS.Core.Application.Triggers.AfterSaveTrigger;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Infra.EFCore.Interceptor;
|
||||
|
|
@ -80,8 +81,15 @@ namespace IRaCIS.Core.API
|
|||
triggerOptions.AddTrigger<UserLogTrigger>();
|
||||
|
||||
triggerOptions.AddTrigger<UserAddTrigger>();
|
||||
|
||||
triggerOptions.AddTrigger<IdenttiyUserRoleInfoTrigger>();
|
||||
|
||||
triggerOptions.AddTrigger<UserLogAfterTrigger>();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
.MinimumLevel.Information()
|
||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
||||
.MinimumLevel.Override("MassTransit", LogEventLevel.Warning)
|
||||
//https://github.com/ZiggyCreatures/FusionCache/blob/main/docs/Logging.md
|
||||
.MinimumLevel.Override("ZiggyCreatures.Caching.Fusion", LogEventLevel.Warning)
|
||||
// Filter out ASP.NET Core infrastructre logs that are Information and below 日志太多了 一个请求 记录好几条
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting", LogEventLevel.Warning)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using IP2Region.Net.Abstractions;
|
||||
using IP2Region.Net.XDB;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.BackGroundJob;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using IRaCIS.Core.Application.Service;
|
||||
|
|
|
|||
|
|
@ -16,8 +16,12 @@ namespace IRaCIS.Core.API;
|
|||
|
||||
public enum SwaggerVersion
|
||||
{
|
||||
[Description("HIR修改")]
|
||||
HIR = -1,
|
||||
|
||||
[Description("医生模块")]
|
||||
Reviewer = 1,
|
||||
|
||||
[Description("项目模块")]
|
||||
Trial = 2,
|
||||
[Description("入组模块")]
|
||||
|
|
@ -33,11 +37,11 @@ public enum SwaggerVersion
|
|||
[Description("财务模块")]
|
||||
Financial = 8,
|
||||
[Description("管理模块")]
|
||||
Management =9,
|
||||
Management = 9,
|
||||
[Description("影像模块")]
|
||||
Image =10,
|
||||
Image = 10,
|
||||
[Description("读片模块")]
|
||||
Reading =11
|
||||
Reading = 11
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -115,6 +119,9 @@ public static class SwaggerSetup
|
|||
|
||||
//DefaultModelsExpandDepth设置为 - 1 可不显示models
|
||||
options.DefaultModelsExpandDepth(-1);
|
||||
|
||||
// 关键一句:关闭外网校验
|
||||
options.ConfigObject.ValidatorUrl = null;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"RemoteNew": "Server=47.117.164.182,1434;Database=Event_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
"Hangfire": "Server=47.117.164.182,1434;Database=Event_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||
},
|
||||
"ObjectStoreService": {
|
||||
"ObjectStoreUse": "AliyunOSS",
|
||||
"AliyunOSS": {
|
||||
"RegionId": "cn-shanghai",
|
||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||
"AccessKeyId": "LTAI5tNRTsqL6aWmHkDmTwoH",
|
||||
"AccessKeySecret": "7mtGz3qrYWI6JMMBZiLeC119VWicZH",
|
||||
"RoleArn": "acs:ram::1899121822495495:role/irc-oss-access",
|
||||
"BucketName": "zy-irc-store",
|
||||
"ViewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
||||
"Region": "oss-cn-shanghai",
|
||||
"DurationSeconds": 7200
|
||||
},
|
||||
"MinIO": {
|
||||
"endpoint": "http://192.168.3.68",
|
||||
"port": "8001",
|
||||
"useSSL": false,
|
||||
"accessKey": "IDFkwEpWej0b4DtiuThL",
|
||||
"secretKey": "Lhuu83yMhVwu7c1SnjvGY6lq74jzpYqifK6Qtj4h",
|
||||
"bucketName": "test"
|
||||
}
|
||||
},
|
||||
|
||||
"BasicSystemConfig": {
|
||||
|
||||
"OpenUserComplexPassword": true,
|
||||
|
||||
"OpenSignDocumentBeforeWork": true,
|
||||
|
||||
"OpenLoginLimit": true,
|
||||
"LoginMaxFailCount": 5,
|
||||
|
||||
"LoginFailLockMinutes": 30,
|
||||
"AutoLoginOutMinutes": 60,
|
||||
|
||||
"ContinuousReadingTimeMin": 120,
|
||||
|
||||
"ReadingRestTimeMin": 10,
|
||||
|
||||
"IsNeedChangePassWord": true,
|
||||
|
||||
"ChangePassWordDays": 90
|
||||
},
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 465,
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
"FromEmail": "uat@extimaging.com",
|
||||
"FromName": "UAT_IRC",
|
||||
"AuthorizationCode": "SHzyyl2021",
|
||||
"SiteUrl": "http://irc.event.extimaging.com/login",
|
||||
"CompanyName": "Extensive Imaging",
|
||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||
"CompanyShortName": "Extensive Imaging",
|
||||
"CompanyShortNameCN": "展影医疗",
|
||||
"IsEnv_US": false
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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": 360,
|
||||
|
||||
"OpenLoginMFA": false,
|
||||
|
||||
"ContinuousReadingTimeMin": 120,
|
||||
|
||||
"ReadingRestTimeMin": 10,
|
||||
|
||||
"IsNeedChangePassWord": true,
|
||||
|
||||
"ChangePassWordDays": 90
|
||||
},
|
||||
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 465,
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
"FromEmail": "IRC@extimaging.com",
|
||||
"FromName": "IRC",
|
||||
"AuthorizationCode": "ExtImg@2022",
|
||||
"SiteUrl": "http://irc.extimaging.com/login",
|
||||
"OrganizationName": "Extlmaging",
|
||||
"OrganizationNameCN": "Extlmaging",
|
||||
"CompanyName": "Extensive Imaging",
|
||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||
"CompanyShortName": "Extensive Imaging",
|
||||
"CompanyShortNameCN": "展影医疗",
|
||||
"IsEnv_US": false,
|
||||
"IsOpenErrorNoticeEmail": true,
|
||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||
},
|
||||
"SystemPacsConfig": {
|
||||
"Port": "11113",
|
||||
"IP": "101.132.193.237"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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,87 +0,0 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"RemoteNew": "Server=us-prod-mssql-service,1433;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
"Hangfire": "Server=us-prod-mssql-service,1433;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||
//"RemoteNew": "Server=44.210.231.169,1435;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
//"Hangfire": "Server=44.210.231.169,1435;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
},
|
||||
|
||||
"ObjectStoreService": {
|
||||
"ObjectStoreUse": "AWS",
|
||||
"MinIO": {
|
||||
"endPoint": "44.210.231.169",
|
||||
"port": "9001",
|
||||
"useSSL": false,
|
||||
"accessKey": "e9bT1isTOqSAUxb6wd4n",
|
||||
"secretKey": "b5TaDzNdQCBtCvfm8eZ3dR6yY7tfZu2JYze2Po1i",
|
||||
"bucketName": "prod-irc-us",
|
||||
"viewEndpoint": "http://44.210.231.169:9001/prod-irc-us/"
|
||||
},
|
||||
|
||||
"AWS": {
|
||||
"Region": "us-east-1",
|
||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
||||
"UseSSL": true,
|
||||
"RoleArn": "arn:aws:iam::471112624751:role/lili_s3_access",
|
||||
"AccessKeyId": "AKIAW3MEAFJXZ2TZK7GM",
|
||||
"SecretAccessKey": "9MLQCQ1HifEVW1gf068zBRAOb4wNnfrOkvBVByth",
|
||||
"BucketName": "ei-med-s3-lili-store",
|
||||
"ViewEndpoint": "https://ei-med-s3-lili-store.s3.amazonaws.com",
|
||||
"DurationSeconds": 7200
|
||||
}
|
||||
},
|
||||
"BasicSystemConfig": {
|
||||
|
||||
"OpenUserComplexPassword": false,
|
||||
|
||||
"OpenSignDocumentBeforeWork": false,
|
||||
|
||||
"OpenTrialRelationDelete": true,
|
||||
|
||||
"OpenLoginLimit": false,
|
||||
|
||||
"LoginMaxFailCount": 5,
|
||||
|
||||
"LoginFailLockMinutes": 30,
|
||||
"AutoLoginOutMinutes": 60,
|
||||
|
||||
"ContinuousReadingTimeMin": 120,
|
||||
|
||||
"ReadingRestTimeMin": 10,
|
||||
"IsNeedChangePassWord": true,
|
||||
|
||||
"ChangePassWordDays": 90
|
||||
},
|
||||
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 587,
|
||||
"Host": "smtp-mail.outlook.com",
|
||||
"FromEmail": "donotreply@elevateimaging.ai",
|
||||
"FromName": "LiLi",
|
||||
"AuthorizationCode": "Q#669869497420ul",
|
||||
|
||||
"OrganizationName": "Elevate Imaging",
|
||||
"OrganizationNameCN": "Elevate Imaging",
|
||||
"CompanyName": "Elevate Imaging Inc.",
|
||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||
"CompanyShortName": "Elevate Imaging",
|
||||
"CompanyShortNameCN": "展影医疗",
|
||||
"SiteUrl": "https://lili.elevateimaging.ai/login",
|
||||
"IsEnv_US": true,
|
||||
"IsOpenErrorNoticeEmail": true,
|
||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||
},
|
||||
|
||||
"SystemPacsConfig": {
|
||||
"Port": "104",
|
||||
"IP": "44.210.231.169"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||
},
|
||||
|
||||
"ObjectStoreService": {
|
||||
|
||||
"ObjectStoreUse": "AWS",
|
||||
"MinIO": {
|
||||
//"endPoint": "hir-oss.uat.extimaging.com",
|
||||
//"port": "443",
|
||||
//"useSSL": true,
|
||||
//"viewEndpoint": "https://hir-oss.uat.extimaging.com/hir-uat",
|
||||
|
||||
"endPoint": "47.117.164.182",
|
||||
"port": "9001",
|
||||
"useSSL": false,
|
||||
"viewEndpoint": "http://47.117.164.182:9001/test-irc-us",
|
||||
|
||||
"accessKey": "b9Ul0e98xPzt6PwRXA1Q",
|
||||
"secretKey": "DzMaU2L4OXl90uytwOmDXF2encN0Jf4Nxu2XkYqQ",
|
||||
"bucketName": "test-irc-us"
|
||||
|
||||
},
|
||||
|
||||
"AWS": {
|
||||
"Region": "us-east-1",
|
||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
||||
"UseSSL": true,
|
||||
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
|
||||
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
|
||||
"SecretAccessKey": "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,
|
||||
|
||||
"OpenLoginMFA": true
|
||||
},
|
||||
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 587,
|
||||
"Host": "smtp-mail.outlook.com",
|
||||
"FromEmail": "donotreply@elevateimaging.ai",
|
||||
"FromName": "LiLi",
|
||||
"AuthorizationCode": "Q#669869497420ul",
|
||||
|
||||
"OrganizationName": "Elevate Imaging",
|
||||
"OrganizationNameCN": "Elevate Imaging",
|
||||
"CompanyName": "Elevate Imaging Inc.",
|
||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||
"CompanyShortName": "Elevate Imaging",
|
||||
"CompanyShortNameCN": "展影医疗",
|
||||
"SiteUrl": "https://lili.test.elevateimaging.ai/login",
|
||||
"IsEnv_US": true,
|
||||
"IsOpenErrorNoticeEmail": false,
|
||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||
},
|
||||
|
||||
"SystemPacsConfig": {
|
||||
"Port": "104",
|
||||
"IP": "3.226.182.187"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
//"RemoteNew": "Server=us-mssql-service,1433;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
//"Hangfire": "Server=us-mssql-service,1433;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||
|
||||
"RemoteNew": "Server=3.226.182.187,1435;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
"Hangfire": "Server=3.226.182.187,1435;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||
},
|
||||
|
||||
"ObjectStoreService": {
|
||||
|
||||
"ObjectStoreUse": "AWS",
|
||||
|
||||
"MinIO": {
|
||||
//"endPoint": "hir-minio.uat.elevateimaging.ai",
|
||||
//"port": "443",
|
||||
//"useSSL": true,
|
||||
//"viewEndpoint": "https://hir-minio.uat.elevateimaging.ai/uat-irc-us",
|
||||
|
||||
"endPoint": "3.226.182.187",
|
||||
"port": "9001",
|
||||
"useSSL": false,
|
||||
"viewEndpoint": "http://44.218.11.19:9001/uat-irc-us",
|
||||
|
||||
"accessKey": "lH8DkKskLuDqPaiubuSQ",
|
||||
"secretKey": "pdPdicvvLeH7xAC5yFUrI7odMyBfOXxvVWMvKYV4",
|
||||
"bucketName": "uat-irc-us"
|
||||
|
||||
},
|
||||
|
||||
"AWS": {
|
||||
"Region": "us-east-1",
|
||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
||||
"UseSSL": true,
|
||||
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
|
||||
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
|
||||
"SecretAccessKey": "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": false,
|
||||
|
||||
"LoginMaxFailCount": 5,
|
||||
|
||||
"LoginFailLockMinutes": 30,
|
||||
"AutoLoginOutMinutes": 60,
|
||||
|
||||
"ContinuousReadingTimeMin": 120,
|
||||
|
||||
"ReadingRestTimeMin": 10,
|
||||
"IsNeedChangePassWord": true,
|
||||
|
||||
"ChangePassWordDays": 90,
|
||||
|
||||
"OpenLoginMFA": false
|
||||
},
|
||||
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 587,
|
||||
"Host": "smtp-mail.outlook.com",
|
||||
"FromEmail": "donotreply@elevateimaging.ai",
|
||||
"FromName": "LiLi",
|
||||
"AuthorizationCode": "Q#669869497420ul",
|
||||
|
||||
"OrganizationName": "Elevate Imaging",
|
||||
"OrganizationNameCN": "Elevate Imaging",
|
||||
"CompanyName": "Elevate Imaging Inc.",
|
||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||
"CompanyShortName": "Elevate Imaging",
|
||||
"CompanyShortNameCN": "展影医疗",
|
||||
"SiteUrl": "https://lili.test.elevateimaging.ai/login",
|
||||
"IsEnv_US": true,
|
||||
"IsOpenErrorNoticeEmail": false,
|
||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||
},
|
||||
|
||||
"SystemPacsConfig": {
|
||||
"Port": "104",
|
||||
"IP": "3.226.182.187"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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,100 +0,0 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"RemoteNew": "Server=47.117.164.182,1434;Database=Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
"Hangfire": "Server=47.117.164.182,1434;Database=Uat_IRC.Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||
},
|
||||
"ObjectStoreService": {
|
||||
|
||||
"ObjectStoreUse": "AliyunOSS",
|
||||
|
||||
"AliyunOSS": {
|
||||
"RegionId": "cn-shanghai",
|
||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||
"AccessKeyId": "LTAI5tRRZehUp2V9pyTPtAJm",
|
||||
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
|
||||
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
|
||||
"BucketName": "zy-irc-uat-store",
|
||||
"ViewEndpoint": "https://zy-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
|
||||
"Region": "oss-cn-shanghai",
|
||||
"DurationSeconds": 7200
|
||||
},
|
||||
|
||||
"MinIO": {
|
||||
"endPoint": "hir-oss.uat.extimaging.com",
|
||||
"port": "80",
|
||||
"useSSL": false,
|
||||
"viewEndpoint": "http://hir-oss.uat.extimaging.com/irc-uat",
|
||||
//"port": "443",
|
||||
//"useSSL": true,
|
||||
//"viewEndpoint": "https://hir-oss.uat.extimaging.com/irc-uat",
|
||||
"accessKey": "b9Ul0e98xPzt6PwRXA1Q",
|
||||
"secretKey": "DzMaU2L4OXl90uytwOmDXF2encN0Jf4Nxu2XkYqQ",
|
||||
"bucketName": "irc-uat"
|
||||
|
||||
},
|
||||
"AWS": {
|
||||
"Region": "us-east-1",
|
||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
||||
"UseSSL": true,
|
||||
"RoleArn": "arn:aws:iam::471112624751:role/sts_s3_upload",
|
||||
"AccessKeyId": "AKIAW3MEAFJXWRCGSX5Z",
|
||||
"SecretAccessKey": "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": 60,
|
||||
"OpenLoginMFA": false,
|
||||
|
||||
"ContinuousReadingTimeMin": 120,
|
||||
|
||||
"ReadingRestTimeMin": 10,
|
||||
"IsNeedChangePassWord": true,
|
||||
|
||||
"ChangePassWordDays": 90
|
||||
|
||||
},
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 465,
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
"FromEmail": "uat@extimaging.com",
|
||||
"FromName": "UAT_IRC",
|
||||
"AuthorizationCode": "SHzyyl2021",
|
||||
"SiteUrl": "http://irc.uat.extimaging.com/login",
|
||||
"OrganizationName": "Extlmaging",
|
||||
"OrganizationNameCN": "Extlmaging",
|
||||
"CompanyName": "Extensive Imaging",
|
||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||
"CompanyShortName": "Extensive Imaging",
|
||||
"CompanyShortNameCN": "展影医疗",
|
||||
"IsEnv_US": false,
|
||||
"IsOpenErrorNoticeEmail": false,
|
||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||
},
|
||||
|
||||
"SystemPacsConfig": {
|
||||
"Port": "11113",
|
||||
"IP": "47.117.164.182"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
"SecurityKey": "ShangHaiZhanYing_SecurityKey_SHzyyl@2021",
|
||||
"Issuer": "Extimaging",
|
||||
"Audience": "EICS",
|
||||
"TokenExpireDays": "7"
|
||||
"TokenExpireMinute": "10080" //7天
|
||||
},
|
||||
"IpRateLimiting": {
|
||||
"EnableEndpointRateLimiting": true,
|
||||
|
|
|
|||
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.
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.
Binary file not shown.
|
|
@ -268,12 +268,12 @@ var abp = abp || {};
|
|||
}
|
||||
|
||||
function loginUserInternal(tenantId, callback) {
|
||||
|
||||
|
||||
var usernameOrEmailAddress = document.getElementById('userName').value;
|
||||
if (!usernameOrEmailAddress) {
|
||||
alert('UserName Can Not Be Null');
|
||||
return false;
|
||||
}
|
||||
// if (!usernameOrEmailAddress) {
|
||||
// alert('UserName Can Not Be Null');
|
||||
// return false;
|
||||
// }
|
||||
|
||||
var password = document.getElementById('password').value;
|
||||
var pwdMd5 = document.getElementById('pwdMd5').value;
|
||||
|
|
@ -286,12 +286,12 @@ var abp = abp || {};
|
|||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.onreadystatechange = function () {
|
||||
|
||||
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
debugger;
|
||||
// debugger;
|
||||
if (xhr.status === 200) {
|
||||
debugger;
|
||||
|
||||
// debugger;
|
||||
|
||||
var resultdata = JSON.parse(xhr.responseText);
|
||||
if (resultdata.ErrorMessage != '') {
|
||||
alert(resultdata.ErrorMessage);
|
||||
|
|
@ -303,18 +303,23 @@ var abp = abp || {};
|
|||
else {
|
||||
var responseJSON = JSON.parse(xhr.responseText);
|
||||
var result = responseJSON;
|
||||
var expireDate = new Date(Date.now() + (60*60*24 * 1000));
|
||||
var expireDate = new Date(Date.now() + (60 * 60 * 24 * 1000));
|
||||
abp.auth.setToken(result.Result.JWTStr, expireDate);
|
||||
callback();
|
||||
let selectDom = document.getElementById("roleSelect")
|
||||
selectDom.options.length = 0;
|
||||
result.Result.BasicInfo.AccountList.forEach(item => {
|
||||
selectDom.options.add(new Option(item.UserTypeShortName, item.Id));
|
||||
})
|
||||
// callback();
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
alert('Login failed !');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhr.open('POST', '/user/login', true);
|
||||
|
||||
xhr.open('POST', '/User/getUserLoginRoleList', true);
|
||||
xhr.setRequestHeader('Abp.TenantId', tenantId);
|
||||
xhr.setRequestHeader('Content-type', 'application/json');
|
||||
var parm = {
|
||||
|
|
@ -330,7 +335,63 @@ var abp = abp || {};
|
|||
//xhr.send("{" + "userName:'" + usernameOrEmailAddress + "'," + "passWord:'" + password + "'}");
|
||||
|
||||
};
|
||||
function loginUserInternalRole(tenantId, callback) {
|
||||
|
||||
var usernameOrEmailAddress = document.getElementById('roleSelect').value;
|
||||
//if (!usernameOrEmailAddress) {
|
||||
// alert('UserName Can Not Be Null');
|
||||
// return false;
|
||||
//}
|
||||
|
||||
var password = document.getElementById('password').value;
|
||||
var pwdMd5 = document.getElementById('pwdMd5').value;
|
||||
console.log(pwdMd5);
|
||||
if (!password && !pwdMd5) {
|
||||
alert('PassWord And Md5 Can Not Be Null');
|
||||
return false;
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.onreadystatechange = function () {
|
||||
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
// debugger;
|
||||
if (xhr.status === 200) {
|
||||
// debugger;
|
||||
|
||||
var resultdata = JSON.parse(xhr.responseText);
|
||||
if (resultdata.ErrorMessage != '') {
|
||||
alert(resultdata.ErrorMessage);
|
||||
return false;
|
||||
}
|
||||
if (resultdata.code == 300) {
|
||||
alert(resultdata.message);
|
||||
}
|
||||
else {
|
||||
var responseJSON = JSON.parse(xhr.responseText);
|
||||
var result = responseJSON;
|
||||
var expireDate = new Date(Date.now() + (60 * 60 * 24 * 1000));
|
||||
abp.auth.setToken(result.Result, expireDate);
|
||||
|
||||
callback();
|
||||
}
|
||||
|
||||
} else {
|
||||
alert('Login failed !');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhr.open('get', `/User/loginSelectUserRole?userRoleId=${usernameOrEmailAddress}`, true);
|
||||
xhr.setRequestHeader('Abp.TenantId', tenantId);
|
||||
xhr.setRequestHeader('Content-type', 'application/json');
|
||||
var authToken = abp.auth.getToken();
|
||||
xhr.setRequestHeader('Authorization', `Bearer ${authToken}`);
|
||||
xhr.send();
|
||||
//xhr.send("{" + "userName:'" + usernameOrEmailAddress + "'," + "passWord:'" + password + "'}");
|
||||
|
||||
};
|
||||
abp.swagger.login = function (callback) {
|
||||
//Get TenantId first
|
||||
var tenancyName = document.getElementById('tenancyName').value;
|
||||
|
|
@ -356,6 +417,31 @@ var abp = abp || {};
|
|||
loginUserInternal(null, callback); // Login for host
|
||||
}
|
||||
};
|
||||
abp.swagger.loginRole = function (callback) {
|
||||
//Get TenantId first
|
||||
var tenancyName = document.getElementById('tenancyName').value;
|
||||
|
||||
if (tenancyName) {
|
||||
var xhrTenancyName = new XMLHttpRequest();
|
||||
xhrTenancyName.onreadystatechange = function () {
|
||||
if (xhrTenancyName.readyState === XMLHttpRequest.DONE && xhrTenancyName.status === 200) {
|
||||
var responseJSON = JSON.parse(xhrTenancyName.responseText);
|
||||
var result = responseJSON.result;
|
||||
if (result.state === 1) { // Tenant exists and active.
|
||||
loginUserInternalRole(result.tenantId, callback); // Login for tenant
|
||||
} else {
|
||||
alert('There is no such tenant or tenant is not active !');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhrTenancyName.open('POST', '/api/services/app/Account/IsTenantAvailable', true);
|
||||
xhrTenancyName.setRequestHeader('Content-type', 'application/json');
|
||||
xhrTenancyName.send("{" + "tenancyName:'" + tenancyName + "'}");
|
||||
} else {
|
||||
loginUserInternalRole(null, callback); // Login for host
|
||||
}
|
||||
};
|
||||
|
||||
abp.swagger.logout = function () {
|
||||
abp.auth.clearToken();
|
||||
|
|
@ -419,9 +505,10 @@ var abp = abp || {};
|
|||
|
||||
//Inputs
|
||||
createInput(modalUxContent, 'tenancyName', 'Tenancy Name (Leave empty for Host)');
|
||||
createInput(modalUxContent, 'userName', 'Username or email address','text','cyldev');
|
||||
createInput(modalUxContent, 'userName', 'Username or email address', 'text', 'cyldev');
|
||||
createInput(modalUxContent, 'password', 'Password', 'password', '123456');
|
||||
createInput(modalUxContent, 'pwdMd5', 'PwdMd5', 'text', '');
|
||||
createSelect(modalUxContent, 'roleSelect', 'role', [])
|
||||
|
||||
//Buttons
|
||||
var authBtnWrapper = document.createElement('div');
|
||||
|
|
@ -444,9 +531,18 @@ var abp = abp || {};
|
|||
abp.swagger.login(loginCallback);
|
||||
};
|
||||
authBtnWrapper.appendChild(authorizeButton);
|
||||
|
||||
// login role
|
||||
var authorizeButton = document.createElement('button');
|
||||
authorizeButton.className = 'btn modal-btn auth authorize button';
|
||||
authorizeButton.innerText = 'LoginRole';
|
||||
authorizeButton.onclick = function () {
|
||||
abp.swagger.loginRole(loginCallback);
|
||||
};
|
||||
authBtnWrapper.appendChild(authorizeButton);
|
||||
}
|
||||
|
||||
function createInput(container, id, title, type, value="") {
|
||||
function createInput(container, id, title, type, value = "") {
|
||||
var wrapper = document.createElement('div');
|
||||
wrapper.className = 'wrapper';
|
||||
if (id == "tenancyName") {
|
||||
|
|
@ -470,6 +566,31 @@ var abp = abp || {};
|
|||
input.autocomplete = "off";
|
||||
|
||||
|
||||
section.appendChild(input);
|
||||
}
|
||||
function createSelect(container, id, title, option = []) {
|
||||
var wrapper = document.createElement('div');
|
||||
wrapper.className = 'wrapper';
|
||||
if (id == "tenancyName") {
|
||||
wrapper.style.display = 'none';
|
||||
}
|
||||
container.appendChild(wrapper);
|
||||
|
||||
var label = document.createElement('label');
|
||||
label.innerText = title;
|
||||
wrapper.appendChild(label);
|
||||
|
||||
var section = document.createElement('section');
|
||||
section.className = 'block-tablet col-10-tablet block-desktop col-10-desktop';
|
||||
wrapper.appendChild(section);
|
||||
|
||||
var input = document.createElement('select');
|
||||
input.id = id;
|
||||
input.style.width = '100%';
|
||||
option.forEach(item => {
|
||||
input.options.add(new Option(item.UserTypeShortName, item.Id));
|
||||
})
|
||||
|
||||
section.appendChild(input);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
|
||||
namespace IRaCIS.Core.Application.Auth
|
||||
{
|
||||
public class IRaCISClaims
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string FullName { get; set; } = String.Empty;
|
||||
public string Code { get; set; } = String.Empty;
|
||||
public string RealName { get; set; } = String.Empty;
|
||||
|
||||
public string UserTypeShortName { get; set; } = String.Empty;
|
||||
|
||||
public UserTypeEnum UserTypeEnum { get; set; }
|
||||
|
||||
public string PermissionStr { get; set; } = String.Empty;
|
||||
|
||||
public Guid UserTypeId { get; set; }
|
||||
|
||||
public int IsAdmin { get; }
|
||||
|
||||
public bool IsTestUser { get; set; }
|
||||
|
||||
public bool IsZhiZhun { get; set; }
|
||||
|
||||
public string Phone { get; set; } = String.Empty;
|
||||
|
||||
public static IRaCISClaims Create(UserBasicInfo user)
|
||||
{
|
||||
return new IRaCISClaims
|
||||
{
|
||||
Id = user.Id,
|
||||
FullName = user.UserName,
|
||||
RealName = user.RealName,
|
||||
UserTypeEnum = user.UserTypeEnum,
|
||||
UserTypeId = user.UserTypeId,
|
||||
IsTestUser = user.IsTestUser,
|
||||
Code = user.Code,
|
||||
PermissionStr = user.PermissionStr,
|
||||
IsZhiZhun = user.IsZhiZhun,
|
||||
UserTypeShortName = user.UserTypeShortName
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +1,39 @@
|
|||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Text;
|
||||
|
||||
namespace IRaCIS.Core.Application.Auth
|
||||
public class JwtSetting
|
||||
{
|
||||
public class JwtSetting
|
||||
/// <summary>
|
||||
/// 颁发者
|
||||
/// </summary>
|
||||
public string Issuer { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 接收者
|
||||
/// </summary>
|
||||
public string Audience { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 令牌密码
|
||||
/// </summary>
|
||||
public string SecurityKey { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 过期时间
|
||||
/// </summary>
|
||||
public int TokenExpireMinute { get; set; }
|
||||
|
||||
//public Dictionary<string, object> Claims { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 签名
|
||||
/// </summary>
|
||||
public SigningCredentials Credentials
|
||||
{
|
||||
/// <summary>
|
||||
/// 颁发者
|
||||
/// </summary>
|
||||
public string Issuer { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 接收者
|
||||
/// </summary>
|
||||
public string Audience { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 令牌密码
|
||||
/// </summary>
|
||||
public string SecurityKey { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 过期时间
|
||||
/// </summary>
|
||||
public int TokenExpireDays { get; set; }
|
||||
|
||||
//public Dictionary<string, object> Claims { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 签名
|
||||
/// </summary>
|
||||
public SigningCredentials Credentials
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityKey));
|
||||
return new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||
}
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityKey));
|
||||
return new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,9 @@ namespace IRaCIS.Core.Application.Auth
|
|||
|
||||
public interface ITokenService
|
||||
{
|
||||
string GetToken(IRaCISClaims user);
|
||||
string GetToken(UserTokenInfo user);
|
||||
|
||||
bool IsTokenExpired(string token);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -21,23 +23,24 @@ namespace IRaCIS.Core.Application.Auth
|
|||
_jwtSetting = option.Value;
|
||||
}
|
||||
|
||||
public string GetToken(IRaCISClaims user)
|
||||
public string GetToken(UserTokenInfo user)
|
||||
{
|
||||
//创建用户身份标识,可按需要添加更多信息
|
||||
var claims = new Claim[]
|
||||
{
|
||||
new Claim(Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
||||
new Claim(JwtIRaCISClaimType.Id, user.Id.ToString()),
|
||||
new Claim(JwtIRaCISClaimType.Name, user.FullName),
|
||||
new Claim(JwtIRaCISClaimType.RealName, user.RealName),
|
||||
new Claim(JwtIRaCISClaimType.Code,user.Code),
|
||||
new Claim(JwtIRaCISClaimType.IdentityUserId, user.IdentityUserId.ToString()),
|
||||
new Claim(JwtIRaCISClaimType.UserRoleId, user.UserRoleId.ToString()),
|
||||
new Claim(JwtIRaCISClaimType.UserName, user.UserName),
|
||||
new Claim(JwtIRaCISClaimType.FullName, user.FullName),
|
||||
new Claim(JwtIRaCISClaimType.UserTypeId,user.UserTypeId.ToString()),
|
||||
new Claim(JwtIRaCISClaimType.UserTypeEnum,user.UserTypeEnum.ToString()),
|
||||
new Claim(JwtIRaCISClaimType.UserTypeEnumInt,((int)user.UserTypeEnum).ToString()),
|
||||
new Claim(JwtIRaCISClaimType.UserTypeShortName,user.UserTypeShortName),
|
||||
new Claim(JwtIRaCISClaimType.PermissionStr,user.PermissionStr),
|
||||
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())
|
||||
};
|
||||
|
||||
////创建令牌
|
||||
|
|
@ -47,13 +50,27 @@ namespace IRaCIS.Core.Application.Auth
|
|||
signingCredentials: _jwtSetting.Credentials,
|
||||
claims: claims,
|
||||
notBefore: DateTime.Now,
|
||||
expires: DateTime.Now.AddDays(_jwtSetting.TokenExpireDays)
|
||||
expires: DateTime.Now.AddMinutes(_jwtSetting.TokenExpireMinute)
|
||||
);
|
||||
|
||||
string jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
|
||||
return jwtToken;
|
||||
|
||||
}
|
||||
|
||||
public bool IsTokenExpired(string token)
|
||||
{
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
try
|
||||
{
|
||||
var jwtToken = handler.ReadJwtToken(token);
|
||||
return jwtToken.ValidTo < DateTime.UtcNow;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return true; // 无效 Token 也视为已过期
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
|
||||
namespace IRaCIS.Core.Application.Auth
|
||||
{
|
||||
public class UserTokenInfo
|
||||
{
|
||||
public Guid IdentityUserId { get; set; }
|
||||
|
||||
public Guid UserRoleId { get; set; }
|
||||
|
||||
public Guid UserTypeId { get; set; }
|
||||
|
||||
public UserTypeEnum UserTypeEnum { get; set; }
|
||||
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
public string FullName { get; set; } = string.Empty;
|
||||
|
||||
public string PermissionStr { get; set; } = string.Empty;
|
||||
|
||||
public bool IsTestUser { get; set; }
|
||||
|
||||
public bool IsZhiZhun { get; set; }
|
||||
|
||||
public string UserTypeShortName { get; set; } = string.Empty;
|
||||
|
||||
public List<HospitalGroupInfo> HospitalGroupList { get; set; } = new List<HospitalGroupInfo>();
|
||||
}
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ public class EncryptionRequestMiddleware
|
|||
{
|
||||
try
|
||||
{
|
||||
var decryptedSegment = AesEncryption.Decrypt(pathSegments[i], decryptedSymmetricKey);
|
||||
var decryptedSegment = Infrastructure.Encryption.AesEncryption.Decrypt(pathSegments[i], decryptedSymmetricKey);
|
||||
pathSegments[i] = decryptedSegment;
|
||||
}
|
||||
catch
|
||||
|
|
@ -74,7 +74,7 @@ public class EncryptionRequestMiddleware
|
|||
foreach (var param in queryParams)
|
||||
{
|
||||
var encryptedValue = param.Value;
|
||||
var decryptedValue = AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
|
||||
var decryptedValue = Infrastructure.Encryption.AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
|
||||
decryptedQueryParams[param.Key] = decryptedValue;
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ public class EncryptionRequestMiddleware
|
|||
foreach (var property in encryptedJson.Properties())
|
||||
{
|
||||
var encryptedValue = property.Value.ToString();
|
||||
var decryptedValue = AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
|
||||
var decryptedValue = Infrastructure.Encryption.AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
|
||||
decryptedJson[property.Name] = decryptedValue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public class LimitUserRequestAuthorization(
|
|||
|
||||
|
||||
//2、在这里取缓存 进行比较 看是否有其他人进行了登陆,如果其他人登陆了,就把之前用户挤掉
|
||||
var cacheUserToken = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserToken(_userInfo.Id));
|
||||
var cacheUserToken = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserToken(_userInfo.IdentityUserId));
|
||||
|
||||
|
||||
|
||||
|
|
@ -58,17 +58,17 @@ public class LimitUserRequestAuthorization(
|
|||
cacheUserToken = _userInfo.UserToken;
|
||||
|
||||
//设置当前用户最新Token
|
||||
await _fusionCache.SetAsync(CacheKeys.UserToken(_userInfo.Id), _userInfo.UserToken, TimeSpan.FromDays(7));
|
||||
await _fusionCache.SetAsync(CacheKeys.UserToken(_userInfo.IdentityUserId), _userInfo.UserToken, TimeSpan.FromDays(7));
|
||||
|
||||
//重启应用程序,所有人续期,不一下子踢出所有人
|
||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.Id), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
|
||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.IdentityUserId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
|
||||
|
||||
}
|
||||
//是同一个人
|
||||
else if (cacheUserToken == _userInfo.UserToken)
|
||||
{
|
||||
|
||||
var cacheTime = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserAutoLoginOut(_userInfo.Id));
|
||||
var cacheTime = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserAutoLoginOut(_userInfo.IdentityUserId));
|
||||
|
||||
//过期了 需要自动退出
|
||||
if (string.IsNullOrEmpty(cacheTime))
|
||||
|
|
@ -80,7 +80,7 @@ public class LimitUserRequestAuthorization(
|
|||
}
|
||||
else
|
||||
{
|
||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.Id), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
|
||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.IdentityUserId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -93,6 +93,21 @@ public class LimitUserRequestAuthorization(
|
|||
|
||||
}
|
||||
|
||||
//用户或者角色禁用,那么操作的人退出
|
||||
|
||||
var isDisable = await _fusionCache.GetOrDefaultAsync<bool>(CacheKeys.UserDisable(_userInfo.IdentityUserId), false);
|
||||
|
||||
var isRoleDisable = await _fusionCache.GetOrDefaultAsync<bool>(CacheKeys.UserRoleDisable(_userInfo.UserRoleId), false);
|
||||
|
||||
if (isDisable == true || isRoleDisable == true)
|
||||
{
|
||||
context.HttpContext.Response.ContentType = "application/json";
|
||||
context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
// 用户或者角色被禁用。
|
||||
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["LimitUser_AccountOrRoleDisable"], ApiResponseCodeEnum.AutoLoginOut));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
using IRaCIS.Core.Application.BusinessFilter;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.BusinessFilter;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using IRaCIS.Core.Infrastructure.Encryption;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
|
@ -13,7 +17,10 @@ using static IRaCIS.Core.Domain.Share.StaticData;
|
|||
|
||||
namespace IRaCIS.Core.Application.Filter;
|
||||
|
||||
public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _userInfo, IRepository<Trial> _trialRepository) : IAsyncActionFilter
|
||||
public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _userInfo, IRepository<Trial> _trialRepository,
|
||||
IOptionsMonitor<ServiceVerifyConfigOption> _basicSystemConfigConfig,
|
||||
IRepository<HIRHospital> _hirHospitalRepository,
|
||||
IStringLocalizer _localizer) : IAsyncActionFilter
|
||||
{
|
||||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||
{
|
||||
|
|
@ -113,9 +120,9 @@ public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _
|
|||
|
||||
trialIdStr = matchResult.Value;
|
||||
|
||||
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||
var trialInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(trialStatusStr))
|
||||
if (string.IsNullOrWhiteSpace(trialInfo?.TrialStatusStr))
|
||||
{
|
||||
|
||||
//数据库 检查该项目Id不对
|
||||
|
|
@ -145,22 +152,83 @@ public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _
|
|||
//通过path 或者body 找到trialId 了
|
||||
if (!string.IsNullOrWhiteSpace(trialIdStr))
|
||||
{
|
||||
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||
var trialInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||
|
||||
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方,比如项目配置(有的在多种状态(初始化,ongoing)都可以操作,有的仅仅在Initializing)还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
|
||||
if (trialStatusStr == StaticData.TrialState.TrialOngoing || optActions.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
|
||||
var hospitalInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Hospital, _ => CacheHelper.GetHospitalCode(_hirHospitalRepository), TimeSpan.FromDays(7));
|
||||
|
||||
var trialStatusStr = string.Empty;
|
||||
|
||||
if (trialInfo != null)
|
||||
{
|
||||
trialStatusStr = trialInfo.TrialStatusStr;
|
||||
|
||||
await next();
|
||||
var activationCode = trialInfo.AuthorizationEncrypt;
|
||||
|
||||
if (string.IsNullOrEmpty(activationCode))
|
||||
{
|
||||
//context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["项目未进行授权之前,不能进行操作"]));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var decodedText = string.Empty;
|
||||
try
|
||||
{
|
||||
//解析加密信息
|
||||
decodedText = AesEncryption.Decrypt(activationCode, _basicSystemConfigConfig.CurrentValue.AESKey, "Trial_AuthorizationEncrypt");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//该授权码与该项目不匹配(无法解密)
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialGlobalLimit_AuthorizationCodeError"]));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var hospitalCode = hospitalInfo.HospitalCode;
|
||||
var authInfo = JsonConvert.DeserializeObject<TrialAuthorizationInfo>(decodedText);
|
||||
|
||||
if (authInfo != null)
|
||||
{
|
||||
if (authInfo.TrialCode != trialInfo.TrialCode || authInfo.CreateUserId != trialInfo.CreateUserId || authInfo.TrialId != trialInfo.TrialId
|
||||
|| authInfo.HospitalCode != hospitalCode || trialInfo.CriterionTypeList.Except(authInfo.CriterionTypeList).Count() != 0)
|
||||
{
|
||||
// 您的操作被禁止,系统检测到该项目授权码与该项目授权配置信息不一致,请还原项目授权配置信息!
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialGlobalLimit_AuthorizationCodeInfoError"]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (DateTime.Now > authInfo.AuthorizationDeadLineDate.Value.AddDays(15))
|
||||
{
|
||||
//当前时间已经超过项目授权截止时间半个月,请重新获取项目授权后再进行操作!
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialGlobalLimit_AuthorizationCodeAfterDeadLine15Days"]));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["该授权码与该项目不匹配"]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方,比如项目配置(有的在多种状态(初始化,ongoing)都可以操作,有的仅仅在Initializing)还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
|
||||
if (trialStatusStr == StaticData.TrialState.TrialOngoing || optActions.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
|
||||
{
|
||||
|
||||
await next();
|
||||
|
||||
}
|
||||
// 项目停止、或者完成 不允许操作
|
||||
else
|
||||
{
|
||||
//---本次请求被配置规则拦截:项目状态处于进行中时,才允许操作,若此处逻辑有误,请联系开发人员修改
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(I18n.T("TrialResource_InterceptedProjectStatusRule")));
|
||||
|
||||
}
|
||||
}
|
||||
// 项目停止、或者完成 不允许操作
|
||||
else
|
||||
{
|
||||
//---本次请求被配置规则拦截:项目状态处于进行中时,才允许操作,若此处逻辑有误,请联系开发人员修改
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(I18n.T("TrialResource_InterceptedProjectStatusRule")));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
//添加项目 签名系统文档的时候 不做拦截 但是更新项目 签名项目文档的时候需要拦截
|
||||
|
|
|
|||
|
|
@ -1,196 +0,0 @@
|
|||
using IRaCIS.Core.Application.Helper;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using System.Text.RegularExpressions;
|
||||
using ZiggyCreatures.Caching.Fusion;
|
||||
using static IRaCIS.Core.Domain.Share.StaticData;
|
||||
|
||||
namespace IRaCIS.Core.Application.Filter;
|
||||
|
||||
/// <summary>
|
||||
/// 主要为了 处理项目结束 锁库,不允许操作
|
||||
/// </summary>
|
||||
public class TrialResourceFilter : Attribute, IAsyncResourceFilter
|
||||
{
|
||||
private readonly IUserInfo _userInfo;
|
||||
private readonly IFusionCache _fusionCache;
|
||||
public IStringLocalizer _localizer;
|
||||
private readonly IRepository<Trial> _trialRepository;
|
||||
private readonly List<string> _trialOptList = new List<string>();
|
||||
|
||||
|
||||
public TrialResourceFilter(IFusionCache fusionCache, IRepository<Trial> trialRepository, IStringLocalizer localizer, IUserInfo userInfo, string trialOpt = null, string trialOpt2 = null, string trialOpt3 = null)
|
||||
{
|
||||
_fusionCache = fusionCache;
|
||||
_userInfo = userInfo;
|
||||
_localizer = localizer;
|
||||
_trialRepository = trialRepository;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(trialOpt)) _trialOptList.Add(trialOpt.Trim());
|
||||
if (!string.IsNullOrWhiteSpace(trialOpt2)) _trialOptList.Add(trialOpt2.Trim());
|
||||
if (!string.IsNullOrWhiteSpace(trialOpt3)) _trialOptList.Add(trialOpt3.Trim());
|
||||
|
||||
}
|
||||
|
||||
//优先选择异步的方法
|
||||
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
|
||||
{
|
||||
// var typeFilter = context.ActionDescriptor.EndpointMetadata.Where(t => t.GetType() == typeof(TypeFilterAttribute)).Select(t => (TypeFilterAttribute)t).ToList().FirstOrDefault();
|
||||
//var _trialOptList= typeFilter.Arguments.Select(t => t.ToString()).ToList();
|
||||
|
||||
// 获取当前请求的 Host 信息
|
||||
var requestHost = context.HttpContext.Request.Host;
|
||||
|
||||
// 检查请求是否来自 localhost:6100
|
||||
if (requestHost.Host == "localhost" && (requestHost.Port == 6100|| requestHost.Port==3305))
|
||||
{
|
||||
await next.Invoke();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#region 处理新的用户类型,不能操作项目相关接口
|
||||
|
||||
// 后期列举出具体的类型,其他任何用户类型,都不允许操作
|
||||
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA && _userInfo.RequestUrl.ToLower() != "TrialDocument/userConfirm".ToLower())
|
||||
{
|
||||
//---对不起,您的账户没有操作权限。
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_NoAccessPermission"]));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
//TrialId 传递的途径多种,可能在path 可能在body 可能在数组中,也可能在对象中,可能就在url
|
||||
var trialIdStr = string.Empty;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(context.HttpContext.Request.Query["trialId"]))
|
||||
{
|
||||
trialIdStr = context.HttpContext.Request.Query["trialId"];
|
||||
}
|
||||
|
||||
//先尝试从path中取TrialId
|
||||
else if (context.RouteData.Values.Keys.Any(t => t.Contains("trialId")))
|
||||
{
|
||||
var index = context.RouteData.Values.Keys.ToList().IndexOf("trialId");
|
||||
trialIdStr = context.RouteData.Values.Values.ToList()[index] as string;
|
||||
}
|
||||
else if (context.HttpContext.Request.Headers["Referer"].ToString().Contains("trialId"))
|
||||
{
|
||||
var headerStr = context.HttpContext.Request.Headers["Referer"].ToString();
|
||||
|
||||
var trialIdIndex = headerStr.IndexOf("trialId");
|
||||
|
||||
|
||||
var matchResult = Regex.Match(headerStr.Substring(trialIdIndex), @"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}");
|
||||
|
||||
if (matchResult.Success)
|
||||
{
|
||||
trialIdStr = matchResult.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
//---正则取请求Refer 中trialId 失败,请联系开发人员核查
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_ReferTrialIdFailed"]));
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
#region body 中取数据
|
||||
|
||||
//设置可以多次读
|
||||
context.HttpContext.Request.EnableBuffering();
|
||||
var reader = new StreamReader(context.HttpContext.Request.Body);
|
||||
var contentFromBody = await reader.ReadToEndAsync();
|
||||
//读取后,流的位置还原
|
||||
context.HttpContext.Request.Body.Seek(0, SeekOrigin.Begin);
|
||||
//context.HttpContext.Request.Body.Position = 0;
|
||||
|
||||
//找到参数位置在字符串中的索引
|
||||
var trialIdIndex = contentFromBody.IndexOf("\"TrialId\"", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (trialIdIndex > -1)
|
||||
{
|
||||
// (?<="trialId" *: *").*?(?=",)
|
||||
|
||||
//使用正则 [0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}
|
||||
|
||||
var matchResult = Regex.Match(contentFromBody.Substring(trialIdIndex), @"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}");
|
||||
|
||||
if (matchResult.Success)
|
||||
{
|
||||
//有可能匹配错误 "trialId":"","documentId":"b8180000-3e2c-0016-9fe0-08da33f96236" 从缓存里面验证下
|
||||
|
||||
trialIdStr = matchResult.Value;
|
||||
|
||||
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(trialStatusStr))
|
||||
{
|
||||
|
||||
//数据库 检查该项目Id不对
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_ReferTrialIdFailed"]));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//---正则取请求Refer 中trialId 失败,请联系开发人员核查
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_ReferTrialIdFailed"]));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//使用字符串取 如果是swagger 可能有时取的不对 因为空格的原因
|
||||
//trialIdStr = contentFromBody.Substring(trialIdIndex + "TrialId".Length + 4, 3
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
//通过path 或者body 找到trialId 了
|
||||
if (!string.IsNullOrWhiteSpace(trialIdStr))
|
||||
{
|
||||
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||
|
||||
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方,比如项目配置(有的在多种状态(初始化,ongoing)都可以操作,有的仅仅在Initializing)还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
|
||||
if (trialStatusStr == StaticData.TrialState.TrialOngoing || _trialOptList.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
|
||||
{
|
||||
|
||||
await next.Invoke();
|
||||
|
||||
}
|
||||
// 项目停止、或者完成 不允许操作
|
||||
else
|
||||
{
|
||||
//---本次请求被配置规则拦截:项目状态处于进行中时,才允许操作,若此处逻辑有误,请联系开发人员修改
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_InterceptedProjectStatusRule"]));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
//添加项目 签名系统文档的时候 不做拦截 但是更新项目 签名项目文档的时候需要拦截
|
||||
else if (_trialOptList.Any(t => t == TrialOpt.AddOrUpdateTrial || t == TrialOpt.SignSystemDocNoTrialId))
|
||||
{
|
||||
await next.Invoke();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
//如果项目相关接口没有传递trialId 会来到这里,提醒,以便修改
|
||||
|
||||
//---该接口参数中,没有传递项目编号,请核对。
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_MissingProjectNumber"]));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service.BusinessFilter;
|
||||
|
||||
|
|
|
|||
|
|
@ -41,19 +41,19 @@ public class LimitUserRequestAuthorizationEndpointFilter(
|
|||
}
|
||||
|
||||
// 获取缓存中的用户 token
|
||||
var cacheUserToken = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserToken(_userInfo.Id));
|
||||
var cacheUserToken = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserToken(_userInfo.IdentityUserId));
|
||||
|
||||
// 缓存中没有取到 token
|
||||
if (string.IsNullOrWhiteSpace(cacheUserToken))
|
||||
{
|
||||
// 设置当前用户最新 token
|
||||
await _fusionCache.SetAsync(CacheKeys.UserToken(_userInfo.Id), _userInfo.UserToken, TimeSpan.FromDays(7));
|
||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.Id), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
|
||||
await _fusionCache.SetAsync(CacheKeys.UserToken(_userInfo.IdentityUserId), _userInfo.UserToken, TimeSpan.FromDays(7));
|
||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.IdentityUserId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
|
||||
}
|
||||
// 如果是同一个用户
|
||||
else if (cacheUserToken == _userInfo.UserToken)
|
||||
{
|
||||
var cacheTime = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserAutoLoginOut(_userInfo.Id));
|
||||
var cacheTime = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserAutoLoginOut(_userInfo.IdentityUserId));
|
||||
|
||||
// 如果过期,自动登出
|
||||
if (string.IsNullOrEmpty(cacheTime))
|
||||
|
|
@ -63,7 +63,7 @@ public class LimitUserRequestAuthorizationEndpointFilter(
|
|||
}
|
||||
else
|
||||
{
|
||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.Id), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
|
||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.IdentityUserId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
using IRaCIS.Core.Application.Helper;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using IRaCIS.Core.Infrastructure.Encryption;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
|
@ -24,7 +28,10 @@ public class TrialGlobalLimitAttribute : Attribute
|
|||
|
||||
|
||||
|
||||
public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo _userInfo, IRepository<Trial> _trialRepository) : IEndpointFilter
|
||||
public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo _userInfo, IRepository<Trial> _trialRepository,
|
||||
IOptionsMonitor<ServiceVerifyConfigOption> _basicSystemConfigConfig,
|
||||
IRepository<HIRHospital> _hirHospitalRepository,
|
||||
IStringLocalizer _localizer) : IEndpointFilter
|
||||
|
||||
{
|
||||
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
|
||||
|
|
@ -121,9 +128,9 @@ public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo
|
|||
|
||||
trialIdStr = matchResult.Value;
|
||||
|
||||
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||
var trialInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(trialStatusStr))
|
||||
if (string.IsNullOrWhiteSpace(trialInfo?.TrialStatusStr))
|
||||
{
|
||||
|
||||
//数据库 检查该项目Id不对
|
||||
|
|
@ -151,22 +158,81 @@ public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo
|
|||
//通过path 或者body 找到trialId 了
|
||||
if (!string.IsNullOrWhiteSpace(trialIdStr))
|
||||
{
|
||||
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||
var trialInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
||||
|
||||
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方,比如项目配置(有的在多种状态(初始化,ongoing)都可以操作,有的仅仅在Initializing)还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
|
||||
if (trialStatusStr == StaticData.TrialState.TrialOngoing || optActions.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
|
||||
var hospitalInfo = await _fusionCache.GetOrSetAsync(CacheKeys.Hospital, _ => CacheHelper.GetHospitalCode(_hirHospitalRepository), TimeSpan.FromDays(7));
|
||||
|
||||
var trialStatusStr = string.Empty;
|
||||
|
||||
|
||||
if (trialInfo != null)
|
||||
{
|
||||
trialStatusStr = trialInfo.TrialStatusStr;
|
||||
|
||||
return await next(context);
|
||||
var activationCode = trialInfo.AuthorizationEncrypt;
|
||||
|
||||
if (string.IsNullOrEmpty(activationCode))
|
||||
{
|
||||
//context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["项目未进行授权之前,不能进行操作"]));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var decodedText = string.Empty;
|
||||
try
|
||||
{
|
||||
//解析加密信息
|
||||
decodedText = AesEncryption.Decrypt(activationCode, _basicSystemConfigConfig.CurrentValue.AESKey, "Trial_AuthorizationEncrypt");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
return Results.Json(ResponseOutput.NotOk(_localizer["该授权码与该项目不匹配"]));
|
||||
}
|
||||
|
||||
|
||||
var hospitalCode = hospitalInfo.HospitalCode;
|
||||
var authInfo = JsonConvert.DeserializeObject<TrialAuthorizationInfo>(decodedText);
|
||||
|
||||
if (authInfo != null)
|
||||
{
|
||||
if (authInfo.TrialCode != trialInfo.TrialCode || authInfo.CreateUserId != trialInfo.CreateUserId || authInfo.TrialId != trialInfo.TrialId
|
||||
|| authInfo.HospitalCode != hospitalCode || trialInfo.CriterionTypeList.Except(authInfo.CriterionTypeList).Count() != 0)
|
||||
{
|
||||
return Results.Json(ResponseOutput.NotOk(_localizer["您的操作被禁止,系统检测到该项目授权码与该项目授权配置信息不一致,请还原项目授权配置信息!"]));
|
||||
}
|
||||
|
||||
if (DateTime.Now > authInfo.AuthorizationDeadLineDate.Value.AddDays(15))
|
||||
{
|
||||
return Results.Json(ResponseOutput.NotOk(_localizer["当前时间已经超过项目授权截止时间半个月,请重新获取项目授权后再进行操作!"]));
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["该授权码与该项目不匹配"]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方,比如项目配置(有的在多种状态(初始化,ongoing)都可以操作,有的仅仅在Initializing)还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
|
||||
if (trialStatusStr == StaticData.TrialState.TrialOngoing || optActions.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
|
||||
{
|
||||
|
||||
return await next(context);
|
||||
|
||||
}
|
||||
// 项目停止、或者完成 不允许操作
|
||||
else
|
||||
{
|
||||
//---本次请求被配置规则拦截:项目状态处于进行中时,才允许操作,若此处逻辑有误,请联系开发人员修改
|
||||
return Results.Json(ResponseOutput.NotOk(I18n.T("TrialResource_InterceptedProjectStatusRule")));
|
||||
|
||||
}
|
||||
}
|
||||
// 项目停止、或者完成 不允许操作
|
||||
else
|
||||
{
|
||||
//---本次请求被配置规则拦截:项目状态处于进行中时,才允许操作,若此处逻辑有误,请联系开发人员修改
|
||||
return Results.Json(ResponseOutput.NotOk(I18n.T("TrialResource_InterceptedProjectStatusRule")));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
//添加项目 签名系统文档的时候 不做拦截 但是更新项目 签名项目文档的时候需要拦截
|
||||
|
|
|
|||
|
|
@ -36,6 +36,15 @@ public class ServiceVerifyConfigOption
|
|||
|
||||
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
|
||||
|
|
@ -51,6 +60,8 @@ public class SystemEmailSendConfig
|
|||
|
||||
public string SiteUrl { get; set; } = string.Empty;
|
||||
|
||||
public string SystemShortName { get; set; } = string.Empty;
|
||||
|
||||
public string OrganizationName { get; set; } = string.Empty;
|
||||
public string OrganizationNameCN { get; set; } = string.Empty;
|
||||
|
||||
|
|
@ -66,11 +77,14 @@ public class SystemEmailSendConfig
|
|||
|
||||
public bool IsOpenErrorNoticeEmail { get; set; }
|
||||
|
||||
public List<string> ErrorNoticeEmailList { get; set; } =new List<string>();
|
||||
public string EmailRegexStr { get; set; }
|
||||
|
||||
public List<string> ErrorNoticeEmailList { get; set; } = new List<string>();
|
||||
}
|
||||
|
||||
public class SystemEmailSendConfigView
|
||||
{
|
||||
public string SystemShortName { get; set; } = string.Empty;
|
||||
public string CompanyName { get; set; } = string.Empty;
|
||||
|
||||
public string CompanyNameCN { get; set; } = string.Empty;
|
||||
|
|
@ -78,6 +92,10 @@ public class SystemEmailSendConfigView
|
|||
public string CompanyShortName { get; set; } = string.Empty;
|
||||
|
||||
public string CompanyShortNameCN { get; set; } = string.Empty;
|
||||
|
||||
public string EmailRegexStr { get; set; }
|
||||
|
||||
public bool OpenImageShare { get; set; }
|
||||
}
|
||||
|
||||
public class SystemPacsConfig
|
||||
|
|
@ -140,7 +158,7 @@ public static class AppSettings
|
|||
case nameof(Doctor):
|
||||
return IRaCISBasicConfig.DoctorCodePrefix + codeInt.ToString("D4");
|
||||
|
||||
case nameof(User):
|
||||
case nameof(IdentityUser):
|
||||
return IRaCISBasicConfig.UserCodePrefix + codeInt.ToString("D4");
|
||||
|
||||
case nameof(QCChallenge):
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@ global using Microsoft.Extensions.Localization;
|
|||
global using AutoMapper;
|
||||
global using IRaCIS.Core.Domain.Share;
|
||||
global using IRaCIS.Core.Application.BusinessFilter;
|
||||
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
|
||||
|
|
@ -27,6 +29,11 @@ public static class CacheKeys
|
|||
//超时没请求接口自动退出
|
||||
public static string UserAutoLoginOut(Guid userId) => $"UserAutoLoginOut:{userId}";
|
||||
|
||||
|
||||
public static string UserDisable(Guid userId) => $"UserDisable:{userId}";
|
||||
|
||||
public static string UserRoleDisable(Guid userRoleId) => $"UserRoleDisable:{userRoleId}";
|
||||
|
||||
/// <summary>
|
||||
/// 用户登录错误 限制登录
|
||||
/// </summary>
|
||||
|
|
@ -56,13 +63,20 @@ public static class CacheKeys
|
|||
/// <returns></returns>
|
||||
public static string StartRestTime(Guid userId) => $"{userId}StartRestTime";
|
||||
|
||||
|
||||
|
||||
public static string CmoveStudyId(string studyIdStr) => $"CmoveStudyId:{studyIdStr}";
|
||||
|
||||
public static string Hospital => $"Hospital";
|
||||
|
||||
}
|
||||
|
||||
public static class CacheHelper
|
||||
{
|
||||
public static async Task<string?> GetTrialStatusAsync(Guid trialId, IRepository<Trial> _trialRepository)
|
||||
public static async Task<TrialCacheInfo> GetTrialStatusAsync(Guid trialId, IRepository<Trial> _trialRepository)
|
||||
{
|
||||
var statusStr = await _trialRepository.Where(t => t.Id == trialId, ignoreQueryFilters: true).Select(t => t.TrialStatusStr).FirstOrDefaultAsync();
|
||||
var statusStr = await _trialRepository.Where(t => t.Id == trialId, ignoreQueryFilters: true).Select(t => new TrialCacheInfo { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr, CriterionTypes = t.CriterionTypes, AuthorizationEncrypt = t.AuthorizationEncrypt, AuthorizationDate = t.AuthorizationDate, CreateUserId = t.CreateUserId, TrialCode = t.TrialCode })
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
return statusStr;
|
||||
}
|
||||
|
|
@ -73,4 +87,10 @@ public static class CacheHelper
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -64,7 +64,7 @@ public static class ExcelExportHelper
|
|||
foreach (var key in dic.Keys)
|
||||
{
|
||||
//是数组 那么找到对应的属性 进行翻译
|
||||
if (dic[key].GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>)))
|
||||
if (dic[key] != null && dic[key].GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>)))
|
||||
{
|
||||
|
||||
var newObjList = new List<object>();
|
||||
|
|
@ -74,14 +74,15 @@ public static class ExcelExportHelper
|
|||
{
|
||||
var itemDic = item.ConvertToDictionary();
|
||||
|
||||
//处理集合里面时间类型,根据当前语言将时间转变为字符串
|
||||
foreach (var itemValuePair in itemDic)
|
||||
{
|
||||
if (DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result))
|
||||
{
|
||||
itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result);
|
||||
}
|
||||
}
|
||||
////处理集合里面时间类型,根据当前语言将时间转变为字符串
|
||||
//foreach (var itemValuePair in itemDic)
|
||||
//{
|
||||
// // 临床数据 1,1 会变成2024-01-01
|
||||
// if (itemValuePair.Value?.ToString().Length > 8 && DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result))
|
||||
// {
|
||||
// itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result);
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
foreach (var needTranslateProperty in needTranslatePropertyList)
|
||||
|
|
@ -165,7 +166,7 @@ public static class ExcelExportHelper
|
|||
}
|
||||
|
||||
//中文替换项目术语
|
||||
if (isEn_US == false && data.TrialObjectNameList.Count > 0)
|
||||
if (data.TrialObjectNameList?.Count > 0)
|
||||
{
|
||||
var replaceObjectList = data.TrialObjectNameList;
|
||||
|
||||
|
|
@ -176,24 +177,30 @@ public static class ExcelExportHelper
|
|||
for (int rowIndex = 0; rowIndex < rowCount; rowIndex++)
|
||||
{
|
||||
var row = sheet.GetRow(rowIndex);
|
||||
var colums = row.LastCellNum;
|
||||
|
||||
for (int colIndex = 0; colIndex < colums; colIndex++)
|
||||
if (row != null)
|
||||
{
|
||||
var cell = row.GetCell(colIndex);
|
||||
|
||||
// 只处理字符串类型的单元格
|
||||
if (cell != null)
|
||||
var colums = row.LastCellNum;
|
||||
|
||||
for (int colIndex = 0; colIndex < colums; colIndex++)
|
||||
{
|
||||
var cellValue = cell.StringCellValue;
|
||||
var cell = row.GetCell(colIndex);
|
||||
|
||||
var find = replaceObjectList.FirstOrDefault(t => t.Name == cellValue);
|
||||
if (find != null)
|
||||
// 只处理字符串类型的单元格
|
||||
if (cell != null)
|
||||
{
|
||||
cell.SetCellValue(find.TrialName);
|
||||
var cellValue = cell.StringCellValue;
|
||||
|
||||
var find = replaceObjectList.FirstOrDefault(t => t.Name == cellValue);
|
||||
if (find != null)
|
||||
{
|
||||
cell.SetCellValue(find.TrialName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -236,6 +243,7 @@ public static class ExcelExportHelper
|
|||
|
||||
}
|
||||
|
||||
|
||||
public class DynamicColumnConfig
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -248,13 +256,19 @@ public static class ExcelExportHelper
|
|||
/// </summary>
|
||||
public int AutoColumnTitleRowIndex { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 模板列最后的索引
|
||||
/// </summary>
|
||||
public int TempalteLastColumnIndex { get; set; }
|
||||
|
||||
public bool IsCDISCExport { get; set; } = false;
|
||||
|
||||
//public List<string> CDISCList { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 动态的列名
|
||||
/// 动态的列名 如果Id 重复,那么就按照名称填充,否则就按照Id 填充列数据
|
||||
/// </summary>
|
||||
public List<string> ColumnNameList { get; set; } = new List<string>();
|
||||
public List<ColumItem> ColumnIdNameList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 动态翻译的字典名
|
||||
|
|
@ -281,7 +295,31 @@ public static class ExcelExportHelper
|
|||
/// </summary>
|
||||
public string DynamicItemTitleName { get; set; }
|
||||
|
||||
public string DynamicItemTitleId { get; set; }
|
||||
|
||||
public List<int> RemoveColunmIndexList { get; set; } = new List<int>();
|
||||
|
||||
public class ColumItem
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public string CDISCCode { get; set; }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is not ColumItem other) return false;
|
||||
return Id == other.Id && Name == other.Name;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Id, Name);
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> ColumnIdList => ColumnIdNameList == null ? new List<string>() : ColumnIdNameList.Select(t => t.Id.ToString()).ToList();
|
||||
public List<string> ColumnNameList => ColumnIdNameList == null ? new List<string>() : ColumnIdNameList.Select(t => t.Name).ToList();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -316,7 +354,7 @@ public static class ExcelExportHelper
|
|||
foreach (var key in dic.Keys)
|
||||
{
|
||||
//是数组 那么找到对应的属性 进行翻译
|
||||
if (dic[key].GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>)))
|
||||
if (dic[key] != null && dic[key].GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>)))
|
||||
//if (dic[key].GetType().IsAssignableFrom(typeof(JArray)))
|
||||
{
|
||||
|
||||
|
|
@ -328,14 +366,14 @@ public static class ExcelExportHelper
|
|||
//var itemDic = JsonConvert.DeserializeObject<IDictionary<string, object>>(item.ToJsonNotIgnoreNull());
|
||||
var itemDic = item.ConvertToDictionary();
|
||||
|
||||
//处理集合里面时间类型,根据当前语言将时间转变为字符串
|
||||
foreach (var itemValuePair in itemDic)
|
||||
{
|
||||
if (DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result))
|
||||
{
|
||||
itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result);
|
||||
}
|
||||
}
|
||||
////处理集合里面时间类型,根据当前语言将时间转变为字符串
|
||||
//foreach (var itemValuePair in itemDic)
|
||||
//{
|
||||
// if (itemValuePair.Value?.ToString().Length > 8 && DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result))
|
||||
// {
|
||||
// itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result);
|
||||
// }
|
||||
//}
|
||||
|
||||
foreach (var needTranslateProperty in needTranslatePropertyList)
|
||||
{
|
||||
|
|
@ -414,8 +452,8 @@ public static class ExcelExportHelper
|
|||
workbook.RemoveSheetAt(1);
|
||||
}
|
||||
|
||||
//中文替换项目术语
|
||||
if (isEn_US == false && data.TrialObjectNameList.Count > 0)
|
||||
#region 中文替换项目术语
|
||||
if (data.TrialObjectNameList?.Count > 0)
|
||||
{
|
||||
var replaceObjectList = data.TrialObjectNameList;
|
||||
|
||||
|
|
@ -426,41 +464,402 @@ public static class ExcelExportHelper
|
|||
for (int rowIndex = 0; rowIndex < rowCount; rowIndex++)
|
||||
{
|
||||
var row = sheet.GetRow(rowIndex);
|
||||
var colums = row.LastCellNum;
|
||||
|
||||
for (int colIndex = 0; colIndex < colums; colIndex++)
|
||||
if (row != null)
|
||||
{
|
||||
var cell = row.GetCell(colIndex);
|
||||
|
||||
// 只处理字符串类型的单元格
|
||||
if (cell != null)
|
||||
var colums = row.LastCellNum;
|
||||
|
||||
for (int colIndex = 0; colIndex < colums; colIndex++)
|
||||
{
|
||||
var cellValue = cell.StringCellValue;
|
||||
var cell = row.GetCell(colIndex);
|
||||
|
||||
var find = replaceObjectList.FirstOrDefault(t => t.Name == cellValue);
|
||||
if (find != null)
|
||||
// 只处理字符串类型的单元格
|
||||
if (cell != null)
|
||||
{
|
||||
cell.SetCellValue(find.TrialName);
|
||||
var cellValue = cell.StringCellValue;
|
||||
|
||||
var find = replaceObjectList.FirstOrDefault(t => t.Name == cellValue);
|
||||
if (find != null)
|
||||
{
|
||||
cell.SetCellValue(find.TrialName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
if (dynamicColumnConfig != null)
|
||||
{
|
||||
//var isCdics = dynamicColumnConfig.CDISCList.Count > 0;
|
||||
|
||||
var isCdics = dynamicColumnConfig.IsCDISCExport;
|
||||
|
||||
var sheet = workbook.GetSheetAt(0);
|
||||
|
||||
var cdicsRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex - 1);
|
||||
var titelRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex);
|
||||
var templateRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex + 1);
|
||||
|
||||
//动态移除列的数量
|
||||
var dynamicRemoveColunmCount = dynamicColumnConfig.RemoveColunmIndexList.Count();
|
||||
|
||||
//在动态列开始前移除的数量
|
||||
var beforeDynamicRemoveCount = dynamicColumnConfig.RemoveColunmIndexList.Where(t => t < dynamicColumnConfig.AutoColumnStartIndex).Count();
|
||||
|
||||
//动态添加列的数量
|
||||
var needAddCount = dynamicColumnConfig.ColumnNameList.Count;
|
||||
var needAddCount = dynamicColumnConfig.ColumnIdNameList.Count;
|
||||
|
||||
//原始表 最终索引
|
||||
var originTotalEndIndex = dynamicColumnConfig.TempalteLastColumnIndex;
|
||||
|
||||
//减去动态移除后原始结束索引
|
||||
var originRemoveEndIndex = originTotalEndIndex - dynamicRemoveColunmCount;
|
||||
|
||||
//最终表 动态列开始索引
|
||||
var dynamicColunmStartIndex = dynamicColumnConfig.AutoColumnStartIndex - beforeDynamicRemoveCount;
|
||||
|
||||
//最终表 动态列的终止索引
|
||||
var dynamicColunmEndIndex = dynamicColunmStartIndex + needAddCount - 1;
|
||||
|
||||
//最终表 最终索引
|
||||
var totalColunmEndIndex = originTotalEndIndex + needAddCount - dynamicRemoveColunmCount;
|
||||
|
||||
|
||||
//动态列后需要移动的数量
|
||||
var backMoveCount = totalColunmEndIndex - dynamicColunmEndIndex;
|
||||
|
||||
//删除需要动态删除的列 从大到小移除,否则索引会变
|
||||
foreach (var removeIndex in dynamicColumnConfig.RemoveColunmIndexList.OrderByDescending(t => t))
|
||||
{
|
||||
//将后面的列向前移动
|
||||
for (var i = 0; i < originTotalEndIndex - removeIndex; i++)
|
||||
{
|
||||
Console.WriteLine(titelRow.GetCell(removeIndex + i + 1).StringCellValue);
|
||||
titelRow.GetCell(removeIndex + i).SetCellValue(titelRow.GetCell(removeIndex + i + 1).StringCellValue);
|
||||
templateRow.GetCell(removeIndex + i).SetCellValue(templateRow.GetCell(removeIndex + i + 1).StringCellValue);
|
||||
|
||||
//后面的数据要清空
|
||||
titelRow.GetCell(removeIndex + i + 1).SetCellValue("");
|
||||
templateRow.GetCell(removeIndex + i + 1).SetCellValue("");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//创建新的列
|
||||
for (int i = originRemoveEndIndex; i < originRemoveEndIndex + needAddCount; i++)
|
||||
{
|
||||
|
||||
titelRow.CreateCell(i + 1);
|
||||
templateRow.CreateCell(i + 1);
|
||||
|
||||
if (isCdics)
|
||||
{
|
||||
cdicsRow.CreateCell(i + 1);
|
||||
}
|
||||
}
|
||||
//移动Title 和下面的模板标识
|
||||
|
||||
var gap = totalColunmEndIndex - originRemoveEndIndex;
|
||||
|
||||
for (int i = totalColunmEndIndex; i > dynamicColunmEndIndex; i--)
|
||||
{
|
||||
|
||||
titelRow.GetCell(i).SetCellValue(titelRow.GetCell(i - gap).StringCellValue);
|
||||
|
||||
templateRow.GetCell(i).SetCellValue(templateRow.GetCell(i - gap).StringCellValue);
|
||||
|
||||
if (isCdics)
|
||||
{
|
||||
cdicsRow.GetCell(i).SetCellValue(cdicsRow.GetCell(i - gap).StringCellValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//设置动态Tilte
|
||||
|
||||
for (int i = dynamicColunmStartIndex; i < dynamicColunmStartIndex + needAddCount; i++)
|
||||
{
|
||||
|
||||
var name = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].Name;
|
||||
|
||||
titelRow.GetCell(i).SetCellValue(name);
|
||||
templateRow.GetCell(i).SetCellValue("");
|
||||
|
||||
if (isCdics)
|
||||
{
|
||||
var cdicsCode = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].CDISCCode;
|
||||
|
||||
cdicsRow.GetCell(i).SetCellValue(cdicsCode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
using (var memoryStream2 = new MemoryStream())
|
||||
{
|
||||
workbook.Write(memoryStream2, true);
|
||||
|
||||
memoryStream2.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
templateStream = memoryStream2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MiniExcel
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
var config = new OpenXmlConfiguration()
|
||||
{
|
||||
IgnoreTemplateParameterMissing = true,
|
||||
};
|
||||
|
||||
//await MiniExcel.SaveAsByTemplateAsync("testmini.xlsx", templateStream.ToArray(), translateData);
|
||||
|
||||
await MiniExcel.SaveAsByTemplateAsync(memoryStream, templateStream.ToArray(), translateData, config);
|
||||
|
||||
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if (dynamicColumnConfig != null)
|
||||
{
|
||||
//Excel 列是按照名称填充 还是Id 填充
|
||||
var isExcelAddDataWithName = dynamicColumnConfig.ColumnIdNameList.Select(t => t.Id).Distinct().Count() == 1;
|
||||
|
||||
var dynamicTranslateDataList = await _dictionaryService.GetBasicDataSelect(dynamicColumnConfig.TranslateDicNameList.ToArray());
|
||||
|
||||
// 使用NPOI 进行二次处理
|
||||
var wb = new XSSFWorkbook(memoryStream);
|
||||
var sheet = wb.GetSheetAt(0);
|
||||
|
||||
var list = translatedDic["List"] as IList;
|
||||
|
||||
foreach (var itemResult in list)
|
||||
{
|
||||
var index = list.IndexOf(itemResult);
|
||||
|
||||
//从第四行开始处理动态列
|
||||
var row = sheet.GetRow(index + dynamicColumnConfig.AutoColumnTitleRowIndex + 1);
|
||||
|
||||
var itemDic = itemResult.ToDictionary();
|
||||
|
||||
var itemList = itemDic[dynamicColumnConfig.DynamicListName] as IList;
|
||||
|
||||
//这个数组是动态的,有的多,有的少,所以在此对比Title 一致才赋值
|
||||
foreach (var itemObj in itemList)
|
||||
{
|
||||
|
||||
var iteObjDic = itemObj.ToDictionary();
|
||||
|
||||
var itemDicName = iteObjDic.ContainsKey(dynamicColumnConfig.DynamicItemDicName) ? iteObjDic[dynamicColumnConfig.DynamicItemDicName]?.ToString() : "";
|
||||
var itemValue = iteObjDic[dynamicColumnConfig.DynamicItemValueName]?.ToString();
|
||||
|
||||
//var writeIndex = itemList.IndexOf(itemObj) + dynamicColumnConfig.AutoColumnStartIndex;
|
||||
|
||||
var writeIndex = 0;
|
||||
|
||||
if (isExcelAddDataWithName)
|
||||
{
|
||||
writeIndex = dynamicColumnConfig.ColumnNameList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleName].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
writeIndex = dynamicColumnConfig.ColumnIdList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleId].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
|
||||
}
|
||||
|
||||
|
||||
if (itemDicName.IsNotNullOrEmpty())
|
||||
{
|
||||
|
||||
var translatedItemData = dynamicTranslateDataList[itemDicName].Where(t => t.Code.ToLower() == itemValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
||||
|
||||
row.GetCell(writeIndex).SetCellValue(translatedItemData);
|
||||
}
|
||||
else
|
||||
{
|
||||
row.GetCell(writeIndex).SetCellValue(itemValue);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var memoryStream2 = new MemoryStream();
|
||||
wb.Write(memoryStream2, true);
|
||||
memoryStream2.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
memoryStream = memoryStream2;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return (memoryStream, fileName);
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂时废弃--合并到上面
|
||||
/// </summary>
|
||||
/// <param name="code"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="_commonDocumentRepository"></param>
|
||||
/// <param name="_hostEnvironment"></param>
|
||||
/// <param name="_dictionaryService"></param>
|
||||
/// <param name="translateType"></param>
|
||||
/// <param name="criterionType"></param>
|
||||
/// <param name="dynamicColumnConfig"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<(MemoryStream, string)> CDISC_DataExport_Async(string code, ExcelExportInfo data, IRepository<CommonDocument> _commonDocumentRepository, IWebHostEnvironment _hostEnvironment, IDictionaryService? _dictionaryService = null, Type? translateType = null, CriterionType? criterionType = null, DynamicColumnConfig? dynamicColumnConfig = null)
|
||||
{
|
||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||
//判断是否有字典翻译
|
||||
|
||||
object translateData = data;
|
||||
|
||||
Dictionary<string, object> translatedDic = default;
|
||||
|
||||
if (_dictionaryService != null && translateType != null)
|
||||
{
|
||||
|
||||
//一个值 对应不同的字典翻译
|
||||
var needTranslatePropertyList = translateType.GetProperties().Where(t => t.IsDefined(typeof(DictionaryTranslateAttribute), true))
|
||||
.SelectMany(c =>
|
||||
c.GetCustomAttributes(typeof(DictionaryTranslateAttribute), false).Select(f => (DictionaryTranslateAttribute?)f).Where(t => t.CriterionType == criterionType || t.CriterionType == null)
|
||||
.Select(k => new { c.Name, k.DicParentCode, k.IsTranslateDenpendOtherProperty, k.DependPropertyName, k.DependPropertyValueStr })
|
||||
).ToList();
|
||||
|
||||
|
||||
|
||||
//字典表查询出所有需要翻译的数据
|
||||
|
||||
var translateDataList = await _dictionaryService.GetBasicDataSelect(needTranslatePropertyList.Select(t => t.DicParentCode).Distinct().ToArray());
|
||||
|
||||
var dic = data.ConvertToDictionary();
|
||||
//var dic = (JsonConvert.DeserializeObject<IDictionary<string, object>>(data.ToJsonNotIgnoreNull())).IfNullThrowException();
|
||||
|
||||
foreach (var key in dic.Keys)
|
||||
{
|
||||
//是数组 那么找到对应的属性 进行翻译
|
||||
if (dic[key] != null && dic[key].GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>)))
|
||||
//if (dic[key].GetType().IsAssignableFrom(typeof(JArray)))
|
||||
{
|
||||
|
||||
var newObjList = new List<object>();
|
||||
var no = 1;
|
||||
foreach (var item in dic[key] as IList)
|
||||
//foreach (var item in dic[key] as JArray)
|
||||
{
|
||||
//var itemDic = JsonConvert.DeserializeObject<IDictionary<string, object>>(item.ToJsonNotIgnoreNull());
|
||||
var itemDic = item.ConvertToDictionary();
|
||||
|
||||
foreach (var needTranslateProperty in needTranslatePropertyList)
|
||||
{
|
||||
if (itemDic.Keys.Any(t => t == needTranslateProperty.Name))
|
||||
{
|
||||
//翻译的属性依赖其他属性
|
||||
if (needTranslateProperty.IsTranslateDenpendOtherProperty)
|
||||
{
|
||||
if (itemDic[needTranslateProperty.DependPropertyName]?.ToString().ToLower() == needTranslateProperty.DependPropertyValueStr.ToLower())
|
||||
{
|
||||
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
|
||||
|
||||
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
||||
}
|
||||
}
|
||||
//普通翻译 或者某一标准翻译
|
||||
else
|
||||
{
|
||||
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
|
||||
|
||||
|
||||
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
itemDic.Add("No", no++);
|
||||
newObjList.Add(itemDic);
|
||||
}
|
||||
|
||||
dic[key] = newObjList;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//data = dic;
|
||||
translateData = dic;
|
||||
translatedDic = dic;
|
||||
|
||||
}
|
||||
|
||||
|
||||
var (physicalPath, fileName) = await FileStoreHelper.GetCommonDocPhysicalFilePathAsync(_hostEnvironment, _commonDocumentRepository, code);
|
||||
|
||||
|
||||
//模板路径
|
||||
var tplPath = physicalPath;
|
||||
|
||||
#region 根据中英文 删除模板sheet
|
||||
|
||||
// 打开模板文件
|
||||
var templateFile = new FileStream(tplPath, FileMode.Open, FileAccess.Read);
|
||||
|
||||
// 获取文件流
|
||||
var templateStream = new MemoryStream();
|
||||
templateFile.CopyTo(templateStream);
|
||||
templateStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
var workbook = new XSSFWorkbook(templateStream);
|
||||
|
||||
int sheetCount = workbook.NumberOfSheets;
|
||||
|
||||
if (sheetCount == 2)
|
||||
{
|
||||
if (isEn_US)
|
||||
{
|
||||
workbook.RemoveSheetAt(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
workbook.RemoveSheetAt(1);
|
||||
}
|
||||
|
||||
if (dynamicColumnConfig != null)
|
||||
{
|
||||
var sheet = workbook.GetSheetAt(0);
|
||||
|
||||
|
||||
var cdicsRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex - 1);
|
||||
var titelRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex);
|
||||
var templateRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex + 1);
|
||||
|
||||
//动态移除列的数量
|
||||
var dynamicRemoveColunmCount = dynamicColumnConfig.RemoveColunmIndexList.Count();
|
||||
|
||||
//在动态列开始前移除的数量
|
||||
var beforeDynamicRemoveCount = dynamicColumnConfig.RemoveColunmIndexList.Where(t => t < dynamicColumnConfig.AutoColumnStartIndex).Count();
|
||||
|
||||
//动态添加列的数量
|
||||
var needAddCount = dynamicColumnConfig.ColumnIdNameList.Count;
|
||||
|
||||
//原始表 最终索引
|
||||
var originTotalEndIndex = dynamicColumnConfig.TempalteLastColumnIndex;
|
||||
|
|
@ -502,6 +901,7 @@ public static class ExcelExportHelper
|
|||
//创建新的列
|
||||
for (int i = originTotalEndIndex; i < originTotalEndIndex + needAddCount; i++)
|
||||
{
|
||||
cdicsRow.CreateCell(i + 1);
|
||||
titelRow.CreateCell(i + 1);
|
||||
templateRow.CreateCell(i + 1);
|
||||
}
|
||||
|
|
@ -523,8 +923,11 @@ public static class ExcelExportHelper
|
|||
|
||||
for (int i = dynamicColunmStartIndex; i < dynamicColunmStartIndex + needAddCount; i++)
|
||||
{
|
||||
var name = dynamicColumnConfig.ColumnNameList[i - dynamicColunmStartIndex];
|
||||
var name = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].Name;
|
||||
|
||||
var cdicsCode = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].CDISCCode;
|
||||
|
||||
cdicsRow.GetCell(i).SetCellValue(cdicsCode);
|
||||
titelRow.GetCell(i).SetCellValue(name);
|
||||
templateRow.GetCell(i).SetCellValue("");
|
||||
}
|
||||
|
|
@ -558,6 +961,8 @@ public static class ExcelExportHelper
|
|||
|
||||
if (dynamicColumnConfig != null)
|
||||
{
|
||||
var isExcelAddDataWithName = dynamicColumnConfig.ColumnIdNameList.Select(t => t.Id).Count() == 1;
|
||||
|
||||
var dynamicTranslateDataList = await _dictionaryService.GetBasicDataSelect(dynamicColumnConfig.TranslateDicNameList.ToArray());
|
||||
|
||||
// 使用NPOI 进行二次处理
|
||||
|
|
@ -588,7 +993,15 @@ public static class ExcelExportHelper
|
|||
|
||||
//var writeIndex = itemList.IndexOf(itemObj) + dynamicColumnConfig.AutoColumnStartIndex;
|
||||
|
||||
var writeIndex = dynamicColumnConfig.ColumnNameList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleName].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
|
||||
var writeIndex = 0;
|
||||
if (isExcelAddDataWithName)
|
||||
{
|
||||
writeIndex = dynamicColumnConfig.ColumnNameList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleName].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
writeIndex = dynamicColumnConfig.ColumnIdList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleId].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
|
||||
}
|
||||
|
||||
if (itemDicName.IsNotNullOrEmpty())
|
||||
{
|
||||
|
|
@ -624,6 +1037,7 @@ public static class ExcelExportHelper
|
|||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 导出文件模板
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ public static class FileStoreHelper
|
|||
{
|
||||
var rootPath = GetIRaCISRootPath(_hostEnvironment);
|
||||
|
||||
var physicalFilePath = Path.Combine(rootPath, relativePath.TrimStart('/'));
|
||||
var physicalFilePath = Path.Combine(rootPath, StaticData.Folder.IRaCISDataFolder, relativePath.TrimStart('/'));
|
||||
|
||||
return physicalFilePath;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue