mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-20 18:51:28 +08:00
Compare commits
1246 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
dd5691cbef | ||
![]() |
de48b32af3 | ||
![]() |
600b5042a1 | ||
![]() |
aac77029da | ||
![]() |
e50205f557 | ||
![]() |
e227411d1f | ||
![]() |
2de0ed793f | ||
![]() |
cb0276f273 | ||
![]() |
562b3f17c9 | ||
![]() |
0f78f81c1c | ||
![]() |
6594937d0a | ||
![]() |
64bc6084be | ||
![]() |
20434d5bd2 | ||
![]() |
9ecc9380e6 | ||
![]() |
a57c55080b | ||
![]() |
b8ca06c6be | ||
![]() |
5aff6461a1 | ||
![]() |
6cf53fefec | ||
![]() |
45132f3503 | ||
![]() |
f1e78a0e8a | ||
![]() |
0bf28ec275 | ||
![]() |
41f8412c97 | ||
![]() |
c535974362 | ||
![]() |
1860c5f215 | ||
![]() |
6d778b2d39 | ||
![]() |
f48b99c259 | ||
![]() |
3c73b93051 | ||
![]() |
98f3f2d519 | ||
![]() |
b76b4e8d68 | ||
![]() |
07285a7c61 | ||
![]() |
03c0dfef37 | ||
![]() |
6ef6929c35 | ||
![]() |
e3c0c173f0 | ||
![]() |
7d64e058d4 | ||
![]() |
e97ee9b64b | ||
![]() |
6a03e39eeb | ||
![]() |
525ec740b5 | ||
![]() |
b790cf5f4e | ||
![]() |
d1248811fd | ||
![]() |
022d016e8e | ||
![]() |
f73245e650 | ||
![]() |
484461fa05 | ||
![]() |
7e0b7aff2a | ||
![]() |
6c450dcb09 | ||
![]() |
227f44283f | ||
![]() |
74f6e79625 | ||
![]() |
cec43e2ce8 | ||
![]() |
7553b258bb | ||
![]() |
8bdbdc117e | ||
![]() |
0e206be296 | ||
![]() |
00b7353433 | ||
![]() |
44e7a83593 | ||
![]() |
dd68d555d4 | ||
![]() |
0456296103 | ||
![]() |
a1b66277ff | ||
![]() |
50758b79bc | ||
![]() |
06a1f902ad | ||
![]() |
58f8b23b7c | ||
![]() |
9e7c348b15 | ||
![]() |
5f5ff8b43b | ||
![]() |
f626b4e5fc | ||
![]() |
bc23200e66 | ||
![]() |
95ab59fd5a | ||
![]() |
0bbee003b0 | ||
![]() |
d20cb7a928 | ||
![]() |
952c134aba | ||
![]() |
5533d980e3 | ||
![]() |
aa0213818f | ||
![]() |
af88ffd57c | ||
![]() |
87447b1c2a | ||
![]() |
384a12880b | ||
![]() |
791f91f377 | ||
![]() |
4f8b405cc3 | ||
![]() |
e1b7af201a | ||
![]() |
a04b7817a9 | ||
![]() |
21bf83aec7 | ||
![]() |
d060d5179d | ||
![]() |
e73dd58e46 | ||
![]() |
a34e4a6942 | ||
![]() |
a7ee6d78b5 | ||
![]() |
0a6651ac11 | ||
![]() |
fa25053c13 | ||
![]() |
61dd4edeb5 | ||
![]() |
dbaeff302b | ||
![]() |
6cbe7ebcf2 | ||
![]() |
2826e08c8c | ||
![]() |
e30e337efa | ||
![]() |
39788e0357 | ||
![]() |
c47363df71 | ||
![]() |
4199453038 | ||
![]() |
db991081c8 | ||
![]() |
24f946a727 | ||
![]() |
772dae047a | ||
![]() |
020f440fdd | ||
![]() |
c88fc5ec09 | ||
![]() |
475849fbef | ||
![]() |
1d63228fb2 | ||
![]() |
c918c0c010 | ||
![]() |
1028179983 | ||
![]() |
686f61ff90 | ||
![]() |
ae43fadca3 | ||
![]() |
1bf05780b3 | ||
![]() |
3e30daa1d3 | ||
![]() |
54ef1233b1 | ||
![]() |
4413633de7 | ||
![]() |
c76e20d146 | ||
![]() |
36d53b7ce4 | ||
![]() |
0b0bce2761 | ||
![]() |
d47a9be03c | ||
![]() |
bc32d7ae7a | ||
![]() |
e6747a2c2c | ||
![]() |
3fb48cb64e | ||
![]() |
381db1cf53 | ||
![]() |
d3939aeb9d | ||
![]() |
5956f90557 | ||
![]() |
7f54ecfe5d | ||
![]() |
e7bda99c8b | ||
![]() |
ea7ab5a2bf | ||
![]() |
ee566d199a | ||
![]() |
56eca454b1 | ||
![]() |
d057974c3e | ||
![]() |
9514e7fdea | ||
![]() |
e546113873 | ||
![]() |
60f1139355 | ||
![]() |
1b18b59054 | ||
![]() |
afec0187e9 | ||
![]() |
d0d7e1ccf8 | ||
![]() |
d72376b4b7 | ||
![]() |
3be60cb305 | ||
![]() |
75b1f351a1 | ||
![]() |
07185f8018 | ||
![]() |
2f081b62a7 | ||
![]() |
bbce2a11e1 | ||
![]() |
96ab609157 | ||
![]() |
d961d56a35 | ||
![]() |
82a5335a92 | ||
![]() |
729a23949c | ||
![]() |
a1b0419d7a | ||
![]() |
7a23015b9d | ||
![]() |
9cbe0dbae1 | ||
![]() |
4f139b7d03 | ||
![]() |
1e925e2560 | ||
![]() |
a42e1e3af3 | ||
![]() |
799caec7ee | ||
![]() |
dd7d30498f | ||
![]() |
e9b1720e98 | ||
![]() |
5f41371bdb | ||
![]() |
5226bfae20 | ||
![]() |
d1eab168b7 | ||
![]() |
8760518c10 | ||
![]() |
6719a352c2 | ||
![]() |
8449b6c6b8 | ||
![]() |
0550eaf465 | ||
![]() |
bdc9eb44ec | ||
![]() |
37b99cb1b0 | ||
![]() |
492381e4fc | ||
![]() |
27d65dd799 | ||
![]() |
434724310c | ||
![]() |
e5ad5a8521 | ||
![]() |
3942819fed | ||
![]() |
1cc5f538aa | ||
![]() |
b0d8534ea4 | ||
![]() |
5b2bc38670 | ||
![]() |
b36aa3557c | ||
![]() |
a1a525e6e3 | ||
![]() |
14453cc437 | ||
![]() |
db760ba5d8 | ||
![]() |
4ae692008f | ||
![]() |
f37449f9ac | ||
![]() |
8b7348b3d4 | ||
![]() |
709cbb7b2e | ||
![]() |
187f1a4ce2 | ||
![]() |
0f2ebd3a54 | ||
![]() |
86b63c2792 | ||
![]() |
cec2e71b41 | ||
![]() |
9380f3e1ec | ||
![]() |
76c2934e12 | ||
![]() |
9714c35d4b | ||
![]() |
0d9beb713a | ||
![]() |
c5f8d0e0b7 | ||
![]() |
5e8f4b075d | ||
![]() |
4b53fca3db | ||
![]() |
5d9c030a09 | ||
![]() |
bacbb9a28e | ||
![]() |
7c287e0c03 | ||
![]() |
10f675137d | ||
![]() |
6bdb5328e3 | ||
![]() |
14f529ac4e | ||
![]() |
ffe96d9ef1 | ||
![]() |
335f264caa | ||
![]() |
b73e86ea9f | ||
![]() |
2bc2c4c57b | ||
![]() |
6f87c2f03a | ||
![]() |
75e677af88 | ||
![]() |
9ffe355396 | ||
![]() |
60b0fb23f8 | ||
![]() |
1c05ffc6ed | ||
![]() |
8cd4e43c68 | ||
![]() |
8486d28310 | ||
![]() |
e8aadda185 | ||
![]() |
fcfd0428ab | ||
![]() |
ddcc087800 | ||
![]() |
d574de54b4 | ||
![]() |
1682ac03ac | ||
![]() |
447dbece1c | ||
![]() |
dcca901b17 | ||
![]() |
a32c779074 | ||
![]() |
187c0f9829 | ||
![]() |
6c970c88ab | ||
![]() |
28a4520c77 | ||
![]() |
02d0dcdff7 | ||
![]() |
427d4e31c9 | ||
![]() |
c60f7aac44 | ||
![]() |
42a7758a34 | ||
![]() |
e0bade4670 | ||
![]() |
6af83152de | ||
![]() |
091a30045d | ||
![]() |
b2c8ae0c33 | ||
![]() |
8b6e0982c6 | ||
![]() |
caa3ebd600 | ||
![]() |
d248e047b3 | ||
![]() |
25a95a1de0 | ||
![]() |
d506b2c692 | ||
![]() |
24c672c2b9 | ||
![]() |
c407e0e83e | ||
![]() |
b1346698d6 | ||
![]() |
5c01129567 | ||
![]() |
cd7ce53bd0 | ||
![]() |
4c95c20061 | ||
![]() |
5339db5058 | ||
![]() |
623e932f8c | ||
![]() |
43659de4f4 | ||
![]() |
2a661eda42 | ||
![]() |
c85a93a17b | ||
![]() |
8ab36cb3e1 | ||
![]() |
72820d0708 | ||
![]() |
95b551d4ba | ||
![]() |
68af9a0695 | ||
![]() |
6953c3989b | ||
![]() |
cd4cb385d5 | ||
![]() |
f4f6d595fc | ||
![]() |
d2356f00e9 | ||
![]() |
e408136196 | ||
![]() |
c355968add | ||
![]() |
783f878947 | ||
![]() |
4faf41e482 | ||
![]() |
d8964b6ed2 | ||
![]() |
b5b999941c | ||
![]() |
deeba8c4de | ||
![]() |
9e48729eb0 | ||
![]() |
936e374c05 | ||
![]() |
0f3524b114 | ||
![]() |
d62de3d72c | ||
![]() |
957a80da4b | ||
![]() |
1dccd70f7c | ||
![]() |
006a5d4e61 | ||
![]() |
ce7cdcf54e | ||
![]() |
c1ebb4a79b | ||
![]() |
41964ae1de | ||
![]() |
66cf34adf7 | ||
![]() |
9e9e0009cf | ||
![]() |
d5cd9660fc | ||
![]() |
12a7803653 | ||
![]() |
8f7bef6a20 | ||
![]() |
a0715b830c | ||
![]() |
f87ce10dc4 | ||
![]() |
ee4936b8c9 | ||
![]() |
3cb2592660 | ||
![]() |
574c901b40 | ||
![]() |
7590ba4ad5 | ||
![]() |
39ce18f8bb | ||
![]() |
777a4f9d3f | ||
![]() |
b91a938787 | ||
![]() |
c903abdb1b | ||
![]() |
3279bc0580 | ||
![]() |
bd32c9f49e | ||
![]() |
5507088e3d | ||
![]() |
37ad48ae4a | ||
![]() |
120c6e6d87 | ||
![]() |
866e907b7e | ||
![]() |
2bd8c2cb10 | ||
![]() |
c6c9919178 | ||
![]() |
575bf9d1e0 | ||
![]() |
82a56e0285 | ||
![]() |
25d5f7c132 | ||
![]() |
a3e9ecf30f | ||
![]() |
ec5ff0a07f | ||
![]() |
be836d30c5 | ||
![]() |
42b1529a5f | ||
![]() |
47708c4807 | ||
![]() |
d2a51e004c | ||
![]() |
ab14230101 | ||
![]() |
4bcf8c1f78 | ||
![]() |
44d00e9da3 | ||
![]() |
d7e6a4493c | ||
![]() |
53e89d8c54 | ||
![]() |
4497c13634 | ||
![]() |
4a35fade46 | ||
![]() |
6cba0601fd | ||
![]() |
ed4332ea78 | ||
![]() |
aba069cec5 | ||
![]() |
8a82ac0a11 | ||
![]() |
1cd1456d75 | ||
![]() |
b791a3eb10 | ||
![]() |
3b22a8b170 | ||
![]() |
419e8214ca | ||
![]() |
b9f8571f0f | ||
![]() |
c6d9a9d7f8 | ||
![]() |
310aba6ccb | ||
![]() |
9bd89ac4f6 | ||
![]() |
ea6a51dca9 | ||
![]() |
e701bcc50c | ||
![]() |
a1abf06e75 | ||
![]() |
76ace394b0 | ||
![]() |
4dac462f8f | ||
![]() |
039672b1e7 | ||
![]() |
1b26ecbbf5 | ||
![]() |
f4a7e96943 | ||
![]() |
a45bc2954f | ||
![]() |
62f32467b7 | ||
![]() |
600a1bf201 | ||
![]() |
7e196e7aa6 | ||
![]() |
9ad3507b66 | ||
![]() |
add1bdfcf6 | ||
![]() |
7ea8a7c079 | ||
![]() |
28e31f5165 | ||
![]() |
10a6975c5d | ||
![]() |
b34ea87660 | ||
![]() |
86ed69c50b | ||
![]() |
02e824154c | ||
![]() |
dc973c8491 | ||
![]() |
0a28e3a8d3 | ||
![]() |
7a48c260e1 | ||
![]() |
c55c49a3a2 | ||
![]() |
0fc9b06d12 | ||
![]() |
d71ad5a6bf | ||
![]() |
f0b3028306 | ||
![]() |
752992c527 | ||
![]() |
43c4476396 | ||
![]() |
f8172bed56 | ||
![]() |
c1f71b4cfc | ||
![]() |
4799da15e7 | ||
![]() |
4936e47c7a | ||
![]() |
cb965373aa | ||
![]() |
654a91184a | ||
![]() |
57997f7f4b | ||
![]() |
ca2f5be3d1 | ||
![]() |
1b091073f1 | ||
![]() |
85d2d3c442 | ||
![]() |
d77dfd63cf | ||
![]() |
db2bf52fca | ||
![]() |
2c62d97440 | ||
![]() |
53b2e64214 | ||
![]() |
ccf82a3ee5 | ||
![]() |
9cb6f35e60 | ||
![]() |
da2e33a040 | ||
![]() |
f2d260bfa4 | ||
![]() |
783c7244f9 | ||
![]() |
c9287e0e63 | ||
![]() |
69b84d115c | ||
![]() |
1745b898b1 | ||
![]() |
5ba4c85249 | ||
![]() |
03c87bb46d | ||
![]() |
dff5a76e9e | ||
![]() |
50386f4ca4 | ||
![]() |
de6ba2ec80 | ||
![]() |
ce126015d9 | ||
![]() |
f2337c3d43 | ||
![]() |
41b59d322a | ||
![]() |
dfea7c111e | ||
![]() |
3d5d672297 | ||
![]() |
e4dcc6f342 | ||
![]() |
9847249611 | ||
![]() |
19742a54ec | ||
![]() |
5af9ae7a80 | ||
![]() |
78962a4a75 | ||
![]() |
9a35d826aa | ||
![]() |
c9cdc89d35 | ||
![]() |
33b75703ba | ||
![]() |
ca55aa3a24 | ||
![]() |
95307c3902 | ||
![]() |
89c8eae7e2 | ||
![]() |
91614772dc | ||
![]() |
cd497ab4dc | ||
![]() |
f81895905e | ||
![]() |
d82fafaa7a | ||
![]() |
0ea01acc46 | ||
![]() |
df55792a68 | ||
![]() |
6a19c45269 | ||
![]() |
23ee345441 | ||
![]() |
0e8ff253f3 | ||
![]() |
89bddb0bc4 | ||
![]() |
77bbca9bb3 | ||
![]() |
1acd4d8d58 | ||
![]() |
4db72a712d | ||
![]() |
da2b7ba08e | ||
![]() |
f8b49411bf | ||
![]() |
a04b0d99b0 | ||
![]() |
9e9735f617 | ||
![]() |
f906b36f01 | ||
![]() |
a9d1f4f854 | ||
![]() |
d017ae905f | ||
![]() |
bede280507 | ||
![]() |
ea130047bc | ||
![]() |
d77d8de63e | ||
![]() |
f5413d9202 | ||
![]() |
559fc8f216 | ||
![]() |
34b2df911d | ||
![]() |
3d5a8a8cbd | ||
![]() |
2b07097e14 | ||
![]() |
372e943d8b | ||
![]() |
95afcedc4f | ||
![]() |
c1dc8f017c | ||
![]() |
dbeddca263 | ||
![]() |
e65d133dec | ||
![]() |
b5e1dea1c2 | ||
![]() |
3f19469939 | ||
![]() |
87874b037a | ||
![]() |
adda6841d1 | ||
![]() |
a8092b921b | ||
![]() |
930e4d69d1 | ||
![]() |
d9219df45b | ||
![]() |
a6d4ec28db | ||
![]() |
b29e13f777 | ||
![]() |
9363b78ff6 | ||
![]() |
eba411fec7 | ||
![]() |
9afe99e134 | ||
![]() |
6678856178 | ||
![]() |
a1fea38c2c | ||
![]() |
2d3265e66d | ||
![]() |
f6d4400db9 | ||
![]() |
6d892a9266 | ||
![]() |
356fa08da5 | ||
![]() |
2225f8c890 | ||
![]() |
d1a89739f9 | ||
![]() |
6ec6896763 | ||
![]() |
9fb718d610 | ||
![]() |
c913b89a47 | ||
![]() |
58b45693b7 | ||
![]() |
29d3ece9b1 | ||
![]() |
7e5db75230 | ||
![]() |
283c0b9845 | ||
![]() |
071a0f1651 | ||
![]() |
1a116557a4 | ||
![]() |
1468297626 | ||
![]() |
87e94fdf52 | ||
![]() |
64e15c33c8 | ||
![]() |
7170f435d1 | ||
![]() |
9942be0493 | ||
![]() |
eaad36277f | ||
![]() |
37cc498568 | ||
![]() |
8a3191340a | ||
![]() |
0f4e998f0a | ||
![]() |
0c93b649ba | ||
![]() |
947d269877 | ||
![]() |
b4b9453948 | ||
![]() |
b99a4cd095 | ||
![]() |
a363d5aa46 | ||
![]() |
ae442dabb4 | ||
![]() |
1477c88397 | ||
![]() |
4172462938 | ||
![]() |
27341ba4f8 | ||
![]() |
7443076094 | ||
![]() |
a764bb4b1d | ||
![]() |
57130e1af7 | ||
![]() |
3f8a354c99 | ||
![]() |
0b10d92929 | ||
![]() |
1a1c55e661 | ||
![]() |
87768f9e8b | ||
![]() |
d079f50364 | ||
![]() |
72a89835c5 | ||
![]() |
39d686810b | ||
![]() |
d936626001 | ||
![]() |
cdce1c5ea6 | ||
![]() |
d59530a54f | ||
![]() |
fe480811fb | ||
![]() |
2e3e0d34c3 | ||
![]() |
1e2984d0d9 | ||
![]() |
3e9fe693c7 | ||
![]() |
63161838d8 | ||
![]() |
7c92951ae9 | ||
![]() |
59a25854ef | ||
![]() |
3ca5768974 | ||
![]() |
9a2dce43dd | ||
![]() |
b7fce4317b | ||
![]() |
97d9514b00 | ||
![]() |
58f88708fa | ||
![]() |
d79c874aa5 | ||
![]() |
58917c1ff8 | ||
![]() |
13b171a62d | ||
![]() |
f0a601922a | ||
![]() |
d90090b35e | ||
![]() |
094d1142e7 | ||
![]() |
eb09d1c925 | ||
![]() |
bd5d75361e | ||
![]() |
5d7c0c635b | ||
![]() |
606f538bf3 | ||
![]() |
574c0eea27 | ||
![]() |
4730cbc543 | ||
![]() |
5c63359550 | ||
![]() |
ec3607f779 | ||
![]() |
7efd0f8098 | ||
![]() |
2a7c30a21a | ||
![]() |
2639c3ee3f | ||
![]() |
547e0153cb | ||
![]() |
423664fcfa | ||
![]() |
c986c230ef | ||
![]() |
7c6001f76e | ||
![]() |
d3620946ac | ||
![]() |
479643221c | ||
![]() |
c9ef8bcf6a | ||
![]() |
d655a7c2f6 | ||
![]() |
306861d3b4 | ||
![]() |
7abab41eed | ||
![]() |
acc2691e33 | ||
![]() |
21a65956b0 | ||
![]() |
9738275ad1 | ||
![]() |
7265034703 | ||
![]() |
9bcc45591d | ||
![]() |
38d657ba0e | ||
![]() |
6a0d16c5bb | ||
![]() |
490d4abb56 | ||
![]() |
a7d0f7fc99 | ||
![]() |
0d2d3ff528 | ||
![]() |
526169f0aa | ||
![]() |
42940ff0e3 | ||
![]() |
e9b943363d | ||
![]() |
01e98ff10c | ||
![]() |
d38981a17d | ||
![]() |
7612e91691 | ||
![]() |
76b0f20033 | ||
![]() |
b78c0f8a29 | ||
![]() |
ea93c7c8fc | ||
![]() |
8ac1952974 | ||
![]() |
b4514a5bbf | ||
![]() |
568053b06d | ||
![]() |
bb180bfc39 | ||
![]() |
5ee635caed | ||
![]() |
5dfd7c8597 | ||
![]() |
fe61b75d7e | ||
![]() |
e7bf565418 | ||
![]() |
12071f6251 | ||
![]() |
72ed2e3ed0 | ||
![]() |
d7c1f134fe | ||
![]() |
5072d9f7ad | ||
![]() |
5d42a1247a | ||
![]() |
ce64be22bd | ||
![]() |
36f9386e8d | ||
![]() |
e9dc963805 | ||
![]() |
8854322997 | ||
![]() |
6018f1e8ca | ||
![]() |
68f8ebb543 | ||
![]() |
301f0218fd | ||
![]() |
a9c4a56893 | ||
![]() |
3ea3d72f11 | ||
![]() |
33da5bf4a7 | ||
![]() |
e3de01948a | ||
![]() |
3cd92aaf54 | ||
![]() |
ab4e1996dd | ||
![]() |
b9ef082abf | ||
![]() |
dac7186da3 | ||
![]() |
1fd6cc2b5e | ||
![]() |
0b7da9790a | ||
![]() |
a9e0e0ead6 | ||
![]() |
079754f1a9 | ||
![]() |
c45b5b1e86 | ||
![]() |
2115cc685c | ||
![]() |
b99e56fc19 | ||
![]() |
74c057eb84 | ||
![]() |
e8ececc0dc | ||
![]() |
ad120b7736 | ||
![]() |
61c0711e79 | ||
![]() |
81c3f6fce0 | ||
![]() |
0a4416e633 | ||
![]() |
6bb712854d | ||
![]() |
46959e2407 | ||
![]() |
debbb049b0 | ||
![]() |
375377fef9 | ||
![]() |
d5758dd6a3 | ||
![]() |
d5deffea58 | ||
![]() |
fadb43d9a1 | ||
![]() |
044b641df0 | ||
![]() |
fbbacdb2ff | ||
![]() |
4bfd7acd96 | ||
![]() |
ff03225cf4 | ||
![]() |
8e820c0e47 | ||
![]() |
d718314324 | ||
![]() |
1c653ec1b1 | ||
![]() |
fe16ddadce | ||
![]() |
7a978054cc | ||
![]() |
8ed3b5a747 | ||
![]() |
6885150800 | ||
![]() |
35d33a1c7d | ||
![]() |
93a16bbd3c | ||
![]() |
d3cf6a4985 | ||
![]() |
8ef7200c32 | ||
![]() |
e43da5ba86 | ||
![]() |
10428b4340 | ||
![]() |
43b7c05cd7 | ||
![]() |
057f64b04c | ||
![]() |
0971d783f3 | ||
![]() |
54aabad3e8 | ||
![]() |
606fbb5fec | ||
![]() |
5093c27ba5 | ||
![]() |
1d3661c946 | ||
![]() |
304f7a068d | ||
![]() |
7ea91be3fc | ||
![]() |
d15464b1ae | ||
![]() |
150435f24e | ||
![]() |
e49507cd14 | ||
![]() |
ad3cc3ebb6 | ||
![]() |
ecaf53836d | ||
![]() |
8fc36e7b24 | ||
![]() |
1dbbac2aa3 | ||
![]() |
4e5775fde4 | ||
![]() |
9d81c7c366 | ||
![]() |
2df0441f0f | ||
![]() |
4216002ce5 | ||
![]() |
1af6f4e151 | ||
![]() |
05f284bc11 | ||
![]() |
40c19b3ad4 | ||
![]() |
d1d972cca0 | ||
![]() |
2a969921d6 | ||
![]() |
4b3e1f5187 | ||
![]() |
561963aa26 | ||
![]() |
6c2c192836 | ||
![]() |
f0730f2295 | ||
![]() |
9df91d2b63 | ||
![]() |
09da1941fd | ||
![]() |
613c8e4c28 | ||
![]() |
7b407fd34d | ||
![]() |
fb7ff7a803 | ||
![]() |
0c1f0e0522 | ||
![]() |
b5d771e9aa | ||
![]() |
2f64255895 | ||
![]() |
5b629a5c40 | ||
![]() |
b749cf52c3 | ||
![]() |
b9a36a9223 | ||
![]() |
32debf6e6b | ||
![]() |
06f6ae01c9 | ||
![]() |
db4d8ad802 | ||
![]() |
9c82de9c9e | ||
![]() |
8329835528 | ||
![]() |
8e624aa31b | ||
![]() |
a2e8741517 | ||
![]() |
3b7c107e8f | ||
![]() |
558bc3f971 | ||
![]() |
90a326f380 | ||
![]() |
867dc1ae35 | ||
![]() |
3f555464f7 | ||
![]() |
c0c0782258 | ||
![]() |
377f57bcb6 | ||
![]() |
a51253f1e5 | ||
![]() |
e674e94da6 | ||
![]() |
93a415f6d3 | ||
![]() |
9364b97692 | ||
![]() |
030915c9ea | ||
![]() |
10882c309a | ||
![]() |
8232fde160 | ||
![]() |
45c3474d4d | ||
![]() |
c5a9e85343 | ||
![]() |
8c7ef59583 | ||
![]() |
36404b5c92 | ||
![]() |
9949a117be | ||
![]() |
a3896db4f5 | ||
![]() |
f668062cab | ||
![]() |
bac0721078 | ||
![]() |
e29d7244d8 | ||
![]() |
5a34b91a7a | ||
![]() |
eaac8b1428 | ||
![]() |
6c6275dc88 | ||
![]() |
bd350ae679 | ||
![]() |
cadee28c68 | ||
![]() |
3534828a99 | ||
![]() |
e1c5777e25 | ||
![]() |
63553d4dd3 | ||
![]() |
6033d779fc | ||
![]() |
97db27e61f | ||
![]() |
8ed861c05f | ||
![]() |
4d416657bf | ||
![]() |
ede0399275 | ||
![]() |
1a28ada04c | ||
![]() |
8ac771cde4 | ||
![]() |
c6afbbfc73 | ||
![]() |
5ba71e8109 | ||
![]() |
a0d2922aca | ||
![]() |
446610b9df | ||
![]() |
4905eea503 | ||
![]() |
519fc128f6 | ||
![]() |
cc10955483 | ||
![]() |
e0bd47bb87 | ||
![]() |
fb0c3c4a06 | ||
![]() |
ceef1fdaf2 | ||
![]() |
e1ac287ed1 | ||
![]() |
29cd3a5945 | ||
![]() |
cab082166b | ||
![]() |
711dfd4da9 | ||
![]() |
643948331d | ||
![]() |
119030f1a5 | ||
![]() |
3efee3dc52 | ||
![]() |
70716d5121 | ||
![]() |
a7d11ead62 | ||
![]() |
017830e433 | ||
![]() |
bceb175c75 | ||
![]() |
98277c6b71 | ||
![]() |
b227fbe523 | ||
![]() |
ac6659a293 | ||
![]() |
30a24ced1d | ||
![]() |
3d1f4ae2ed | ||
![]() |
e86aff049c | ||
![]() |
8ec0ba7c9e | ||
![]() |
c2898f0b2e | ||
![]() |
0747374378 | ||
![]() |
a0c2fea833 | ||
![]() |
811c1a445f | ||
![]() |
72d3041e7e | ||
![]() |
503180e7ec | ||
![]() |
8ad548cad7 | ||
![]() |
85d9acf605 | ||
![]() |
fc93c5ffcb | ||
![]() |
d6b0a9314c | ||
![]() |
83bc07c3ff | ||
![]() |
6ca680cd41 | ||
![]() |
2b533dcb2b | ||
![]() |
13a5a09f98 | ||
![]() |
75ff7ebdbe | ||
![]() |
6d8f3a1fc8 | ||
![]() |
a11b411912 | ||
![]() |
2dba817c69 | ||
![]() |
d4df9a545f | ||
![]() |
cae21391e5 | ||
![]() |
573b22d2c2 | ||
![]() |
14d4112a9d | ||
![]() |
28aa9db9c5 | ||
![]() |
d50c349e00 | ||
![]() |
905362c59c | ||
![]() |
97e7d44310 | ||
![]() |
bb71a1ef23 | ||
![]() |
de2771d008 | ||
![]() |
02de34b65a | ||
![]() |
c6e14889f2 | ||
![]() |
f843732790 | ||
![]() |
80e7ff0fc1 | ||
![]() |
2964db6bdd | ||
![]() |
5fbd94ec74 | ||
![]() |
1d8d31d4f0 | ||
![]() |
707c3eed99 | ||
![]() |
e33a81ad36 | ||
![]() |
0f7d216379 | ||
![]() |
f0052e97a6 | ||
![]() |
5c6076d48d | ||
![]() |
883bd31249 | ||
![]() |
d7b5fde3c7 | ||
![]() |
f4273efef0 | ||
![]() |
471dc966d9 | ||
![]() |
50368654a4 | ||
![]() |
b1e1cc04ce | ||
![]() |
554f67e295 | ||
![]() |
278bd09a6c | ||
![]() |
300d083038 | ||
![]() |
34664f0025 | ||
![]() |
7aaa803813 | ||
![]() |
b075b3ec1c | ||
![]() |
0f3f4b0f5b | ||
![]() |
fd5ed78442 | ||
![]() |
d516e7dcb4 | ||
![]() |
6a1f1ebf9d | ||
![]() |
6ba5c02dd6 | ||
![]() |
c9b8f90859 | ||
![]() |
70a0bf6d5c | ||
![]() |
4caf8d6fab | ||
![]() |
aa90593158 | ||
![]() |
9da5531483 | ||
![]() |
9483459ba7 | ||
![]() |
ae57883770 | ||
![]() |
8cb5a89d10 | ||
![]() |
1a35fb0d4d | ||
![]() |
1a2483c68c | ||
![]() |
6c806238b2 | ||
![]() |
ea6e07a38b | ||
![]() |
ec6b07b275 | ||
![]() |
e85a03a1ca | ||
![]() |
5d66b7677f | ||
![]() |
3932834172 | ||
![]() |
d2e8294a1a | ||
![]() |
b06aa66ad8 | ||
![]() |
c45b48d949 | ||
![]() |
f779af1f65 | ||
![]() |
78d039cd5f | ||
![]() |
fdbd5418c7 | ||
![]() |
5df42466fd | ||
![]() |
ff2bed87f2 | ||
![]() |
765e7d0b1e | ||
![]() |
71ab6d42c8 | ||
![]() |
2ea2a662ef | ||
![]() |
c2d45349a4 | ||
![]() |
1b5cf410b7 | ||
![]() |
3e79e2bed0 | ||
![]() |
2a1f933702 | ||
![]() |
251d3b487f | ||
![]() |
e55ec48c7d | ||
![]() |
7ce2195adb | ||
![]() |
537b79f1c2 | ||
![]() |
e4c4d22f56 | ||
![]() |
c4d244398c | ||
![]() |
47260cdaf0 | ||
![]() |
7ef13058c7 | ||
![]() |
8066cb1804 | ||
![]() |
c5af6062fa | ||
![]() |
908a2eba20 | ||
![]() |
6f43957703 | ||
![]() |
897ea28cf4 | ||
![]() |
d056ddbff1 | ||
![]() |
f157350059 | ||
![]() |
7e3d99bda3 | ||
![]() |
c7c53e1d94 | ||
![]() |
b912ee3f6f | ||
![]() |
06c05ad8e5 | ||
![]() |
7f411400d5 | ||
![]() |
f24f234869 | ||
![]() |
4e384e7811 | ||
![]() |
5143448163 | ||
![]() |
8e5e9f7cbc | ||
![]() |
5ea7fd01bf | ||
![]() |
8f3f6bc774 | ||
![]() |
7f1524b42f | ||
![]() |
4b7db4689d | ||
![]() |
92831ecb43 | ||
![]() |
d486f3f306 | ||
![]() |
bfb7468f62 | ||
![]() |
2e417d41db | ||
![]() |
b17f68cbfb | ||
![]() |
8a22a523d6 | ||
![]() |
97fe752a4e | ||
![]() |
cc4ea122a2 | ||
![]() |
db995d29e5 | ||
![]() |
c22dde8008 | ||
![]() |
462d888894 | ||
![]() |
9311b914ad | ||
![]() |
c5e0488210 | ||
![]() |
f548c27179 | ||
![]() |
1f5f405b52 | ||
![]() |
cd923ab838 | ||
![]() |
aacdff92d2 | ||
![]() |
32160d388a | ||
![]() |
72e31929eb | ||
![]() |
29014bb40e | ||
![]() |
e9d0a65536 | ||
![]() |
f7a3b68834 | ||
![]() |
dcc9d3b588 | ||
![]() |
b8f6f65943 | ||
![]() |
3dacdda21a | ||
![]() |
49b766120f | ||
![]() |
2d7e1553f8 | ||
![]() |
d5d41213b0 | ||
![]() |
328df00d2e | ||
![]() |
e4a5bf8234 | ||
![]() |
d6ee0f216c | ||
![]() |
0246ef6b6a | ||
![]() |
7fd40518fd | ||
![]() |
95eb53edf6 | ||
![]() |
4cdf2962cd | ||
![]() |
5bf8ccd1fd | ||
![]() |
dd9fbbcfa7 | ||
![]() |
72d8fd5be0 | ||
![]() |
b577229ed3 | ||
![]() |
4ae870b799 | ||
![]() |
0590e74b30 | ||
![]() |
b9956ba800 | ||
![]() |
fef6259d09 | ||
![]() |
e24f19e88b | ||
![]() |
cc6de1e71c | ||
![]() |
b0240a1c95 | ||
![]() |
8acdec333b | ||
![]() |
eafcbb81f9 | ||
![]() |
4b083463c8 | ||
![]() |
78e834e04f | ||
![]() |
2ed1893620 | ||
![]() |
35f188a7dd | ||
![]() |
07f577a9dd | ||
![]() |
25c72b50c0 | ||
![]() |
e07346ebea | ||
![]() |
699b466291 | ||
![]() |
f0f24ff96f | ||
![]() |
1113997c71 | ||
![]() |
487fb6e5c9 | ||
![]() |
62908a323c | ||
![]() |
021131271a | ||
![]() |
c20fa4dbd2 | ||
![]() |
b1826678da | ||
![]() |
1630338f4e | ||
![]() |
78af3d979c | ||
![]() |
8346dfb1f5 | ||
![]() |
5ecb4e4fe4 | ||
![]() |
ec9ff23b23 | ||
![]() |
149e9931e7 | ||
![]() |
58b62094bd | ||
![]() |
d357074ad4 | ||
![]() |
d9bacc129b | ||
![]() |
28d869b099 | ||
![]() |
d04e87718a | ||
![]() |
8d81bf60c9 | ||
![]() |
4fe9094ff7 | ||
![]() |
4cfde45755 | ||
![]() |
c28844dbeb | ||
![]() |
837ea7c8d6 | ||
![]() |
6c85ac8827 | ||
![]() |
c8eb8bf35d | ||
![]() |
0f6cbddd57 | ||
![]() |
530b4755bf | ||
![]() |
679395b3fe | ||
![]() |
9293442836 | ||
![]() |
4841b412f3 | ||
![]() |
f03575ad89 | ||
![]() |
e0e5428ebd | ||
![]() |
015f7edae2 | ||
![]() |
d5414f5d91 | ||
![]() |
4bc3512d42 | ||
![]() |
4c305994ca | ||
![]() |
788e2cba04 | ||
![]() |
b79b79970e | ||
![]() |
8b0f4de516 | ||
![]() |
a17000ad6d | ||
![]() |
c9f63c58df | ||
![]() |
c311b1c706 | ||
![]() |
072451afae | ||
![]() |
7349793463 | ||
![]() |
c0144eab86 | ||
![]() |
ba79b25944 | ||
![]() |
3fb34b12a0 | ||
![]() |
b6c17e76c2 | ||
![]() |
1201f20d79 | ||
![]() |
98ae8e692e | ||
![]() |
8342dbff4e | ||
![]() |
a22aa0f9a7 | ||
![]() |
b49d221ec1 | ||
![]() |
f1be315147 | ||
![]() |
8aaac2a3d4 | ||
![]() |
bd07d30e47 | ||
![]() |
54e103f00f | ||
![]() |
5404d8f7ab | ||
![]() |
1364e02c67 | ||
![]() |
b4818e2f9a | ||
![]() |
734cf57d4a | ||
![]() |
9236610ec1 | ||
![]() |
c33828a5d9 | ||
![]() |
faadb03e46 | ||
![]() |
3a0c4c51d2 | ||
![]() |
6c28c2b91e | ||
![]() |
5226df6194 | ||
![]() |
1ad23a3cbb | ||
![]() |
c4149ca304 | ||
![]() |
68b02fe950 | ||
![]() |
d9408523a5 | ||
![]() |
40ad0f063a | ||
![]() |
40d85e8926 | ||
![]() |
e655f719e6 | ||
![]() |
ede0ea02c5 | ||
![]() |
e579575b21 | ||
![]() |
06ffcc9fdf | ||
![]() |
774d03e510 | ||
![]() |
adcac9dfe6 | ||
![]() |
399e14c70c | ||
![]() |
ec8b51033b | ||
![]() |
ca5d167b6a | ||
![]() |
fcd1b001d1 | ||
![]() |
1cabbefe04 | ||
![]() |
ecefe22c95 | ||
![]() |
64db77b9a2 | ||
![]() |
19d7360ad5 | ||
![]() |
2f014cd827 | ||
![]() |
7fb84205d9 | ||
![]() |
47e1127c5f | ||
![]() |
e036b59306 | ||
![]() |
f4904c3b53 | ||
![]() |
3002a63ba5 | ||
![]() |
b69717e6c3 | ||
![]() |
d07962953f | ||
![]() |
857cf0d21e | ||
![]() |
5f08c2615d | ||
![]() |
e87428ef33 | ||
![]() |
03fd54fe70 | ||
![]() |
086c2c8253 | ||
![]() |
05c19a32ea | ||
![]() |
99d174906a | ||
![]() |
82e30a326a | ||
![]() |
2963a9cdca | ||
![]() |
288da75b2b | ||
![]() |
0943a496dd | ||
![]() |
e5dd7cc2fa | ||
![]() |
358836ef9f | ||
![]() |
aab4fac6c5 | ||
![]() |
525540b603 | ||
![]() |
b30eeb4694 | ||
![]() |
3faf0aa2fc | ||
![]() |
fd728dec5d | ||
![]() |
08b14b72d4 | ||
![]() |
de2e005abf | ||
![]() |
0fc75239a6 | ||
![]() |
390fe30a0d | ||
![]() |
633f49fcd2 | ||
![]() |
30c0ba93b9 | ||
![]() |
e935fb9621 | ||
![]() |
5ce8bb1d08 | ||
![]() |
1acd12980a | ||
![]() |
683235dd8a | ||
![]() |
65fe183ad4 | ||
![]() |
f39d5d355c | ||
![]() |
eccc8e0ff0 | ||
![]() |
dd4d8e775c | ||
![]() |
7a7f857b2f | ||
![]() |
10882b7d93 | ||
![]() |
e669b81005 | ||
![]() |
28a81d9539 | ||
![]() |
6bf5e4a6b8 | ||
![]() |
a51eee93f4 | ||
![]() |
bece2555c2 | ||
![]() |
d98d405009 | ||
![]() |
8d0881632c | ||
![]() |
e8b81da897 | ||
![]() |
acf4fbf750 | ||
![]() |
b4f1921d33 | ||
![]() |
94b4816f53 | ||
![]() |
b6ddafde3e | ||
![]() |
b01036818f | ||
![]() |
ad7da1a0c3 | ||
![]() |
1e0818d9d9 | ||
![]() |
a4686f01c3 | ||
![]() |
84d76f9aab | ||
![]() |
b90bf5eb86 | ||
![]() |
fe258f3fe5 | ||
![]() |
d339494594 | ||
![]() |
adfaf13055 | ||
![]() |
8abfeb5923 | ||
![]() |
c1a027a771 | ||
![]() |
5f3094d79b | ||
![]() |
925b81aca8 | ||
![]() |
c0c8437966 | ||
![]() |
1d27b2fc4a | ||
![]() |
5da43e7808 | ||
![]() |
5edbb558ae | ||
![]() |
7347cc1df2 | ||
![]() |
20cac11b2a | ||
![]() |
75c35c4ff8 | ||
![]() |
9d573512d0 | ||
![]() |
7921365853 | ||
![]() |
43263fd3b9 | ||
![]() |
59042a5ead | ||
![]() |
91b14de807 | ||
![]() |
81fab2be08 | ||
![]() |
165b742782 | ||
![]() |
76fef9c807 | ||
![]() |
e69ea0b9dc | ||
![]() |
98d3183f2b | ||
![]() |
a29390a951 | ||
![]() |
6291ce8617 | ||
![]() |
c76b1b50a0 | ||
![]() |
cc45e2aec0 | ||
![]() |
17efebb8e8 | ||
![]() |
5c94c733ee | ||
![]() |
156b89dd9c | ||
![]() |
34ba9f67e7 | ||
![]() |
5ddaa6b872 | ||
![]() |
9043fa7f56 | ||
![]() |
4c8e487dc9 | ||
![]() |
d3b87179aa | ||
![]() |
2166de8331 | ||
![]() |
f0bc3f001f | ||
![]() |
50448e7085 | ||
![]() |
cd1d42353e | ||
![]() |
5e588bf737 | ||
![]() |
7ff777d178 | ||
![]() |
861621189a | ||
![]() |
dcc00e08fd | ||
![]() |
a1b8a47d4b | ||
![]() |
1fd6b5e239 | ||
![]() |
f91e45bf44 | ||
![]() |
0675a45592 | ||
![]() |
0c7c6ae451 | ||
![]() |
cf089e8c4c | ||
![]() |
90928ac679 | ||
![]() |
3bbcf71784 | ||
![]() |
222734775d | ||
![]() |
f23ee7a6e0 | ||
![]() |
5b075aa6d5 | ||
![]() |
80cd6b693e | ||
![]() |
04721a12b1 | ||
![]() |
64e22c0e46 | ||
![]() |
d5a70c5b08 | ||
![]() |
eaac7b6bcf | ||
![]() |
b062a491cd | ||
![]() |
1e868517bb | ||
![]() |
7b2a93a2d7 | ||
![]() |
f57f0447c6 | ||
![]() |
7126ff881e | ||
![]() |
e28da4b165 | ||
![]() |
92d9b91f7c | ||
![]() |
149c4a30c0 | ||
![]() |
84e62062ec | ||
![]() |
dc1fb74850 | ||
![]() |
00c6010789 | ||
![]() |
5d35c058e0 | ||
![]() |
1522a521f6 | ||
![]() |
6e11b885f9 | ||
![]() |
442ae6e0e8 | ||
![]() |
6b49e83464 | ||
![]() |
f1ecf13fe1 | ||
![]() |
83d1c8582b | ||
![]() |
179f6cd454 | ||
![]() |
91b1474ff0 | ||
![]() |
15aabc88a1 | ||
![]() |
afc0d3017d | ||
![]() |
9e0b1dc8aa | ||
![]() |
55b482fd26 | ||
![]() |
4f9c9a6566 | ||
![]() |
4725120ee9 | ||
![]() |
a288f50fbb | ||
![]() |
09cf2560a4 | ||
![]() |
16353de7b1 | ||
![]() |
eb5834cb5c | ||
![]() |
3ef5736aed | ||
![]() |
d2e7b77d16 | ||
![]() |
8f794bce75 | ||
![]() |
c33196a50a | ||
![]() |
6e8b5b431f | ||
![]() |
8ca3ecf17f | ||
![]() |
91f7db59ea | ||
![]() |
a0b4501352 | ||
![]() |
345047820a | ||
![]() |
ac3525a953 | ||
![]() |
c8c3f5b134 | ||
![]() |
51319c0718 | ||
![]() |
43399b8b47 | ||
![]() |
a6596042b7 | ||
![]() |
23ae85fc9c | ||
![]() |
2da54862f1 | ||
![]() |
f272fb0559 | ||
![]() |
bd04e33586 | ||
![]() |
b09b9752ca | ||
![]() |
a810a48158 | ||
![]() |
b4f5792aa8 | ||
![]() |
fdf0330b4f | ||
![]() |
ca73743082 | ||
![]() |
df0cde2cfd | ||
![]() |
5a8421e807 | ||
![]() |
025ac95d81 | ||
![]() |
71b5824fdc | ||
![]() |
1a907c0be7 | ||
![]() |
1635cabd32 | ||
![]() |
27946a5b0f | ||
![]() |
e141822fd0 | ||
![]() |
6326828a02 | ||
![]() |
96b5362491 | ||
![]() |
8ab91a51bc | ||
![]() |
35e7e7af18 | ||
![]() |
0e248a7302 | ||
![]() |
d5ce4d6600 | ||
![]() |
2365bb5e87 | ||
![]() |
2230216a7e | ||
![]() |
54f896d25f | ||
![]() |
e47d239caf | ||
![]() |
ac259958d7 | ||
![]() |
0505ad88a6 | ||
![]() |
b323de3383 | ||
![]() |
c0e023324b | ||
![]() |
495806d5e3 | ||
![]() |
3a9f745a2d | ||
![]() |
7b15d114a3 | ||
![]() |
6ac0f72169 | ||
![]() |
ff68030231 | ||
![]() |
d34361b6dd | ||
![]() |
56c6ebe523 | ||
![]() |
2c6d2e0eb4 | ||
![]() |
8e64196a8f | ||
![]() |
926d5faf21 | ||
![]() |
18bad2af25 | ||
![]() |
6be4dc4aac | ||
![]() |
6398a59dda | ||
![]() |
48158b1db6 | ||
![]() |
47fe519e54 | ||
![]() |
7e06f19bbc | ||
![]() |
0b66c1f0d6 | ||
![]() |
ff2742ffd8 | ||
![]() |
70c2992a5f | ||
![]() |
4ac4ee6874 | ||
![]() |
865164a404 | ||
![]() |
f9c8069ab2 | ||
![]() |
2fbf5140e5 | ||
![]() |
0126f8144a | ||
![]() |
71383d7482 | ||
![]() |
4d3bfc5f42 | ||
![]() |
c173d217de | ||
![]() |
d2da9a039f | ||
![]() |
c915edd458 | ||
![]() |
504948452e | ||
![]() |
3daa6c7a54 | ||
![]() |
10cd1580a5 | ||
![]() |
5b0876e106 | ||
![]() |
cfcdeaff01 | ||
![]() |
7c34f233fd | ||
![]() |
686146a7d9 | ||
![]() |
44732d5977 | ||
![]() |
05c3794cf7 | ||
![]() |
f0431a504a | ||
![]() |
eccec85ea6 | ||
![]() |
16ff538804 | ||
![]() |
f81e07eb6f | ||
![]() |
1cbd41ad87 | ||
![]() |
d8567b8427 | ||
![]() |
afe6a1923b | ||
![]() |
0f60f4754f | ||
![]() |
7e988d0401 | ||
![]() |
d85813c229 | ||
![]() |
12eb56809d | ||
![]() |
d792172779 | ||
![]() |
011562ae73 | ||
![]() |
71c4e36933 | ||
![]() |
6261982f6c | ||
![]() |
4ac01e0ed0 | ||
![]() |
2dfe07f13e | ||
![]() |
7f4e4017ce | ||
![]() |
635970f37b | ||
![]() |
106e740220 | ||
![]() |
3e6420ba6f | ||
![]() |
79be8010d5 | ||
![]() |
0b6e679f3b | ||
![]() |
97c43ad2b9 | ||
![]() |
cbf978745c | ||
![]() |
63dceada90 | ||
![]() |
366aade8b4 | ||
![]() |
aeb505e3d9 | ||
![]() |
f9482e4773 | ||
![]() |
57dfc22ff7 | ||
![]() |
adc489b6ed | ||
![]() |
0623684315 | ||
![]() |
68afccd859 | ||
![]() |
99eef8fb28 | ||
![]() |
47e7685d39 | ||
![]() |
b6ea596ade | ||
![]() |
44d60b469b | ||
![]() |
51087408df | ||
![]() |
96226d9e6e | ||
![]() |
28f0f62424 | ||
![]() |
2e772a8cd4 | ||
![]() |
3fd192f0cf | ||
![]() |
d16ae81961 |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -362,7 +362,7 @@ MigrationBackup/
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
|
||||
/framework/*pro*
|
||||
/framework/*Pro*
|
||||
|
||||
/src/*Pro*/
|
||||
/src/*Pro*
|
||||
/src/*pro*
|
||||
/src/*pro*/
|
202
LICENSE
Normal file
202
LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Cachetribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2023-present Diego
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
202
LICENSE.txt
202
LICENSE.txt
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2023-present Diego
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
103
README.md
103
README.md
@@ -1,38 +1,101 @@
|
||||
|
||||
# ThingsGateway
|
||||
|
||||
## 介绍
|
||||
|
||||
|
||||
**NetCore** 跨平台边缘采集网关(工业设备采集)
|
||||
## Introduction
|
||||
|
||||
**ThingsGateway** 存储库同时提供 [**设备采集驱动**](https://www.nuget.org/packages?q=Tags%3A%22ThingsGateway%22)
|
||||
|
||||
A cross-platform, high-performance edge data collection gateway based on net9.
|
||||
|
||||
|
||||
**ThingsGateway** 存储库同时提供 **基于Blazor的权限框架** 查看 **ThingsGateway - Admin**
|
||||
## Documentation
|
||||
|
||||
|
||||
[Documentation](https://thingsgateway.cn/).
|
||||
|
||||
[NuGet](https://www.nuget.org/packages?q=Tags%3A%22ThingsGateway%22)
|
||||
|
||||
|
||||
|
||||
## 文档
|
||||
## Demo
|
||||
|
||||
[ThingsGateway](https://diego2098.gitee.io/thingsgateway-docs/) 文档。
|
||||
|
||||
[Demo](https://demo.thingsgateway.cn/)
|
||||
|
||||
## 协议
|
||||
|
||||
Account: **SuperAdmin**
|
||||
|
||||
[ThingsGateway](https://gitee.com/diego2098/ThingsGateway) 采用 [Apache-2.0](https://gitee.com/diego2098/ThingsGateway/blob/master/LICENSE.zh) 开源协议。
|
||||
|
||||
Password: **111111**
|
||||
|
||||
## 演示
|
||||
|
||||
**In the upper-right corner, switch to the IoT Gateway module in the personal popup box**
|
||||
|
||||
[ThingsGateway演示地址](http://120.24.62.140:5000/)
|
||||
## Docker
|
||||
|
||||
账户 : **superAdmin**
|
||||
```shell
|
||||
|
||||
密码 : **111111**
|
||||
docker pull registry.cn-shenzhen.aliyuncs.com/thingsgateway/thingsgateway
|
||||
|
||||
## 赞助
|
||||
|
||||
[ThingsGateway赞助途径](https://diego2098.gitee.io/thingsgateway-docs/docs/donate)
|
||||
|
||||
## 社区
|
||||
|
||||
QQ群:605534569
|
||||
docker pull registry.cn-shenzhen.aliyuncs.com/thingsgateway/thingsgateway_arm64
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Plugin List
|
||||
|
||||
|
||||
|
||||
#### Data Collection Plugins
|
||||
|
||||
|
||||
| Plugin Name | Remarks |
|
||||
| ----------- | ------------------------------------------------------------- |
|
||||
| Modbus | Supports Rtu/Tcp message formats, with Serial/Tcp/Udp links |
|
||||
| SiemensS7 | Siemens PLC S7 series |
|
||||
| Dlt6452007 | Supports Serial/Tcp/Udp links |
|
||||
| OpcDaMaster | Compiled for 64-bit |
|
||||
| OpcUaMaster | Supports certificate login, object extension, Json read/write |
|
||||
| Webhook | Webhook |
|
||||
|
||||
#### Business Plugins
|
||||
|
||||
|
||||
| Plugin Name | Remarks |
|
||||
| ---------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| ModbusSlave | Supports Rtu/Tcp message formats, with Serial/Tcp/Udp links, supports Rpc reverse writing |
|
||||
| OpcUaServer | OpcUa server, supports Rpc reverse writing |
|
||||
| MqttClient | Mqtt client, supports Rpc reverse writing, script-customizable upload content |
|
||||
| MqttServer | Mqtt server, supports WebSocket, supports Rpc reverse writing, script-customizable upload content |
|
||||
| KafkaProducer | Script-customizable upload content |
|
||||
| RabbitMQProducer | Script-customizable upload content |
|
||||
| SqlDB | Relational database storage, supports historical storage and real-time data updates |
|
||||
| SqlHistoryAlarm | Alarm historical data relational database storage |
|
||||
| TDengineDB | Time-series database storage |
|
||||
| QuestDB | Time-series database storage |
|
||||
|
||||
|
||||
|
||||
## License
|
||||
|
||||
|
||||
[License](https://thingsgateway.cn/docs/1)
|
||||
|
||||
|
||||
|
||||
## Sponsorship
|
||||
|
||||
|
||||
[Sponsorship Approach](https://thingsgateway.cn/docs/1000)
|
||||
|
||||
|
||||
## Community
|
||||
|
||||
|
||||
QQ Group: 605534569 [Jump](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=NnBjPO-8kcNFzo_RzSbdICflb97u2O1i&authKey=V1MI3iJtpDMHc08myszP262kDykbx2Yev6ebE4Me0elTe0P0IFAmtU5l7Sy5w0jx&noverify=0&group_code=605534569)
|
||||
|
||||
|
||||
## Pro Plugins
|
||||
|
||||
|
||||
[Plugin List](https://thingsgateway.cn/docs/1001)
|
||||
|
86
README.zh-CN.md
Normal file
86
README.zh-CN.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# ThingsGateway
|
||||
|
||||
## 介绍
|
||||
|
||||
基于net9的跨平台高性能边缘采集网关
|
||||
|
||||
## 文档
|
||||
|
||||
[文档](https://thingsgateway.cn/)
|
||||
|
||||
[NuGet](https://www.nuget.org/packages?q=Tags%3A%22ThingsGateway%22)
|
||||
|
||||
|
||||
## 演示
|
||||
|
||||
[ThingsGateway演示地址](https://demo.thingsgateway.cn/)
|
||||
|
||||
账户 : **SuperAdmin**
|
||||
|
||||
密码 : **111111**
|
||||
|
||||
**右上角个人弹出框中,切换到物联网关模块**
|
||||
|
||||
## Docker
|
||||
|
||||
```shell
|
||||
|
||||
docker pull registry.cn-shenzhen.aliyuncs.com/thingsgateway/thingsgateway
|
||||
|
||||
docker pull registry.cn-shenzhen.aliyuncs.com/thingsgateway/thingsgateway_arm64
|
||||
```
|
||||
|
||||
|
||||
### 插件列表
|
||||
|
||||
#### 采集插件
|
||||
|
||||
|
||||
| 插件名称 | 备注 |
|
||||
| ----------- | ------------------------------------- |
|
||||
| Modbus | Rtu/Tcp报文格式,支持串口/Tcp/Udp链路 |
|
||||
| SiemensS7 | 西门子PLC S7系列 |
|
||||
| Dlt6452007 | 支持串口/Tcp/Udp链路 |
|
||||
| OpcDaMaster | 64位编译 |
|
||||
| OpcUaMaster | 支持证书登录,扩展对象,Json读写 |
|
||||
|
||||
#### 业务插件
|
||||
|
||||
|
||||
| 插件名称 | 备注 |
|
||||
| ---------------- | ---------------------------------------------------------- |
|
||||
| ModbusSlave | Rtu/Tcp报文格式,支持串口/Tcp/Udp链路,支持Rpc反写 |
|
||||
| OpcUaServer | OpcUa服务端,支持Rpc反写 |
|
||||
| MqttClient | Mqtt客户端,支持Rpc反写,脚本自定义上传内容 |
|
||||
| MqttServer | Mqtt服务端,支持WebSocket,支持Rpc反写,脚本自定义上传内容 |
|
||||
| KafkaProducer | 脚本自定义上传内容 |
|
||||
| RabbitMQProducer | 脚本自定义上传内容 |
|
||||
| SqlDB | 关系数据库存储,支持历史存储和实时数据更新 |
|
||||
| SqlHistoryAlarm | 报警历史数据关系数据库存储 |
|
||||
| TDengineDB | 时序数据库存储 |
|
||||
| QuestDB | 时序数据库存储 |
|
||||
| Webhook | Webhook |
|
||||
|
||||
## 协议
|
||||
|
||||
[版权声明](https://thingsgateway.cn/docs/1)
|
||||
|
||||
|
||||
## 赞助
|
||||
|
||||
[赞助途径](https://thingsgateway.cn/docs/1000)
|
||||
|
||||
## 社区
|
||||
|
||||
QQ群:605534569 [跳转](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=NnBjPO-8kcNFzo_RzSbdICflb97u2O1i&authKey=V1MI3iJtpDMHc08myszP262kDykbx2Yev6ebE4Me0elTe0P0IFAmtU5l7Sy5w0jx&noverify=0&group_code=605534569)
|
||||
|
||||
## Pro插件
|
||||
|
||||
[插件列表](https://thingsgateway.cn/docs/1001)
|
||||
|
||||
|
||||
## 特别声明
|
||||
|
||||
ThingsGateway 项目已加入 [dotNET China](https://gitee.com/dotnetchina) 组织。<br/>
|
||||
|
||||

|
@@ -1,20 +0,0 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFrameworks>net6.0;net8.0;</TargetFrameworks>
|
||||
<Version>4.0.0.7</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Authors>Diego</Authors>
|
||||
<Product>ThingsGateway</Product>
|
||||
<Copyright>© 2023-present Diego</Copyright>
|
||||
<RepositoryUrl>https://gitee.com/diego2098/ThingsGateway</RepositoryUrl>
|
||||
<SignAssembly>True</SignAssembly>
|
||||
<DelaySign>False</DelaySign>
|
||||
<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages>
|
||||
<GenerateDocumentationFile>False</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
|
||||
</Project>
|
@@ -1,101 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.6.33927.249
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "admin", "admin", "{4E66C22C-0636-4949-BF6A-9E3BBE1550BA}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
admin\Directory.Build.props = admin\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "admin\ThingsGateway.Components\ThingsGateway.Components.csproj", "{0A891D8E-23B3-46AD-8D30-565EE5004F93}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "admin\ThingsGateway.Core\ThingsGateway.Core.csproj", "{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Core", "admin\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj", "{5DA3D2BD-6768-4479-B52F-49E022EFF310}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Blazor", "admin\ThingsGateway.Admin.Blazor\ThingsGateway.Admin.Blazor.csproj", "{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Application", "admin\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj", "{D6685A42-2712-417A-92C5-5EFF90B9FA94}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.ApiController", "admin\ThingsGateway.Admin.ApiController\ThingsGateway.Admin.ApiController.csproj", "{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
web\Directory.Build.props = web\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Core", "web\ThingsGateway.Web.Core\ThingsGateway.Web.Core.csproj", "{D37EC028-EA46-4510-8261-6E780A906314}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Entry", "web\ThingsGateway.Web.Entry\ThingsGateway.Web.Entry.csproj", "{C5F662EB-991F-438D-BF61-EF87E7371C04}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{97B23D8B-C6C0-4746-A21F-C7B49354B284}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\.gitignore = ..\.gitignore
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj", "{6961511A-8787-42AF-827D-B630B2AF4791}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "foundation", "foundation", "{268A1A81-2685-47E1-9986-5934A58A31A4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{D37EC028-EA46-4510-8261-6E780A906314} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791} = {268A1A81-2685-47E1-9986-5934A58A31A4}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@@ -1,289 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.6.33927.249
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "foundation\ThingsGateway.foundation\ThingsGateway.Foundation.csproj", "{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "foundation", "foundation", "{0874CBC5-C583-4FAD-BA93-94571D446898}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
foundation\Directory.Build.props = foundation\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.DLT645", "foundation\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj", "{92963877-0185-45A5-A0EB-CEC0D55FF9B0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.Modbus", "foundation\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj", "{24510CCE-0B60-4A03-9719-CF367C3528E9}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.OPCDA", "foundation\ThingsGateway.Foundation.Adapter.OPCDA\ThingsGateway.Foundation.Adapter.OPCDA.csproj", "{566783A4-222B-46F5-AA12-0753997B3254}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.OPCUA", "foundation\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj", "{BEFBC44A-E140-4E3E-AFBE-2DD8B98EB9BF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.Siemens", "foundation\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj", "{9695B353-D773-40DD-B65E-7B10EB0C16EC}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{358AE1E1-4DD6-4D1F-8935-1ACBB0111A01}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
demo\Directory.Build.props = demo\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Demo.Photino", "demo\ThingsGateway.Foundation.Demo.Photino\ThingsGateway.Foundation.Demo.Photino.csproj", "{2192217C-CF77-422E-9E63-DF4003ABF01A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Demo.Rcl", "demo\ThingsGateway.Foundation.Demo.Rcl\ThingsGateway.Foundation.Demo.Rcl.csproj", "{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Demo.Winform", "demo\ThingsGateway.Foundation.Demo.Winform\ThingsGateway.Foundation.Demo.Winform.csproj", "{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gateway", "gateway", "{DFB97103-FC3A-4DC3-A327-DA8C65BDA607}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
gateway\Directory.Build.props = gateway\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "admin", "admin", "{4E66C22C-0636-4949-BF6A-9E3BBE1550BA}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
admin\Directory.Build.props = admin\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "admin\ThingsGateway.Components\ThingsGateway.Components.csproj", "{0A891D8E-23B3-46AD-8D30-565EE5004F93}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "admin\ThingsGateway.Core\ThingsGateway.Core.csproj", "{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Core", "admin\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj", "{5DA3D2BD-6768-4479-B52F-49E022EFF310}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Blazor", "admin\ThingsGateway.Admin.Blazor\ThingsGateway.Admin.Blazor.csproj", "{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Application", "admin\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj", "{D6685A42-2712-417A-92C5-5EFF90B9FA94}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.ApiController", "admin\ThingsGateway.Admin.ApiController\ThingsGateway.Admin.ApiController.csproj", "{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Core", "gateway\ThingsGateway.Gateway.Core\ThingsGateway.Gateway.Core.csproj", "{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Blazor", "gateway\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj", "{69EA3D89-CB40-425A-8D70-5E4A33337BE5}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Application", "gateway\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj", "{90AB5C24-1AA3-4F58-9987-B307B92B5193}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.ApiController", "gateway\ThingsGateway.Gateway.ApiController\ThingsGateway.Gateway.ApiController.csproj", "{4C7A5A90-8292-413B-8848-419D9DCDE66F}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
web\Directory.Build.props = web\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Core", "web\ThingsGateway.Web.Core\ThingsGateway.Web.Core.csproj", "{D37EC028-EA46-4510-8261-6E780A906314}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Entry", "web\ThingsGateway.Web.Entry\ThingsGateway.Web.Entry.csproj", "{C5F662EB-991F-438D-BF61-EF87E7371C04}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugin", "plugin", "{E65490B8-D2E2-4693-B39C-15703B1EBFBB}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
plugin\Directory.Build.props = plugin\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Modbus", "plugin\ThingsGateway.Plugin.Modbus\ThingsGateway.Plugin.Modbus.csproj", "{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Mqtt", "plugin\ThingsGateway.Plugin.Mqtt\ThingsGateway.Plugin.Mqtt.csproj", "{53C870AE-0249-4485-AE63-F8A16EA4BCB4}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{97B23D8B-C6C0-4746-A21F-C7B49354B284}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\.gitignore = ..\.gitignore
|
||||
Directory.Build.props = Directory.Build.props
|
||||
..\README.md = ..\README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Kafka", "plugin\ThingsGateway.Plugin.Kafka\ThingsGateway.Plugin.Kafka.csproj", "{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.SQLDB", "plugin\ThingsGateway.Plugin.SQLDB\ThingsGateway.Plugin.SQLDB.csproj", "{C102AB3A-377E-4753-AFA7-C13250D7DF00}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.QuestDB", "plugin\ThingsGateway.Plugin.QuestDB\ThingsGateway.Plugin.QuestDB.csproj", "{0DE1D254-0BD2-4D98-B939-5440BE5EB552}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.TDengineDB", "plugin\ThingsGateway.Plugin.TDengineDB\ThingsGateway.Plugin.TDengineDB.csproj", "{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.RabbitMQ", "plugin\ThingsGateway.Plugin.RabbitMQ\ThingsGateway.Plugin.RabbitMQ.csproj", "{A8E68E17-4EBF-4E4C-8272-B489329A68BF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Siemens", "plugin\ThingsGateway.Plugin.Siemens\ThingsGateway.Plugin.Siemens.csproj", "{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.DLT645", "plugin\ThingsGateway.Plugin.DLT645\ThingsGateway.Plugin.DLT645.csproj", "{AC4295F2-AB2F-4137-99EF-80FA5C83896B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCDA", "plugin\ThingsGateway.Plugin.OPCDA\ThingsGateway.Plugin.OPCDA.csproj", "{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCUA", "plugin\ThingsGateway.Plugin.OPCUA\ThingsGateway.Plugin.OPCUA.csproj", "{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.SQLHisAlarm", "plugin\ThingsGateway.Plugin.SQLHisAlarm\ThingsGateway.Plugin.SQLHisAlarm.csproj", "{0947E6C0-6371-4483-B0ED-191FB5073151}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{92963877-0185-45A5-A0EB-CEC0D55FF9B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{92963877-0185-45A5-A0EB-CEC0D55FF9B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{92963877-0185-45A5-A0EB-CEC0D55FF9B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{92963877-0185-45A5-A0EB-CEC0D55FF9B0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{24510CCE-0B60-4A03-9719-CF367C3528E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{24510CCE-0B60-4A03-9719-CF367C3528E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{24510CCE-0B60-4A03-9719-CF367C3528E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{24510CCE-0B60-4A03-9719-CF367C3528E9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{566783A4-222B-46F5-AA12-0753997B3254}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{566783A4-222B-46F5-AA12-0753997B3254}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{566783A4-222B-46F5-AA12-0753997B3254}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{566783A4-222B-46F5-AA12-0753997B3254}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BEFBC44A-E140-4E3E-AFBE-2DD8B98EB9BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BEFBC44A-E140-4E3E-AFBE-2DD8B98EB9BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BEFBC44A-E140-4E3E-AFBE-2DD8B98EB9BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BEFBC44A-E140-4E3E-AFBE-2DD8B98EB9BF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9695B353-D773-40DD-B65E-7B10EB0C16EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9695B353-D773-40DD-B65E-7B10EB0C16EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9695B353-D773-40DD-B65E-7B10EB0C16EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9695B353-D773-40DD-B65E-7B10EB0C16EC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2192217C-CF77-422E-9E63-DF4003ABF01A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2192217C-CF77-422E-9E63-DF4003ABF01A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2192217C-CF77-422E-9E63-DF4003ABF01A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2192217C-CF77-422E-9E63-DF4003ABF01A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{69EA3D89-CB40-425A-8D70-5E4A33337BE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{69EA3D89-CB40-425A-8D70-5E4A33337BE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{69EA3D89-CB40-425A-8D70-5E4A33337BE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{69EA3D89-CB40-425A-8D70-5E4A33337BE5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{90AB5C24-1AA3-4F58-9987-B307B92B5193}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{90AB5C24-1AA3-4F58-9987-B307B92B5193}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{90AB5C24-1AA3-4F58-9987-B307B92B5193}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{90AB5C24-1AA3-4F58-9987-B307B92B5193}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4C7A5A90-8292-413B-8848-419D9DCDE66F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4C7A5A90-8292-413B-8848-419D9DCDE66F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4C7A5A90-8292-413B-8848-419D9DCDE66F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4C7A5A90-8292-413B-8848-419D9DCDE66F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{53C870AE-0249-4485-AE63-F8A16EA4BCB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{53C870AE-0249-4485-AE63-F8A16EA4BCB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{53C870AE-0249-4485-AE63-F8A16EA4BCB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{53C870AE-0249-4485-AE63-F8A16EA4BCB4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C102AB3A-377E-4753-AFA7-C13250D7DF00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C102AB3A-377E-4753-AFA7-C13250D7DF00}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C102AB3A-377E-4753-AFA7-C13250D7DF00}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C102AB3A-377E-4753-AFA7-C13250D7DF00}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0DE1D254-0BD2-4D98-B939-5440BE5EB552}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0DE1D254-0BD2-4D98-B939-5440BE5EB552}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0DE1D254-0BD2-4D98-B939-5440BE5EB552}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0DE1D254-0BD2-4D98-B939-5440BE5EB552}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A8E68E17-4EBF-4E4C-8272-B489329A68BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A8E68E17-4EBF-4E4C-8272-B489329A68BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A8E68E17-4EBF-4E4C-8272-B489329A68BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A8E68E17-4EBF-4E4C-8272-B489329A68BF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AC4295F2-AB2F-4137-99EF-80FA5C83896B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AC4295F2-AB2F-4137-99EF-80FA5C83896B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AC4295F2-AB2F-4137-99EF-80FA5C83896B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AC4295F2-AB2F-4137-99EF-80FA5C83896B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891} = {0874CBC5-C583-4FAD-BA93-94571D446898}
|
||||
{92963877-0185-45A5-A0EB-CEC0D55FF9B0} = {0874CBC5-C583-4FAD-BA93-94571D446898}
|
||||
{24510CCE-0B60-4A03-9719-CF367C3528E9} = {0874CBC5-C583-4FAD-BA93-94571D446898}
|
||||
{566783A4-222B-46F5-AA12-0753997B3254} = {0874CBC5-C583-4FAD-BA93-94571D446898}
|
||||
{BEFBC44A-E140-4E3E-AFBE-2DD8B98EB9BF} = {0874CBC5-C583-4FAD-BA93-94571D446898}
|
||||
{9695B353-D773-40DD-B65E-7B10EB0C16EC} = {0874CBC5-C583-4FAD-BA93-94571D446898}
|
||||
{2192217C-CF77-422E-9E63-DF4003ABF01A} = {358AE1E1-4DD6-4D1F-8935-1ACBB0111A01}
|
||||
{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB} = {358AE1E1-4DD6-4D1F-8935-1ACBB0111A01}
|
||||
{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325} = {358AE1E1-4DD6-4D1F-8935-1ACBB0111A01}
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2} = {DFB97103-FC3A-4DC3-A327-DA8C65BDA607}
|
||||
{69EA3D89-CB40-425A-8D70-5E4A33337BE5} = {DFB97103-FC3A-4DC3-A327-DA8C65BDA607}
|
||||
{90AB5C24-1AA3-4F58-9987-B307B92B5193} = {DFB97103-FC3A-4DC3-A327-DA8C65BDA607}
|
||||
{4C7A5A90-8292-413B-8848-419D9DCDE66F} = {DFB97103-FC3A-4DC3-A327-DA8C65BDA607}
|
||||
{D37EC028-EA46-4510-8261-6E780A906314} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}
|
||||
{ECF3A7A3-2363-4A38-BC78-8FF9A8564603} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{53C870AE-0249-4485-AE63-F8A16EA4BCB4} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{C102AB3A-377E-4753-AFA7-C13250D7DF00} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{0DE1D254-0BD2-4D98-B939-5440BE5EB552} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{C1911F84-6FDB-4DEC-8938-69B2E3901CC4} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{A8E68E17-4EBF-4E4C-8272-B489329A68BF} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{AC4295F2-AB2F-4137-99EF-80FA5C83896B} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{9DA9AED3-9572-4378-A2A6-4D792D67ADDC} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@@ -1,25 +0,0 @@
|
||||
extensions: .cs
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
extensions: .razor
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
@@ -1,9 +0,0 @@
|
||||
<Project>
|
||||
<Import Project="$(SolutionDir)\Directory.Build.props" />
|
||||
<PropertyGroup>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
|
||||
</Project>
|
@@ -1,62 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace ThingsGateway.Admin.ApiController;
|
||||
|
||||
/// <summary>
|
||||
/// 后台登录控制器
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(CateGoryConst.ThingsGatewayAdmin, Order = 200)]
|
||||
[Route("auth/b")]
|
||||
[LoggingMonitor]
|
||||
public class AuthController : IDynamicApiController
|
||||
{
|
||||
private readonly IAuthService _authService;
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="AuthController"/>
|
||||
/// </summary>
|
||||
/// <param name="authService"></param>
|
||||
public AuthController(IAuthService authService)
|
||||
{
|
||||
_authService = authService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 后台登录
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost("login")]
|
||||
[Description(EventSubscriberConst.Login)]
|
||||
public async Task<LoginOutput> LoginAsync(LoginInput input)
|
||||
{
|
||||
return await _authService.LoginAsync(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 后台登出
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("logout")]
|
||||
[Description(EventSubscriberConst.Logout)]
|
||||
[Authorize]
|
||||
public async Task LogoutAsync()
|
||||
{
|
||||
await _authService.LogoutAsync();
|
||||
}
|
||||
}
|
@@ -1,67 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace ThingsGateway.Admin.ApiController;
|
||||
|
||||
/// <summary>
|
||||
/// 文件下载
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(CateGoryConst.ThingsGatewayAdmin, Order = 200)]
|
||||
[Route("file")]
|
||||
[LoggingMonitor]
|
||||
public class FileController : IDynamicApiController
|
||||
{
|
||||
private readonly IOperateLogService _operateLogService;
|
||||
private readonly IVisitLogService _visitLogService;
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="FileController"/>
|
||||
/// </summary>
|
||||
public FileController(
|
||||
IOperateLogService operateLogService,
|
||||
IVisitLogService visitLogService
|
||||
)
|
||||
{
|
||||
_operateLogService = operateLogService;
|
||||
_visitLogService = visitLogService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下载操作日志
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("operateLog")]
|
||||
public async Task<IActionResult> DownloadOperateLogAsync([FromQuery] OperateLogInput input)
|
||||
{
|
||||
var memoryStream = await _operateLogService.ExportFileAsync(input);
|
||||
var data = new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
{
|
||||
FileDownloadName = $"operateLog{DateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx"
|
||||
};
|
||||
return data;
|
||||
}
|
||||
/// <summary>
|
||||
/// 下载访问日志
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("visitLog")]
|
||||
public async Task<IActionResult> DownloadVisitLogAsync([FromQuery] VisitLogInput input)
|
||||
{
|
||||
var memoryStream = await _visitLogService.ExportFileAsync(input);
|
||||
var data = new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
{
|
||||
FileDownloadName = $"operateLog{DateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx"
|
||||
};
|
||||
return data;
|
||||
}
|
||||
}
|
@@ -1,63 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace ThingsGateway.Admin.ApiController;
|
||||
|
||||
/// <summary>
|
||||
/// OpenApi登录控制器
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(CateGoryConst.ThingsGatewayOpenApi, Order = 200)]
|
||||
[Route("auth/openapi")]
|
||||
[LoggingMonitor]
|
||||
[Description("OpenApi登录")]
|
||||
[Authorize(AuthenticationSchemes = "Bearer")]
|
||||
public class OpenApiAuthController : IDynamicApiController
|
||||
{
|
||||
private readonly IOpenApiAuthService _authService;
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="OpenApiAuthController"/>
|
||||
/// </summary>
|
||||
/// <param name="authService"></param>
|
||||
public OpenApiAuthController(IOpenApiAuthService authService)
|
||||
{
|
||||
_authService = authService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OpenApi登录
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost("login")]
|
||||
[Description(EventSubscriberConst.LoginOpenApi)]
|
||||
public async Task<LoginOpenApiOutput> LoginOpenApiAsync(LoginOpenApiInput input)
|
||||
{
|
||||
return await _authService.LoginOpenApiAsync(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 登出
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("logout")]
|
||||
[Description(EventSubscriberConst.LogoutOpenApi)]
|
||||
public async Task LogoutAsync()
|
||||
{
|
||||
await _authService.LogoutAsync();
|
||||
}
|
||||
}
|
@@ -1,69 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.SpecificationDocument;
|
||||
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
namespace ThingsGateway.Admin.ApiController;
|
||||
|
||||
/// <summary>
|
||||
/// Swagger登录授权服务
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(CateGoryConst.ThingsGatewayAdmin, Order = 200)]
|
||||
[Route("Swagger")]
|
||||
public class SwaggerController : IDynamicApiController, IScoped
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="SwaggerController"/>
|
||||
/// </summary>
|
||||
/// <param name="sysConfigService"></param>
|
||||
public SwaggerController(IConfigService sysConfigService)
|
||||
{
|
||||
_configService = sysConfigService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Swagger登录检查
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("CheckUrl")]
|
||||
[AllowAnonymous, NonUnify]
|
||||
public async Task<int> SwaggerCheckUrlAsync()
|
||||
{
|
||||
var enable = (await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SWAGGERLOGIN_OPEN)).ConfigValue.ToBool(false);
|
||||
return enable ? 401 : 200;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Swagger登录
|
||||
/// </summary>
|
||||
/// <param name="auth"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("SubmitUrl")]
|
||||
[AllowAnonymous, NonUnify]
|
||||
public async Task<int> SwaggerSubmitUrlAsync([FromForm] SpecificationAuth auth)
|
||||
{
|
||||
var userName = (await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SWAGGER_NAME)).ConfigValue;
|
||||
var password = (await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SWAGGER_PASSWORD)).ConfigValue;
|
||||
if (auth.UserName == userName && auth.Password == password)
|
||||
{
|
||||
return 200;
|
||||
}
|
||||
return 401;
|
||||
}
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
global using Furion.DynamicApiController;
|
||||
|
||||
global using System;
|
||||
global using System.Threading.Tasks;
|
||||
|
||||
global using ThingsGateway.Admin.Application;
|
||||
global using ThingsGateway.Foundation.Core;
|
@@ -1,12 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<DocumentationFile>$(MSBuildProjectName).xml</DocumentationFile>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@@ -1,102 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>ThingsGateway.Admin.ApiController</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="T:ThingsGateway.Admin.ApiController.AuthController">
|
||||
<summary>
|
||||
后台登录控制器
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ThingsGateway.Admin.ApiController.AuthController.#ctor(ThingsGateway.Admin.Application.IAuthService)">
|
||||
<summary>
|
||||
<inheritdoc cref="T:ThingsGateway.Admin.ApiController.AuthController"/>
|
||||
</summary>
|
||||
<param name="authService"></param>
|
||||
</member>
|
||||
<member name="M:ThingsGateway.Admin.ApiController.AuthController.LoginAsync(ThingsGateway.Admin.Application.LoginInput)">
|
||||
<summary>
|
||||
后台登录
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ThingsGateway.Admin.ApiController.AuthController.LogoutAsync">
|
||||
<summary>
|
||||
后台登出
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:ThingsGateway.Admin.ApiController.FileController">
|
||||
<summary>
|
||||
文件下载
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ThingsGateway.Admin.ApiController.FileController.#ctor(ThingsGateway.Admin.Application.IOperateLogService,ThingsGateway.Admin.Application.IVisitLogService)">
|
||||
<summary>
|
||||
<inheritdoc cref="T:ThingsGateway.Admin.ApiController.FileController"/>
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ThingsGateway.Admin.ApiController.FileController.DownloadOperateLogAsync(ThingsGateway.Admin.Application.OperateLogInput)">
|
||||
<summary>
|
||||
下载操作日志
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ThingsGateway.Admin.ApiController.FileController.DownloadVisitLogAsync(ThingsGateway.Admin.Application.VisitLogInput)">
|
||||
<summary>
|
||||
下载访问日志
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:ThingsGateway.Admin.ApiController.OpenApiAuthController">
|
||||
<summary>
|
||||
OpenApi登录控制器
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ThingsGateway.Admin.ApiController.OpenApiAuthController.#ctor(ThingsGateway.Admin.Application.IOpenApiAuthService)">
|
||||
<summary>
|
||||
<inheritdoc cref="T:ThingsGateway.Admin.ApiController.OpenApiAuthController"/>
|
||||
</summary>
|
||||
<param name="authService"></param>
|
||||
</member>
|
||||
<member name="M:ThingsGateway.Admin.ApiController.OpenApiAuthController.LoginOpenApiAsync(ThingsGateway.Admin.Application.LoginOpenApiInput)">
|
||||
<summary>
|
||||
OpenApi登录
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ThingsGateway.Admin.ApiController.OpenApiAuthController.LogoutAsync">
|
||||
<summary>
|
||||
登出
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:ThingsGateway.Admin.ApiController.SwaggerController">
|
||||
<summary>
|
||||
Swagger登录授权服务
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ThingsGateway.Admin.ApiController.SwaggerController.#ctor(ThingsGateway.Admin.Application.IConfigService)">
|
||||
<summary>
|
||||
<inheritdoc cref="T:ThingsGateway.Admin.ApiController.SwaggerController"/>
|
||||
</summary>
|
||||
<param name="sysConfigService"></param>
|
||||
</member>
|
||||
<member name="M:ThingsGateway.Admin.ApiController.SwaggerController.SwaggerCheckUrlAsync">
|
||||
<summary>
|
||||
Swagger登录检查
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ThingsGateway.Admin.ApiController.SwaggerController.SwaggerSubmitUrlAsync(Furion.SpecificationDocument.SpecificationAuth)">
|
||||
<summary>
|
||||
Swagger登录
|
||||
</summary>
|
||||
<param name="auth"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
@@ -1,43 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 操作事件说明特性
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class OperDescAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作记录标识
|
||||
/// </summary>
|
||||
/// <param name="description"></param>
|
||||
/// <param name="catcategory"></param>
|
||||
public OperDescAttribute(string description, string catcategory = LogConst.LOG_OPERATE)
|
||||
{
|
||||
Description = description;
|
||||
Catcategory = catcategory;
|
||||
}
|
||||
/// <summary>
|
||||
/// 分类
|
||||
/// </summary>
|
||||
public string Catcategory { get; }
|
||||
/// <summary>
|
||||
/// 说明
|
||||
/// </summary>
|
||||
public string Description { get; }
|
||||
/// <summary>
|
||||
/// 记录参数,默认true
|
||||
/// </summary>
|
||||
public bool IsRecordPar { get; set; } = true;
|
||||
}
|
@@ -1,224 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.Reflection;
|
||||
using Furion.Reflection.Extensions;
|
||||
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
using UAParser;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// AOP处理操作日志
|
||||
/// </summary>
|
||||
public class OperDispatchProxy : AspectDispatchProxy, IDispatchProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务提供器,可以用来解析服务,如:Services.GetService()
|
||||
/// </summary>
|
||||
public IServiceProvider Services { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前服务实例
|
||||
/// </summary>
|
||||
public object Target { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 方法
|
||||
/// </summary>
|
||||
/// <param name="method"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
public override object Invoke(MethodInfo method, object[] args)
|
||||
{
|
||||
var desc = Target.GetCustomAttribute<OperDescAttribute>(method.ToString(), true);
|
||||
if (desc == null)
|
||||
{
|
||||
return Invoke(method, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
Exception exception = default;
|
||||
object result = default;
|
||||
try
|
||||
{
|
||||
result = Invoke(method, args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
}
|
||||
|
||||
WriteOperLog(method, args, desc, result, exception);
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
throw exception;
|
||||
}
|
||||
return result;//返回结果
|
||||
}
|
||||
|
||||
object Invoke(MethodInfo method, object[] args)
|
||||
{
|
||||
//如果不带返回值
|
||||
if (method.ReturnType == typeof(void))
|
||||
{
|
||||
return method.Invoke(Target, args);//直接返回
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = method.Invoke(Target, args);
|
||||
return result;//返回结果
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步无返回值
|
||||
/// </summary>
|
||||
/// <param name="method"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public override async Task InvokeAsync(MethodInfo method, object[] args)
|
||||
{
|
||||
var desc = method.GetActualCustomAttribute<OperDescAttribute>(Target, true);
|
||||
if (desc == null)
|
||||
{
|
||||
var task = method.Invoke(Target, args) as Task;
|
||||
await task;
|
||||
}
|
||||
else
|
||||
{
|
||||
Exception exception = default;
|
||||
try
|
||||
{
|
||||
var task = method.Invoke(Target, args) as Task;
|
||||
await task;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
}
|
||||
|
||||
WriteOperLog(method, args, desc, null, exception);
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步带返回值
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="method"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public override async Task<T> InvokeAsyncT<T>(MethodInfo method, object[] args)
|
||||
{
|
||||
var desc = method.GetActualCustomAttribute<OperDescAttribute>(Target, true);
|
||||
if (desc == null)
|
||||
{
|
||||
var taskT = method.Invoke(Target, args) as Task<T>;
|
||||
var result = await taskT;
|
||||
return result;//返回结果
|
||||
}
|
||||
else
|
||||
{
|
||||
T result = default;
|
||||
//写入操作日志
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
var taskT = method.Invoke(Target, args) as Task<T>;
|
||||
result = await taskT;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
}
|
||||
WriteOperLog(method, args, desc, result, exception);
|
||||
if (exception != null)
|
||||
{
|
||||
throw exception;
|
||||
}
|
||||
else
|
||||
{
|
||||
return result;//返回结果
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void WriteOperLog(MethodInfo method, object[] args, OperDescAttribute desc, object result, Exception exception)
|
||||
{
|
||||
//写入操作日志
|
||||
var str = App.HttpContext?.Request?.Headers?.UserAgent;
|
||||
ClientInfo clientInfo = null;
|
||||
if (str.HasValue)
|
||||
{
|
||||
var uaParser = Parser.GetDefault();
|
||||
clientInfo = uaParser.Parse(str);
|
||||
}
|
||||
|
||||
StringBuilder stringBuilder = new();
|
||||
if (desc.IsRecordPar)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
var jsonParameters = parameters.Select((p, i) => $"\"{p.Name}\": {args[i].ToJsonString()}");
|
||||
stringBuilder.Append('{');
|
||||
stringBuilder.Append(string.Join(", ", jsonParameters));
|
||||
stringBuilder.Append('}');
|
||||
}
|
||||
var paramJson = stringBuilder.ToString();
|
||||
var resultJson = desc.IsRecordPar ? result?.ToJsonString() : null;
|
||||
//操作日志表实体
|
||||
var log = new SysOperateLog
|
||||
{
|
||||
Name = desc.Description,
|
||||
Category = desc.Catcategory,
|
||||
ExeStatus = LogConst.LOG_SUCCESS,
|
||||
OpIp = App.HttpContext?.Connection?.RemoteIpAddress?.MapToIPv4().ToString(),
|
||||
OpBrowser = clientInfo?.UA?.Family + clientInfo?.UA?.Major,
|
||||
OpOs = clientInfo?.OS?.Family + clientInfo?.OS?.Major,
|
||||
OpTime = DateTimeExtensions.CurrentDateTime,
|
||||
OpAccount = UserManager.UserAccount,
|
||||
ReqUrl = "",
|
||||
ReqMethod = LogConst.LOG_REQMETHOD,
|
||||
ResultJson = resultJson,
|
||||
ClassName = method.ReflectedType.Name,
|
||||
MethodName = method.Name,
|
||||
ParamJson = paramJson,
|
||||
VerificatId = UserManager.VerificatId.ToLong(),
|
||||
};
|
||||
//如果异常不为空
|
||||
if (exception != null)
|
||||
{
|
||||
log.ExeStatus = LogConst.LOG_FAIL;//操作状态为失败
|
||||
log.ExeMessage = exception.Source + ":" + exception.Message + Environment.NewLine + exception.StackTrace;
|
||||
}
|
||||
DbContext.Db.CopyNew().InsertableWithAttr(log).ExecuteCommand();//入库
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 权限操作常量
|
||||
/// </summary>
|
||||
public class AdminConst
|
||||
{
|
||||
#region 操作
|
||||
|
||||
/// <summary>
|
||||
/// 禁用操作
|
||||
/// </summary>
|
||||
public const string Disable = "禁用";
|
||||
|
||||
/// <summary>
|
||||
/// 启用操作
|
||||
/// </summary>
|
||||
public const string Enable = "启用";
|
||||
|
||||
/// <summary>
|
||||
/// 用户授权操作
|
||||
/// </summary>
|
||||
public const string GrantRole = "授权";
|
||||
|
||||
#endregion 操作
|
||||
}
|
@@ -1,83 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// Cache常量
|
||||
/// </summary>
|
||||
public class CacheConst
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 登录验证码缓存Key
|
||||
/// </summary>
|
||||
public const string LOGIN_CAPTCHA = "LOGIN_CAPTCHA";
|
||||
|
||||
/// <summary>
|
||||
/// 配置缓存Key
|
||||
/// </summary>
|
||||
public const string SYS_CONFIGCATEGORY = "SYS_CONFIGCATEGORY";
|
||||
|
||||
|
||||
#region OpenApi
|
||||
|
||||
/// <summary>
|
||||
/// OpenApi用户表缓存Key
|
||||
/// </summary>
|
||||
public const string CACHE_OPENAPIUSER = "CACHE_OPENAPIUSER";
|
||||
|
||||
/// <summary>
|
||||
/// OpenApi关系缓存Key
|
||||
/// </summary>
|
||||
public const string CACHE_OPENAPIUSERACCOUNT = "CACHE_OPENAPIUSERACCOUNT";
|
||||
|
||||
/// <summary>
|
||||
/// UserVerificat缓存Key
|
||||
/// </summary>
|
||||
public const string CACHE_OPENAPIUSERVERIFICAT = "CACHE_OPENAPIUSERVERIFICAT";
|
||||
|
||||
/// <summary>
|
||||
/// UserVerificat缓存Key
|
||||
/// </summary>
|
||||
public const string CACHE_USERVERIFICAT = "CACHE_USERVERIFICAT";
|
||||
|
||||
|
||||
#endregion OpenApi
|
||||
|
||||
/// <summary>
|
||||
/// 用户表缓存Key
|
||||
/// </summary>
|
||||
public const string CACHE_SYSUSER = "CACHE_SYSUSER";
|
||||
|
||||
/// <summary>
|
||||
/// 用户表缓存Key
|
||||
/// </summary>
|
||||
public const string CAHCE_SYSUSERACCOUNT = "CAHCE_SYSUSERACCOUNT";
|
||||
|
||||
/// <summary>
|
||||
/// 关系表缓存Key
|
||||
/// </summary>
|
||||
public const string CACHE_SYSRELATION = "CACHE_SYSRELATION";
|
||||
|
||||
/// <summary>
|
||||
/// 资源表缓存Key
|
||||
/// </summary>
|
||||
public const string CACHE_SYSRESOURCE = "CACHE_SYSRESOURCE";
|
||||
|
||||
/// <summary>
|
||||
/// 角色表缓存Key
|
||||
/// </summary>
|
||||
public const string CACHE_SYSROLE = "CACHE_SYSROLE";
|
||||
|
||||
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 其他分类常量
|
||||
/// </summary>
|
||||
public static class CateGoryConst
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// ThingsGateway.Admin
|
||||
/// </summary>
|
||||
public const string ThingsGatewayAdmin = "ThingsGateway.Admin";
|
||||
/// <summary>
|
||||
/// ThingsGateway.OpenApi
|
||||
/// </summary>
|
||||
public const string ThingsGatewayOpenApi = "ThingsGateway.OpenApi";
|
||||
|
||||
|
||||
|
||||
|
||||
#region 关系表
|
||||
|
||||
/// <summary>
|
||||
/// 用户主页
|
||||
/// </summary>
|
||||
public const string Relation_SYS_USER_DEFAULTRAZOR = "Relation_SYS_USER_DEFAULTRAZOR";
|
||||
|
||||
/// <summary>
|
||||
/// 用户工作台数据
|
||||
/// </summary>
|
||||
public const string Relation_SYS_USER_WORKBENCH_DATA = "SYS_USER_WORKBENCH_DATA";
|
||||
|
||||
/// <summary>
|
||||
/// 角色有哪些权限
|
||||
/// </summary>
|
||||
public const string Relation_SYS_ROLE_HAS_PERMISSION = "SYS_ROLE_HAS_PERMISSION";
|
||||
|
||||
/// <summary>
|
||||
/// 角色有哪些资源
|
||||
/// </summary>
|
||||
public const string Relation_SYS_ROLE_HAS_RESOURCE = "SYS_ROLE_HAS_RESOURCE";
|
||||
|
||||
/// <summary>
|
||||
/// 用户有哪些角色
|
||||
/// </summary>
|
||||
public const string Relation_SYS_USER_HAS_ROLE = "SYS_USER_HAS_ROLE";
|
||||
#endregion 关系表
|
||||
|
||||
}
|
@@ -1,96 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 配置常量
|
||||
/// </summary>
|
||||
public static class ConfigConst
|
||||
{
|
||||
/// <summary>
|
||||
/// 系统固定配置
|
||||
/// </summary>
|
||||
public const string SYS_CONFIGBASEDEFAULT = "SYS_CONFIGBASEDEFAULT";
|
||||
|
||||
/// <summary>
|
||||
/// 其他自定义配置
|
||||
/// </summary>
|
||||
public const string SYS_CONFIGOTHER = "SYS_CONFIGOTHER";
|
||||
|
||||
|
||||
#region config
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 版权标识
|
||||
/// </summary>
|
||||
public const string CONFIG_COPYRIGHT = "CONFIG_COPYRIGHT";
|
||||
|
||||
/// <summary>
|
||||
/// 版权跳转url
|
||||
/// </summary>
|
||||
public const string CONFIG_COPYRIGHT_URL = "CONFIG_COPYRIGHT_URL";
|
||||
/// <summary>
|
||||
/// 是否启用PageTab
|
||||
/// </summary>
|
||||
public const string CONFIG_PAGETAB = "CONFIG_PAGETAB";
|
||||
|
||||
/// <summary>
|
||||
/// 登录验证码开关
|
||||
/// </summary>
|
||||
public const string CONFIG_CAPTCHA_OPEN = "CONFIG_CAPTCHA_OPEN";
|
||||
|
||||
/// <summary>
|
||||
/// 默认用户密码
|
||||
/// </summary>
|
||||
public const string CONFIG_PASSWORD = "CONFIG_PASSWORD";
|
||||
|
||||
/// <summary>
|
||||
/// 登录界面的介绍文本
|
||||
/// </summary>
|
||||
public const string CONFIG_REMARK = "CONFIG_REMARK";
|
||||
|
||||
/// <summary>
|
||||
/// 单用户登录开关
|
||||
/// </summary>
|
||||
public const string CONFIG_SINGLE_OPEN = "CONFIG_SINGLE_OPEN";
|
||||
|
||||
/// <summary>
|
||||
/// swagger用户
|
||||
/// </summary>
|
||||
public const string CONFIG_SWAGGER_NAME = "CONFIG_SWAGGER_NAME";
|
||||
|
||||
/// <summary>
|
||||
/// swagger密码
|
||||
/// </summary>
|
||||
public const string CONFIG_SWAGGER_PASSWORD = "CONFIG_SWAGGER_PASSWORD";
|
||||
|
||||
/// <summary>
|
||||
/// 系统标题
|
||||
/// </summary>
|
||||
public const string CONFIG_TITLE = "CONFIG_TITLE";
|
||||
|
||||
/// <summary>
|
||||
/// 系统登录过期时间
|
||||
/// </summary>
|
||||
public const string CONFIG_VERIFICAT_EXPIRES = "CONFIG_VERIFICAT_EXPIRES";
|
||||
|
||||
/// <summary>
|
||||
/// Swagger是否需要登录
|
||||
/// </summary>
|
||||
public const string CONFIG_SWAGGERLOGIN_OPEN = "CONFIG_SWAGGERLOGIN_OPEN";
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 事件总线常量
|
||||
/// </summary>
|
||||
public class EventSubscriberConst
|
||||
{
|
||||
/// <summary>
|
||||
/// 清除用户缓存
|
||||
/// </summary>
|
||||
public const string ClearUserCache = "清除用户缓存";
|
||||
|
||||
/// <summary>
|
||||
/// 页面登录
|
||||
/// </summary>
|
||||
public const string Login = "登录";
|
||||
|
||||
/// <summary>
|
||||
/// OpenApi登录
|
||||
/// </summary>
|
||||
public const string LoginOpenApi = "OpenApi登录";
|
||||
|
||||
/// <summary>
|
||||
/// 后台登出
|
||||
/// </summary>
|
||||
public const string Logout = "退出";
|
||||
|
||||
/// <summary>
|
||||
/// OpenApi登出
|
||||
/// </summary>
|
||||
public const string LogoutOpenApi = "OpenApi退出";
|
||||
|
||||
|
||||
|
||||
}
|
@@ -1,69 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 日志常量
|
||||
/// </summary>
|
||||
public class LogConst
|
||||
{
|
||||
#region 日志表
|
||||
|
||||
/// <summary>
|
||||
/// 登录
|
||||
/// </summary>
|
||||
public const string LOG_LOGIN = "LOGIN";
|
||||
|
||||
/// <summary>
|
||||
/// 登出
|
||||
/// </summary>
|
||||
public const string LOG_LOGOUT = "LOGOUT";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 第三方登录
|
||||
/// </summary>
|
||||
public const string LOG_OPENAPILOGIN = "OPENAPILOGIN";
|
||||
|
||||
/// <summary>
|
||||
/// 第三方登出
|
||||
/// </summary>
|
||||
public const string LOG_OPENAPILOGOUT = "OPENAPILOGOUT";
|
||||
|
||||
/// <summary>
|
||||
/// 第三方操作来源
|
||||
/// </summary>
|
||||
public const string LOG_OPENAPIOPERATE = "OPENAPIOPERATE";
|
||||
|
||||
/// <summary>
|
||||
/// 操作分类
|
||||
/// </summary>
|
||||
public const string LOG_OPERATE = "OPERATE";
|
||||
|
||||
/// <summary>
|
||||
/// 内部操作来源
|
||||
/// </summary>
|
||||
public const string LOG_REQMETHOD = "BLAZORSERVER";
|
||||
|
||||
/// <summary>
|
||||
/// 操作成功
|
||||
/// </summary>
|
||||
public const string LOG_SUCCESS = "SUCCESS";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 操作失败
|
||||
/// </summary>
|
||||
public const string LOG_FAIL = "FAIL";
|
||||
#endregion 日志表
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 资源表常量
|
||||
/// </summary>
|
||||
public class ResourceConst
|
||||
{
|
||||
/// <summary>
|
||||
/// 系统内置编码
|
||||
/// </summary>
|
||||
public const string System = "system";
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 角色常量
|
||||
/// </summary>
|
||||
public class RoleConst
|
||||
{
|
||||
/// <summary>
|
||||
/// 超级管理员
|
||||
/// </summary>
|
||||
public const string SuperAdmin = "superAdmin";
|
||||
|
||||
#region 关系表
|
||||
|
||||
/// <summary>
|
||||
/// 角色有哪些权限
|
||||
/// </summary>
|
||||
public const string Relation_SYS_ROLE_HAS_PERMISSION = "SYS_ROLE_HAS_PERMISSION";
|
||||
|
||||
/// <summary>
|
||||
/// 角色有哪些资源
|
||||
/// </summary>
|
||||
public const string Relation_SYS_ROLE_HAS_RESOURCE = "SYS_ROLE_HAS_RESOURCE";
|
||||
|
||||
/// <summary>
|
||||
/// 用户有哪些角色
|
||||
/// </summary>
|
||||
public const string Relation_SYS_USER_HAS_ROLE = "SYS_USER_HAS_ROLE";
|
||||
|
||||
#endregion 关系表
|
||||
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
global using Furion;
|
||||
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.IO;
|
||||
global using System.Linq;
|
||||
global using System.Threading;
|
||||
global using System.Threading.Tasks;
|
||||
|
||||
global using ThingsGateway.Admin.Core;
|
||||
global using ThingsGateway.Core;
|
||||
global using ThingsGateway.Foundation.Core;
|
@@ -1,68 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.Schedule;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <inheritdoc cref="IJobPersistence"/>
|
||||
public class JobPersistence : IJobPersistence
|
||||
{
|
||||
private readonly IServiceScope _serviceScope;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public JobPersistence(IServiceScopeFactory serviceScopeFactory)
|
||||
{
|
||||
_serviceScope = serviceScopeFactory.CreateScope();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
_serviceScope?.Dispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnChanged(PersistenceContext context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 作业计划初始化通知
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public SchedulerBuilder OnLoading(SchedulerBuilder builder)
|
||||
{
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnTriggerChanged(PersistenceTriggerContext context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 作业调度服务启动时
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<SchedulerBuilder> Preload()
|
||||
{
|
||||
// 获取所有定义的作业
|
||||
var allJobs = App.EffectiveTypes.ScanToBuilders().ToList();
|
||||
return allJobs;
|
||||
}
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.Schedule;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 清理日志作业任务
|
||||
/// </summary>
|
||||
[JobDetail("job_log", Description = "清理访问/操作日志", GroupName = "default", Concurrent = false)]
|
||||
[Daily(TriggerId = "trigger_log", Description = "清理访问/操作日志", RunOnStart = true)]
|
||||
public class LogJob : IJob
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
|
||||
{
|
||||
var db = DbContext.Db.CopyNew();
|
||||
var daysAgo = App.GetConfig<int?>("Logging:LogJob:DaysAgo") ?? 30;
|
||||
await db.DeleteableWithAttr<SysVisitLog>().Where(u => u.CreateTime < DateTimeExtensions.CurrentDateTime.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); // 删除访问日志
|
||||
await db.DeleteableWithAttr<SysOperateLog>().Where(u => u.CreateTime < DateTimeExtensions.CurrentDateTime.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); // 删除操作日志
|
||||
}
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 登录事件参数
|
||||
/// </summary>
|
||||
public class LoginOpenApiEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// 时间
|
||||
/// </summary>
|
||||
public DateTime DateTime = DateTimeExtensions.CurrentDateTime;
|
||||
|
||||
/// <summary>
|
||||
/// 登录设备
|
||||
/// </summary>
|
||||
public AuthDeviceTypeEnum Device { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 过期时间(分)
|
||||
/// </summary>
|
||||
public int Expire { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ip地址
|
||||
/// </summary>
|
||||
public string Ip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户信息
|
||||
/// </summary>
|
||||
public OpenApiUser OpenApiUser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 验证Id
|
||||
/// </summary>
|
||||
public long VerificatId { get; set; }
|
||||
}
|
@@ -1,52 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.EventBus;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 认证模块事件总线
|
||||
/// </summary>
|
||||
public class OpenApiAuthEventSubscriber : IEventSubscriber, ISingleton
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录事件
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
[EventSubscribe(EventSubscriberConst.LoginOpenApi)]
|
||||
public async Task LoginOpenApi(EventHandlerExecutingContext context)
|
||||
{
|
||||
LoginOpenApiEvent loginEvent = (LoginOpenApiEvent)context.Source.Payload;//获取参数
|
||||
OpenApiUser openApiUser = loginEvent.OpenApiUser;
|
||||
var db = DbContext.Db.CopyNew();
|
||||
#region 重新赋值属性,设置本次登录信息为最新的信息
|
||||
|
||||
db.Tracking(openApiUser);//创建跟踪,只更新修改字段
|
||||
openApiUser.LastLoginDevice = openApiUser.LatestLoginDevice;
|
||||
openApiUser.LastLoginIp = openApiUser.LatestLoginIp;
|
||||
openApiUser.LastLoginTime = openApiUser.LatestLoginTime;
|
||||
openApiUser.LatestLoginDevice = loginEvent.Device.ToString();
|
||||
openApiUser.LatestLoginIp = loginEvent.Ip;
|
||||
openApiUser.LatestLoginTime = loginEvent.DateTime;
|
||||
|
||||
#endregion 重新赋值属性,设置本次登录信息为最新的信息
|
||||
|
||||
//更新用户信息
|
||||
if (await db.UpdateableWithAttr(openApiUser).ExecuteCommandAsync() > 0)
|
||||
{
|
||||
App.GetService<MemoryCache>().Set(CacheConst.CACHE_OPENAPIUSER + openApiUser.Id, openApiUser, false); //更新Cache信息
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 登录输入参数
|
||||
/// </summary>
|
||||
public class LoginOpenApiInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 账号
|
||||
///</summary>
|
||||
[Required(ErrorMessage = "账号不能为空"), MinLength(3, ErrorMessage = "账号不能少于4个字符")]
|
||||
public string Account { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
///</summary>
|
||||
[Required(ErrorMessage = "密码不能为空"), MinLength(3, ErrorMessage = "密码不能少于3个字符")]
|
||||
public string Password { get; set; }
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 登录返回参数
|
||||
/// </summary>
|
||||
public class LoginOpenApiOutput : BaseLoginOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// TOKEN
|
||||
/// </summary>
|
||||
public string Token { get; set; }
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 登录服务
|
||||
/// </summary>
|
||||
public interface IOpenApiAuthService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录
|
||||
/// </summary>
|
||||
/// <param name="input">登录参数</param>
|
||||
/// <returns>Token信息</returns>
|
||||
Task<LoginOpenApiOutput> LoginOpenApiAsync(LoginOpenApiInput input);
|
||||
/// <summary>
|
||||
/// 登出
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task LogoutAsync();
|
||||
}
|
@@ -1,172 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DataEncryption;
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.EventBus;
|
||||
using Furion.FriendlyException;
|
||||
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <inheritdoc cref="IOpenApiAuthService"/>
|
||||
public class OpenApiAuthService : IOpenApiAuthService, ITransient
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IEventPublisher _eventPublisher;
|
||||
private readonly IOpenApiUserService _openApiUserService;
|
||||
private readonly IVerificatService _verificatService;
|
||||
|
||||
/// <inheritdoc cref="IOpenApiAuthService"/>
|
||||
public OpenApiAuthService(
|
||||
IEventPublisher eventPublisher,
|
||||
IOpenApiUserService openApiUserService,
|
||||
IVerificatService verificatService,
|
||||
IConfigService configService)
|
||||
{
|
||||
_verificatService = verificatService;
|
||||
_eventPublisher = eventPublisher;
|
||||
_openApiUserService = openApiUserService;
|
||||
_configService = configService;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<LoginOpenApiOutput> LoginOpenApiAsync(LoginOpenApiInput input)
|
||||
{
|
||||
var password = input.Password;
|
||||
var userInfo = await _openApiUserService.GetUserByAccountAsync(input.Account);//获取用户信息
|
||||
if (userInfo == null) throw Oops.Bah("用户不存在");//用户不存在
|
||||
if (userInfo.Password != password) throw Oops.Bah("账号密码错误");//账号密码错误
|
||||
return await PrivateLoginOpenApiAsync(userInfo);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task LogoutAsync()
|
||||
{
|
||||
//获取用户信息
|
||||
var userinfo = await _openApiUserService.GetUserByAccountAsync(UserManager.UserAccount);
|
||||
if (userinfo != null)
|
||||
{
|
||||
LoginOpenApiEvent loginEvent = new()
|
||||
{
|
||||
Ip = App.HttpContext.GetRemoteIpAddressToIPv4(),
|
||||
OpenApiUser = userinfo,
|
||||
VerificatId = UserManager.VerificatId.ToLong(),
|
||||
};
|
||||
await RemoveVerificatFromCacheAsync(loginEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<VerificatInfo>> GetVerificatInfos(long userId)
|
||||
{
|
||||
List<VerificatInfo> verificatInfos = await _verificatService.GetOpenApiVerificatIdAsync(userId);
|
||||
return verificatInfos;
|
||||
}
|
||||
|
||||
private async Task<LoginOpenApiOutput> PrivateLoginOpenApiAsync(OpenApiUser openApiUser)
|
||||
{
|
||||
if (openApiUser.UserEnable == false) throw Oops.Bah("账号已停用");//账号冻结
|
||||
var sessionid = YitIdHelper.NextId();
|
||||
var expire = (await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_VERIFICAT_EXPIRES)).ConfigValue.ToInt();
|
||||
//生成Token
|
||||
var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
|
||||
{
|
||||
{ClaimConst.UserId, openApiUser.Id},
|
||||
{ClaimConst.Account, openApiUser.Account},
|
||||
{ ClaimConst.VerificatId, sessionid.ToString()},
|
||||
{ ClaimConst.IsOpenApi, true},
|
||||
}, expire);
|
||||
// 生成刷新Token令牌
|
||||
var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, expire * 2);
|
||||
// 设置Swagger自动登录
|
||||
App.HttpContext.SigninToSwagger(accessToken);
|
||||
// 设置响应报文头
|
||||
App.HttpContext.SetTokensOfResponseHeaders(accessToken, refreshToken);
|
||||
//登录事件参数
|
||||
var logingEvent = new LoginOpenApiEvent
|
||||
{
|
||||
Ip = App.HttpContext.GetRemoteIpAddressToIPv4(),
|
||||
Device = AuthDeviceTypeEnum.Api,
|
||||
Expire = expire,
|
||||
OpenApiUser = openApiUser,
|
||||
VerificatId = sessionid
|
||||
};
|
||||
|
||||
await WriteVerificatToCacheAsync(logingEvent);//写入verificat到cache
|
||||
await _eventPublisher.PublishAsync(EventSubscriberConst.LoginOpenApi, logingEvent); //发布登录事件总线
|
||||
//返回结果
|
||||
return new LoginOpenApiOutput { VerificatId = sessionid, Token = accessToken, Account = openApiUser.Account };
|
||||
}
|
||||
|
||||
private async Task RemoveVerificatFromCacheAsync(LoginOpenApiEvent loginEvent)
|
||||
{
|
||||
//获取verificat列表
|
||||
var verificatInfos = await GetVerificatInfos(loginEvent.OpenApiUser.Id);
|
||||
if (verificatInfos != null)
|
||||
{
|
||||
//获取当前用户的verificat
|
||||
var verificat = verificatInfos.Where(it => it.Id == loginEvent.VerificatId).FirstOrDefault();
|
||||
if (verificat != null)
|
||||
verificatInfos.Remove(verificat);
|
||||
//更新verificat列表
|
||||
await _verificatService.SetOpenApiVerificatIdAsync(loginEvent.OpenApiUser.Id, verificatInfos);
|
||||
}
|
||||
await App.HttpContext?.SignOutAsync();
|
||||
App.HttpContext?.SignoutToSwagger();
|
||||
}
|
||||
|
||||
private async Task WriteVerificatToCacheAsync(LoginOpenApiEvent loginEvent)
|
||||
{
|
||||
//获取verificat列表
|
||||
List<VerificatInfo> verificatInfos = await GetVerificatInfos(loginEvent.OpenApiUser.Id);
|
||||
var verificatTimeout = loginEvent.DateTime.AddMinutes(loginEvent.Expire);
|
||||
//生成verificat信息
|
||||
var verificatInfo = new VerificatInfo
|
||||
{
|
||||
Device = loginEvent.Device.ToString(),
|
||||
Expire = loginEvent.Expire,
|
||||
VerificatTimeout = verificatTimeout,
|
||||
Id = loginEvent.VerificatId,
|
||||
UserId = loginEvent.OpenApiUser.Id,
|
||||
};
|
||||
if (verificatInfos != null)
|
||||
{
|
||||
bool isSingle = false;//默认不开启单用户登录
|
||||
var singleConfig = await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SINGLE_OPEN);//获取系统单用户登录选项
|
||||
if (singleConfig != null) isSingle = singleConfig.ConfigValue.ToBool(false);//如果配置不为空则设置单用户登录选项为系统配置的值
|
||||
|
||||
//判断是否单用户登录
|
||||
if (isSingle)
|
||||
{
|
||||
verificatInfos = verificatInfos.ToList();//去掉当前登录类型的verificat
|
||||
verificatInfos.Add(verificatInfo);//添加到列表
|
||||
}
|
||||
else
|
||||
{
|
||||
verificatInfos.Add(verificatInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
verificatInfos = new List<VerificatInfo> { verificatInfo };//直接就一个
|
||||
}
|
||||
|
||||
//添加到verificat列表
|
||||
await _verificatService.SetOpenApiVerificatIdAsync(loginEvent.OpenApiUser.Id, verificatInfos);
|
||||
}
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 会话分页查询
|
||||
/// </summary>
|
||||
public class OpenApiSessionPageInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
[Description("账号")]
|
||||
public string Account { get; set; }
|
||||
/// <summary>
|
||||
/// 最新登录IP
|
||||
/// </summary>
|
||||
[Description("最新登录IP")]
|
||||
public string LatestLoginIp { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 退出参数
|
||||
/// </summary>
|
||||
public class OpenApiExitVerificatInput : BaseIdInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证ID列表
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "VerificatIds不能为空")]
|
||||
public List<long> VerificatIds { get; set; }
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 会话输出
|
||||
/// </summary>
|
||||
public class OpenApiSessionOutput : PrimaryKeyEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// 账号
|
||||
///</summary>
|
||||
[Description("账号")]
|
||||
[DataTable(Order = 1, IsShow = true, Sortable = true)]
|
||||
public virtual string Account { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最新登录ip
|
||||
///</summary>
|
||||
[Description("最新登录ip")]
|
||||
[DataTable(Order = 2, IsShow = true, Sortable = true)]
|
||||
public string LatestLoginIp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最新登录时间
|
||||
///</summary>
|
||||
[Description("最新登录时间")]
|
||||
[DataTable(Order = 3, IsShow = true, Sortable = true)]
|
||||
public DateTime? LatestLoginTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 令牌数量
|
||||
/// </summary>
|
||||
[Description("令牌数量")]
|
||||
[DataTable(Order = 4, IsShow = true, Sortable = false)]
|
||||
public int VerificatCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 令牌信息集合
|
||||
/// </summary>
|
||||
[Description("令牌列表")]
|
||||
public List<VerificatInfo> VerificatSignList { get; set; }
|
||||
}
|
@@ -1,40 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 会话管理服务
|
||||
/// </summary>
|
||||
public interface IOpenApiSessionService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 强退会话
|
||||
/// </summary>
|
||||
/// <param name="input">用户ID</param>
|
||||
Task ExitSessionAsync(long input);
|
||||
|
||||
/// <summary>
|
||||
/// 强退cookie
|
||||
/// </summary>
|
||||
/// <param name="input">cookie列表</param>
|
||||
Task ExitVerificatAsync(OpenApiExitVerificatInput input);
|
||||
|
||||
/// <summary>
|
||||
/// B端会话分页查询
|
||||
/// </summary>
|
||||
/// <param name="input">查询参数</param>
|
||||
/// <returns>B端会话列表</returns>
|
||||
Task<ISqlSugarPagedList<OpenApiSessionOutput>> PageAsync(OpenApiSessionPageInput input);
|
||||
}
|
@@ -1,106 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="IOpenApiSessionService"/>
|
||||
/// </summary>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class OpenApiSessionService : DbRepository<OpenApiUser>, IOpenApiSessionService
|
||||
{
|
||||
|
||||
private readonly IVerificatService _verificatService;
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc cref="IOpenApiSessionService"/>
|
||||
public OpenApiSessionService(IVerificatService verificatService)
|
||||
{
|
||||
_verificatService = verificatService;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("强退OPENAPI会话")]
|
||||
public async Task ExitSessionAsync(long input)
|
||||
{
|
||||
//从列表中删除
|
||||
await _verificatService.SetOpenApiVerificatIdAsync(input, new());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("强退OPENAPI令牌")]
|
||||
public async Task ExitVerificatAsync(OpenApiExitVerificatInput input)
|
||||
{
|
||||
//获取该用户的verificat信息
|
||||
List<VerificatInfo> verificatInfos = await _verificatService.GetOpenApiVerificatIdAsync(input.Id);
|
||||
//当前需要踢掉用户的verificat
|
||||
var setVerificats = verificatInfos.Where(it => !input.VerificatIds.Contains(it.Id)).ToList();
|
||||
await _verificatService.SetOpenApiVerificatIdAsync(input.Id, setVerificats);//如果还有verificat则更新verificat
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取verificat剩余时间信息
|
||||
/// </summary>
|
||||
/// <param name="verificatInfos">verificat列表</param>
|
||||
private static void GetVerificatInfos(ref List<VerificatInfo> verificatInfos)
|
||||
{
|
||||
verificatInfos = verificatInfos.ToList();
|
||||
verificatInfos.ForEach(it =>
|
||||
{
|
||||
var now = DateTimeExtensions.CurrentDateTime;
|
||||
it.VerificatRemain = now.GetDiffTime(it.VerificatTimeout);//获取时间差
|
||||
var verificatSecond = it.VerificatTimeout.AddMinutes(-it.Expire).ToLong();//颁发时间转为时间戳
|
||||
var timeoutSecond = it.VerificatTimeout.ToLong();//过期时间转为时间戳
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ISqlSugarPagedList<OpenApiSessionOutput>> PageAsync(OpenApiSessionPageInput input)
|
||||
{
|
||||
var query = Context.Queryable<OpenApiUser>()
|
||||
.WhereIF(!string.IsNullOrEmpty(input.Account), it => it.Account.Contains(input.Account))//根据账号查询
|
||||
.WhereIF(!string.IsNullOrEmpty(input.LatestLoginIp), it => it.LatestLoginIp.Contains(input.LatestLoginIp))//根据IP查询
|
||||
.OrderBy(it => it.LatestLoginTime, OrderByType.Desc)
|
||||
.Select<OpenApiSessionOutput>()
|
||||
.Mapper(async it =>
|
||||
{
|
||||
var verificatInfos = await _verificatService.GetVerificatIdAsync(it.Id);
|
||||
if (verificatInfos != null)
|
||||
{
|
||||
GetVerificatInfos(ref verificatInfos);//获取剩余时间
|
||||
it.VerificatCount = verificatInfos.Count;//令牌数量
|
||||
it.VerificatSignList = verificatInfos;//令牌列表
|
||||
}
|
||||
else
|
||||
{
|
||||
it.VerificatSignList = new();
|
||||
}
|
||||
|
||||
});
|
||||
for (int i = input.SortField.Count - 1; i >= 0; i--)
|
||||
{
|
||||
query = query.OrderByIF(!string.IsNullOrEmpty(input.SortField[i]), $"{input.SortField[i]} {(input.SortDesc[i] ? "desc" : "asc")}");
|
||||
}
|
||||
|
||||
var pageInfo = await query.ToPagedListAsync(input.Current, input.Size);//分页
|
||||
pageInfo.Records = pageInfo.Records.OrderByDescending(it => it.VerificatCount);
|
||||
return pageInfo;
|
||||
}
|
||||
|
||||
}
|
@@ -1,148 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// Api授权资源树
|
||||
/// </summary>
|
||||
public class OpenApiPermissionTreeSelector
|
||||
{
|
||||
/// <summary>
|
||||
/// 接口描述
|
||||
/// </summary>
|
||||
[Description("Api说明")]
|
||||
public string ApiName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 路由名称
|
||||
/// </summary>
|
||||
[Description("Api路径")]
|
||||
public string ApiRoute { get; set; }
|
||||
/// <summary>
|
||||
/// 子节点
|
||||
/// </summary>
|
||||
public List<OpenApiPermissionTreeSelector> Children { get; set; } = new();
|
||||
/// <summary>
|
||||
/// ID
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
/// <summary>
|
||||
/// 父ID
|
||||
/// </summary>
|
||||
public long ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限名称
|
||||
/// </summary>
|
||||
[Description("权限名称")]
|
||||
public string PermissionName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 多个树转列表
|
||||
/// </summary>
|
||||
public static List<OpenApiPermissionTreeSelector> TreeToList(IList<OpenApiPermissionTreeSelector> data)
|
||||
{
|
||||
List<OpenApiPermissionTreeSelector> list = new();
|
||||
foreach (var item in data)
|
||||
{
|
||||
list.Add(item);
|
||||
if (item.Children != null && item.Children.Count > 0)
|
||||
{
|
||||
list.AddRange(TreeToList(item.Children));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加用户参数
|
||||
/// </summary>
|
||||
public class OpenApiUserAddInput : OpenApiUser
|
||||
{
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "账号不能为空"), MinLength(3, ErrorMessage = "账号不能少于4个字符")]
|
||||
public override string Account { get; set; }
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "密码不能为空"), MinLength(2, ErrorMessage = "密码不能少于3个字符")]
|
||||
public override string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public override bool UserEnable { get; set; } = true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编辑用户参数
|
||||
/// </summary>
|
||||
public class OpenApiUserEditInput : OpenApiUser
|
||||
{
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "账号不能为空"), MinLength(3, ErrorMessage = "账号不能少于4个字符")]
|
||||
public override string Account { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
[MinValue(1, ErrorMessage = "Id不能为空")]
|
||||
public override long Id { get; set; }
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "密码不能为空"), MinLength(2, ErrorMessage = "密码不能少于3个字符")]
|
||||
public override string Password { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户分页查询参数
|
||||
/// </summary>
|
||||
public class OpenApiUserPageInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 动态查询条件
|
||||
/// </summary>
|
||||
public Expressionable<SysUser> Expression { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户授权参数
|
||||
/// </summary>
|
||||
public class OpenApiUserGrantPermissionInput
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Id不能为空")]
|
||||
public long? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 授权权限信息
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "PermissionList不能为空")]
|
||||
public List<string> PermissionList { get; set; }
|
||||
}
|
@@ -1,104 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 用户服务
|
||||
/// </summary>
|
||||
public interface IOpenApiUserService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加用户
|
||||
/// </summary>
|
||||
/// <param name="input">添加参数</param>
|
||||
/// <returns></returns>
|
||||
Task AddAsync(OpenApiUserAddInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 删除用户
|
||||
/// </summary>
|
||||
/// <param name="input">Id列表</param>
|
||||
/// <returns></returns>
|
||||
Task DeleteAsync(params long[] input);
|
||||
|
||||
/// <summary>
|
||||
/// 从cache中删除用户信息
|
||||
/// </summary>
|
||||
/// <param name="ids">用户ID列表</param>
|
||||
void DeleteUserFromCache(params long[] ids);
|
||||
|
||||
/// <summary>
|
||||
/// 禁用用户
|
||||
/// </summary>
|
||||
/// <param name="input">用户Id</param>
|
||||
/// <returns></returns>
|
||||
Task DisableUserAsync(long input);
|
||||
|
||||
/// <summary>
|
||||
/// 编辑
|
||||
/// </summary>
|
||||
/// <param name="input">编辑参数</param>
|
||||
/// <returns></returns>
|
||||
Task EditAsync(OpenApiUserEditInput input);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 启用用户
|
||||
/// </summary>
|
||||
/// <param name="input">用户Id</param>
|
||||
/// <returns></returns>
|
||||
Task EnableUserAsync(long input);
|
||||
|
||||
/// <summary>
|
||||
///根据用户账号获取用户ID
|
||||
/// </summary>
|
||||
/// <param name="account">用户账号</param>
|
||||
/// <returns></returns>
|
||||
Task<long> GetIdByAccountAsync(string account);
|
||||
|
||||
/// <summary>
|
||||
/// 根据账号获取用户信息
|
||||
/// </summary>
|
||||
/// <param name="account">用户名</param>
|
||||
/// <returns>用户信息</returns>
|
||||
Task<OpenApiUser> GetUserByAccountAsync(string account);
|
||||
/// <summary>
|
||||
/// 根据ID获取用户信息
|
||||
/// </summary>
|
||||
/// <param name="Id"></param>
|
||||
/// <returns></returns>
|
||||
Task<OpenApiUser> GetUsertByIdAsync(long Id);
|
||||
|
||||
/// <summary>
|
||||
/// 给用户授权
|
||||
/// </summary>
|
||||
/// <param name="input">授权参数</param>
|
||||
/// <returns></returns>
|
||||
Task GrantRoleAsync(OpenApiUserGrantPermissionInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户拥有权限,返回的是服务方法名称
|
||||
/// </summary>
|
||||
/// <param name="input">用户ID</param>
|
||||
/// <returns></returns>
|
||||
Task<List<string>> OwnPermissionsAsync(BaseIdInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 用户分页查询
|
||||
/// </summary>
|
||||
/// <param name="input">查询参数</param>
|
||||
/// <returns>用户分页列表</returns>
|
||||
Task<ISqlSugarPagedList<OpenApiUser>> PageAsync(OpenApiUserPageInput input);
|
||||
}
|
@@ -1,284 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DataEncryption;
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.FriendlyException;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="IOpenApiUserService"/>
|
||||
/// </summary>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class OpenApiUserService : DbRepository<OpenApiUser>, IOpenApiUserService
|
||||
{
|
||||
private readonly IVerificatService _verificatService;
|
||||
private readonly IServiceScope _serviceScope;
|
||||
|
||||
/// <inheritdoc cref="IOpenApiUserService"/>
|
||||
public OpenApiUserService(
|
||||
IVerificatService verificatService, IServiceScopeFactory serviceScopeFactory
|
||||
)
|
||||
{
|
||||
_verificatService = verificatService;
|
||||
_serviceScope = serviceScopeFactory.CreateScope();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("添加用户")]
|
||||
public async Task AddAsync(OpenApiUserAddInput input)
|
||||
{
|
||||
var account_Id = await GetIdByAccountAsync(input.Account);
|
||||
if (account_Id > 0)
|
||||
throw Oops.Bah($"存在重复的账号:{input.Account}");
|
||||
|
||||
var openApiUser = input.Adapt<OpenApiUser>();//实体转换
|
||||
await InsertAsync(openApiUser);//添加数据
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("删除用户")]
|
||||
public async Task DeleteAsync(params long[] ids)
|
||||
{
|
||||
|
||||
//获取所有ID
|
||||
if (ids.Length > 0)
|
||||
{
|
||||
var result = await DeleteByIdsAsync(ids.Cast<object>().ToArray());
|
||||
if (result)
|
||||
{
|
||||
//从列表中删除
|
||||
foreach (var id in ids)
|
||||
{
|
||||
await _verificatService.SetOpenApiVerificatIdAsync(id, new());
|
||||
}
|
||||
DeleteUserFromCache(ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DeleteUserFromCache(params long[] ids)
|
||||
{
|
||||
var userIds = ids.Select(it => it.ToString()).ToArray();//id转string列表
|
||||
List<OpenApiUser> openApiUsers = new();
|
||||
foreach (var item in userIds)
|
||||
{
|
||||
var user = _serviceScope.ServiceProvider.GetService<MemoryCache>().Get<OpenApiUser>(CacheConst.CACHE_OPENAPIUSER + item, false);//获取用户列表
|
||||
openApiUsers.Add(user);
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Remove(CacheConst.CACHE_OPENAPIUSER + item);
|
||||
}
|
||||
openApiUsers = openApiUsers.Where(it => it != null).ToList();//过滤掉不存在的
|
||||
if (openApiUsers.Count > 0)
|
||||
{
|
||||
var accounts = openApiUsers.Select(it => it.Account).ToArray();//账号集合
|
||||
foreach (var item in accounts)
|
||||
{
|
||||
//删除账号
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Remove(CacheConst.CACHE_OPENAPIUSERACCOUNT + item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("禁用用户")]
|
||||
public async Task DisableUserAsync(long input)
|
||||
{
|
||||
var openApiUser = await GetUsertByIdAsync(input);//获取用户信息
|
||||
if (openApiUser != null)
|
||||
{
|
||||
if (await UpdateAsync(it => new OpenApiUser { UserEnable = false }, it => it.Id == input))
|
||||
{
|
||||
await _verificatService.SetOpenApiVerificatIdAsync(input, new());
|
||||
DeleteUserFromCache(input);//从cache删除用户信息
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("编辑用户")]
|
||||
public async Task EditAsync(OpenApiUserEditInput input)
|
||||
{
|
||||
await CheckInputAsync(input);//检查参数
|
||||
var exist = await GetUsertByIdAsync(input.Id);//获取用户信息
|
||||
if (exist != null)
|
||||
{
|
||||
var openApiUser = input.Adapt<OpenApiUser>();//实体转换
|
||||
openApiUser.Password = DESCEncryption.Encrypt(openApiUser.Password, DESCKeyConst.DESCKey);
|
||||
if (await Context.Updateable(openApiUser).IgnoreColumns(it =>
|
||||
new
|
||||
{
|
||||
//忽略更新字段
|
||||
it.LastLoginDevice,
|
||||
it.LastLoginIp,
|
||||
it.LastLoginTime,
|
||||
it.LatestLoginDevice,
|
||||
it.LatestLoginIp,
|
||||
it.LatestLoginTime
|
||||
}).ExecuteCommandAsync() > 0)//修改数据
|
||||
DeleteUserFromCache(openApiUser.Id);//用户缓存到cache
|
||||
}
|
||||
//编辑操作可能会修改用户密码等信息,认证时需要实时获取用户并验证
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("启用用户")]
|
||||
public async Task EnableUserAsync(long input)
|
||||
{
|
||||
//设置状态为启用
|
||||
if (await UpdateAsync(it => new OpenApiUser { UserEnable = true }, it => it.Id == input))
|
||||
DeleteUserFromCache(input);//从cache删除用户信息
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<long> GetIdByAccountAsync(string account)
|
||||
{
|
||||
//先从Cache拿
|
||||
var userId = _serviceScope.ServiceProvider.GetService<MemoryCache>().Get<long>(CacheConst.CACHE_OPENAPIUSERACCOUNT + account, false);
|
||||
if (userId == 0)
|
||||
{
|
||||
//单查获取用户账号对应ID
|
||||
userId = await GetFirstAsync(it => it.Account == account, it => it.Id);
|
||||
if (userId != 0)
|
||||
{
|
||||
//插入Cache
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Set(CacheConst.CACHE_OPENAPIUSERACCOUNT + account, userId, false);
|
||||
}
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<OpenApiUser> GetUserByAccountAsync(string account)
|
||||
{
|
||||
var userId = await GetIdByAccountAsync(account);//获取用户ID
|
||||
if (userId > 0)
|
||||
{
|
||||
var openApiUser = await GetUsertByIdAsync(userId);//获取用户信息
|
||||
if (openApiUser.Account == account)//这里做了比较用来限制大小写
|
||||
return openApiUser;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<OpenApiUser> GetUsertByIdAsync(long Id)
|
||||
{
|
||||
//先从Cache拿,需要获取新的对象,避免操作导致缓存中对象改变
|
||||
var openApiUser = _serviceScope.ServiceProvider.GetService<MemoryCache>().Get<OpenApiUser>(CacheConst.CACHE_OPENAPIUSER + Id.ToString(), true);
|
||||
if (openApiUser == null)
|
||||
{
|
||||
openApiUser = await Context.Queryable<OpenApiUser>()
|
||||
.Where(u => u.Id == Id)
|
||||
.FirstAsync();
|
||||
if (openApiUser != null)
|
||||
{
|
||||
//插入Cache
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Set(CacheConst.CACHE_OPENAPIUSER + openApiUser.Id.ToString(), openApiUser, true);
|
||||
}
|
||||
}
|
||||
return openApiUser;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("用户授权")]
|
||||
public async Task GrantRoleAsync(OpenApiUserGrantPermissionInput input)
|
||||
{
|
||||
var openApiUser = await GetUsertByIdAsync(input.Id.Value);//获取用户信息
|
||||
if (openApiUser != null)
|
||||
{
|
||||
openApiUser.PermissionCodeList = input.PermissionList;
|
||||
await CheckInputAsync(openApiUser);
|
||||
if (await Context.Updateable(openApiUser).IgnoreColumns(it =>
|
||||
new
|
||||
{
|
||||
//忽略更新字段
|
||||
it.Password,
|
||||
it.LastLoginDevice,
|
||||
it.LastLoginIp,
|
||||
it.LastLoginTime,
|
||||
it.LatestLoginDevice,
|
||||
it.LatestLoginIp,
|
||||
it.LatestLoginTime
|
||||
}).ExecuteCommandAsync() > 0)//修改数据
|
||||
DeleteUserFromCache(input.Id.Value);//从cache删除用户信息
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<string>> OwnPermissionsAsync(BaseIdInput input)
|
||||
{
|
||||
var openApiUser = await GetUsertByIdAsync(input.Id);//获取用户信息
|
||||
return openApiUser.PermissionCodeList;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ISqlSugarPagedList<OpenApiUser>> PageAsync(OpenApiUserPageInput input)
|
||||
{
|
||||
var query = Context.Queryable<OpenApiUser>()
|
||||
.WhereIF(!string.IsNullOrEmpty(input.SearchKey), u => u.Account.Contains(input.SearchKey));//根据关键字查询
|
||||
for (int i = input.SortField.Count - 1; i >= 0; i--)
|
||||
{
|
||||
query = query.OrderByIF(!string.IsNullOrEmpty(input.SortField[i]), $"{input.SortField[i]} {(input.SortDesc[i] ? "desc" : "asc")}");
|
||||
}
|
||||
query = query.OrderBy(it => it.SortCode);//排序
|
||||
query = query.OrderBy(u => u.Id);//排序
|
||||
|
||||
|
||||
var pageInfo = await query.ToPagedListAsync(input.Current, input.Size);//分页
|
||||
return pageInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查输入参数
|
||||
/// </summary>
|
||||
/// <param name="openApiUser"></param>
|
||||
private async Task CheckInputAsync(OpenApiUser openApiUser)
|
||||
{
|
||||
//判断账号重复,直接从cache拿
|
||||
var account_Id = await GetIdByAccountAsync(openApiUser.Account);
|
||||
if (account_Id > 0 && account_Id != openApiUser.Id)
|
||||
throw Oops.Bah($"存在重复的账号:{openApiUser.Account}");
|
||||
//如果手机号不是空
|
||||
if (!string.IsNullOrEmpty(openApiUser.Phone))
|
||||
{
|
||||
if (!openApiUser.Phone.MatchPhoneNumber())//验证手机格式
|
||||
throw Oops.Bah($"手机号码:{openApiUser.Phone} 格式错误");
|
||||
openApiUser.Phone = DESCEncryption.Encrypt(openApiUser.Phone, DESCKeyConst.DESCKey);
|
||||
}
|
||||
//如果邮箱不是空
|
||||
if (!string.IsNullOrEmpty(openApiUser.Email))
|
||||
{
|
||||
var ismatch = openApiUser.Email.MatchEmail();//验证邮箱格式
|
||||
if (!ismatch)
|
||||
throw Oops.Bah($"邮箱:{openApiUser.Email} 格式错误");
|
||||
if (await IsAnyAsync(it => it.Email == openApiUser.Email && it.Id != openApiUser.Id))
|
||||
throw Oops.Bah($"存在重复的邮箱:{openApiUser.Email}");
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"RECORDS": [
|
||||
{
|
||||
"Id": 444657867911429,
|
||||
"Category": "SYS_USER_HAS_ROLE",
|
||||
"ObjectId": 212725263002001,
|
||||
"TargetId": "212725263001001",
|
||||
"ExtJson": null
|
||||
},
|
||||
{
|
||||
"Id": 444657879060741,
|
||||
"Category": "SYS_USER_HAS_ROLE",
|
||||
"ObjectId": 201725263002001,
|
||||
"TargetId": "212725263001002",
|
||||
"ExtJson": null
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,564 +0,0 @@
|
||||
{
|
||||
"RECORDS": [
|
||||
{
|
||||
"Id": "100",
|
||||
"Title": "系统首页",
|
||||
"Icon": "mdi-home-account",
|
||||
"Name": "index",
|
||||
"Component": "/index",
|
||||
"Category": "SPA",
|
||||
"Code": "system",
|
||||
"ParentId": "0",
|
||||
"SortCode": "1",
|
||||
"TargetType": "SELF",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001",
|
||||
"Title": "权限管理",
|
||||
"Icon": "mdi-account-hard-hat",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "0",
|
||||
"SortCode": "4",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false",
|
||||
"UpdateTime": "2023-02-26 00:55:23.977",
|
||||
"UpdateUser": "superAdmin",
|
||||
"UpdateUserId": "212725263002001"
|
||||
},
|
||||
{
|
||||
"Id": "100001001",
|
||||
"Title": "用户管理",
|
||||
"Icon": "mdi-account-edit",
|
||||
"Name": "sysUser",
|
||||
"Component": "/admin/user",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "100001",
|
||||
"SortCode": "1",
|
||||
"TargetType": "SELF",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001002",
|
||||
"Title": "角色管理",
|
||||
"Icon": "mdi-account-hard-hat",
|
||||
"Name": "sysRole",
|
||||
"Component": "/admin/role",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "100001",
|
||||
"SortCode": "2",
|
||||
"TargetType": "SELF",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001003",
|
||||
"Title": "菜单管理",
|
||||
"Icon": "mdi-menu",
|
||||
"Name": "sysMenu",
|
||||
"Component": "/admin/menu",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "100001",
|
||||
"SortCode": "3",
|
||||
"TargetType": "SELF",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100002002",
|
||||
"Title": "访问日志",
|
||||
"Icon": "mdi-account-switch-outline",
|
||||
"Name": "sysVislog",
|
||||
"Component": "/admin/vislog",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "100002",
|
||||
"SortCode": "2",
|
||||
"TargetType": "SELF",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100002003",
|
||||
"Title": "操作日志",
|
||||
"Icon": "mdi-database-search-outline",
|
||||
"Name": "sysOplog",
|
||||
"Component": "/admin/oplog",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "100002",
|
||||
"SortCode": "3",
|
||||
"TargetType": "SELF",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100002010",
|
||||
"Title": "定时看板",
|
||||
"Icon": "mdi-database-cog-outline",
|
||||
"Name": "schedulePage",
|
||||
"Component": "/schedulePage",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "100002",
|
||||
"SortCode": "4",
|
||||
"TargetType": "SELF",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100002",
|
||||
"Title": "系统运维",
|
||||
"Icon": "mdi-cogs",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "0",
|
||||
"SortCode": "5",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false",
|
||||
"UpdateTime": "2023-02-26 00:55:33.503",
|
||||
"UpdateUser": "superAdmin",
|
||||
"UpdateUserId": "212725263002001"
|
||||
},
|
||||
{
|
||||
"Id": "100002001",
|
||||
"Title": "系统配置",
|
||||
"Icon": "mdi-cog-transfer-outline",
|
||||
"Name": "sysConfig",
|
||||
"Component": "/admin/config",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "100002",
|
||||
"SortCode": "1",
|
||||
"TargetType": "SELF",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100003",
|
||||
"Title": "第三方授权",
|
||||
"Icon": "mdi-transit-transfer",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "0",
|
||||
"SortCode": "6",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false",
|
||||
"UpdateTime": "2023-02-26 00:55:29.094",
|
||||
"UpdateUser": "superAdmin",
|
||||
"UpdateUserId": "212725263002001"
|
||||
},
|
||||
{
|
||||
"Id": "100003001",
|
||||
"Title": "令牌列表",
|
||||
"Icon": "mdi-transit-transfer",
|
||||
"Name": "sysOpenApiSession",
|
||||
"Component": "/admin/openapisession",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "100003",
|
||||
"SortCode": "1",
|
||||
"TargetType": "SELF",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100003002",
|
||||
"Title": "授权用户",
|
||||
"Icon": "mdi-transit-transfer",
|
||||
"Name": "sysOpenApiUser",
|
||||
"Component": "/admin/openapiuser",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "100003",
|
||||
"SortCode": "2",
|
||||
"TargetType": "SELF",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100003003",
|
||||
"Title": "接口文档",
|
||||
"Icon": "mdi-cog-transfer-outline",
|
||||
"Name": "swaggerUrl",
|
||||
"Component": "/api/index.html",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "100003",
|
||||
"SortCode": "3",
|
||||
"TargetType": "BLANK",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100002004",
|
||||
"Title": "会话管理",
|
||||
"Icon": "mdi-transit-transfer",
|
||||
"Name": "session",
|
||||
"Component": "/admin/session",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "100002",
|
||||
"SortCode": "4",
|
||||
"TargetType": "SELF",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001001001",
|
||||
"Title": "添加",
|
||||
"Name": "add",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysuseradd",
|
||||
"ParentId": "100001001",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001004",
|
||||
"Title": "单页管理",
|
||||
"Icon": "mdi-menu",
|
||||
"Name": "sysSpa",
|
||||
"Component": "/admin/spa",
|
||||
"Category": "MENU",
|
||||
"Code": "system",
|
||||
"ParentId": "100001",
|
||||
"SortCode": "4",
|
||||
"TargetType": "SELF",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001001002",
|
||||
"Title": "编辑",
|
||||
"Name": "edit",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysuseredit",
|
||||
"ParentId": "100001001",
|
||||
"SortCode": "2",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001001003",
|
||||
"Title": "删除",
|
||||
"Name": "delete",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysuserdelete",
|
||||
"ParentId": "100001001",
|
||||
"SortCode": "3",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001002001",
|
||||
"Title": "添加",
|
||||
"Name": "add",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysroleadd",
|
||||
"ParentId": "100001002",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001002002",
|
||||
"Title": "编辑",
|
||||
"Name": "edit",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysroleedit",
|
||||
"ParentId": "100001002",
|
||||
"SortCode": "2",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001002003",
|
||||
"Title": "删除",
|
||||
"Name": "delete",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysroledelete",
|
||||
"ParentId": "100001002",
|
||||
"SortCode": "3",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001003001",
|
||||
"Title": "添加",
|
||||
"Name": "add",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysmenuadd",
|
||||
"ParentId": "100001003",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001003002",
|
||||
"Title": "编辑",
|
||||
"Name": "edit",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysmenuedit",
|
||||
"ParentId": "100001003",
|
||||
"SortCode": "2",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001003003",
|
||||
"Title": "删除",
|
||||
"Name": "delete",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysmenudelete",
|
||||
"ParentId": "100001003",
|
||||
"SortCode": "3",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001004001",
|
||||
"Title": "添加",
|
||||
"Name": "add",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysspaadd",
|
||||
"ParentId": "100001004",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001004002",
|
||||
"Title": "编辑",
|
||||
"Name": "edit",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysspaedit",
|
||||
"ParentId": "100001004",
|
||||
"SortCode": "2",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001004003",
|
||||
"Title": "删除",
|
||||
"Name": "delete",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysspadelete",
|
||||
"ParentId": "100001004",
|
||||
"SortCode": "3",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100002001001",
|
||||
"Title": "添加",
|
||||
"Name": "add",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysconfigadd",
|
||||
"ParentId": "100002001",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100002001002",
|
||||
"Title": "编辑",
|
||||
"Name": "edit",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysconfigedit",
|
||||
"ParentId": "100002001",
|
||||
"SortCode": "2",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100002001003",
|
||||
"Title": "删除",
|
||||
"Name": "delete",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysconfigdelete",
|
||||
"ParentId": "100002001",
|
||||
"SortCode": "3",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100003002001",
|
||||
"Title": "添加",
|
||||
"Name": "add",
|
||||
"Category": "BUTTON",
|
||||
"Code": "openapiuseradd",
|
||||
"ParentId": "100003002",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100003002002",
|
||||
"Title": "编辑",
|
||||
"Name": "edit",
|
||||
"Category": "BUTTON",
|
||||
"Code": "openapiuseredit",
|
||||
"ParentId": "100003002",
|
||||
"SortCode": "2",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100003002003",
|
||||
"Title": "删除",
|
||||
"Name": "delete",
|
||||
"Category": "BUTTON",
|
||||
"Code": "openapiuserdelete",
|
||||
"ParentId": "100003002",
|
||||
"SortCode": "3",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001001004",
|
||||
"Title": "重置密码",
|
||||
"Name": "resetpassword",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysuserresetpassword",
|
||||
"ParentId": "100001001",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001001005",
|
||||
"Title": "角色授权",
|
||||
"Name": "perrole",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysuserperrole",
|
||||
"ParentId": "100001001",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001002004",
|
||||
"Title": "资源授权",
|
||||
"Name": "perresuorce",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysroleperresuorce",
|
||||
"ParentId": "100001002",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100001002005",
|
||||
"Title": "用户授权",
|
||||
"Name": "peruser",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysroleperuser",
|
||||
"ParentId": "100001002",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100002004004",
|
||||
"Title": "会话强退",
|
||||
"Name": "exit",
|
||||
"Category": "BUTTON",
|
||||
"Code": "syssessionexit",
|
||||
"ParentId": "100002004",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100002004005",
|
||||
"Title": "令牌删除",
|
||||
"Name": "verificatdelete",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysverificatdelete",
|
||||
"ParentId": "100002004",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100003001004",
|
||||
"Title": "会话强退",
|
||||
"Name": "exit",
|
||||
"Category": "BUTTON",
|
||||
"Code": "openapisessionexit",
|
||||
"ParentId": "100003001",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100003001005",
|
||||
"Title": "令牌删除",
|
||||
"Name": "verificatdelete",
|
||||
"Category": "BUTTON",
|
||||
"Code": "openapiverificatdelete",
|
||||
"ParentId": "100003001",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100002002003",
|
||||
"Title": "清空",
|
||||
"Name": "clear",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysoplogclear",
|
||||
"ParentId": "100002002",
|
||||
"SortCode": "3",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100002003003",
|
||||
"Title": "清空",
|
||||
"Name": "clear",
|
||||
"Category": "BUTTON",
|
||||
"Code": "sysvislogclear",
|
||||
"ParentId": "100002003",
|
||||
"SortCode": "3",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100003002004",
|
||||
"Title": "修改密码",
|
||||
"Name": "editpassword",
|
||||
"Category": "BUTTON",
|
||||
"Code": "openapiusereditpassword",
|
||||
"ParentId": "100003002",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "100003002005",
|
||||
"Title": "授权Api",
|
||||
"Name": "per",
|
||||
"Category": "BUTTON",
|
||||
"Code": "openapiuserper",
|
||||
"ParentId": "100003002",
|
||||
"SortCode": "1",
|
||||
"TargetType": "None",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "391545543004421",
|
||||
"Title": "个人中心",
|
||||
"Icon": "mdi-home-account",
|
||||
"Component": "/usercenter",
|
||||
"Category": "SPA",
|
||||
"Code": "391545542885637",
|
||||
"ParentId": "0",
|
||||
"SortCode": "2",
|
||||
"TargetType": "SELF",
|
||||
"CreateTime": "2023-03-02 19:42:55.6049703",
|
||||
"CreateUser": "superAdmin",
|
||||
"CreateUserId": "212725263002001",
|
||||
"IsDelete": "false",
|
||||
"UpdateTime": "2023-03-02 19:46:13.3919053",
|
||||
"UpdateUser": "superAdmin",
|
||||
"UpdateUserId": "212725263002001"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
@@ -1,145 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 系统配置种子数据
|
||||
/// </summary>
|
||||
public class SysConfigSeedData : ISqlSugarEntitySeedData<SysConfig>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<SysConfig> SeedData()
|
||||
{
|
||||
List<SysConfig> configList = new List<SysConfig>
|
||||
{
|
||||
new SysConfig
|
||||
{
|
||||
Id = 22222222222222,
|
||||
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
|
||||
ConfigKey = ConfigConst.CONFIG_SWAGGER_NAME,
|
||||
ConfigValue = "admin",
|
||||
Remark = "swagger账号",
|
||||
SortCode = 1,
|
||||
},
|
||||
|
||||
new SysConfig
|
||||
{
|
||||
Id = 22222222222223,
|
||||
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
|
||||
ConfigKey = ConfigConst.CONFIG_SWAGGER_PASSWORD,
|
||||
ConfigValue = "123456",
|
||||
Remark = "swagger密码",
|
||||
SortCode = 2,
|
||||
},
|
||||
|
||||
new SysConfig
|
||||
{
|
||||
Id = 22222222222224,
|
||||
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
|
||||
ConfigKey = ConfigConst.CONFIG_SWAGGERLOGIN_OPEN,
|
||||
ConfigValue = "false",
|
||||
Remark = "swagger开启登录",
|
||||
SortCode = 3,
|
||||
},
|
||||
|
||||
new SysConfig
|
||||
{
|
||||
Id = 22222222222226,
|
||||
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
|
||||
ConfigKey = ConfigConst.CONFIG_TITLE,
|
||||
ConfigValue = "ThingsGateway",
|
||||
Remark = "标题",
|
||||
SortCode = 5,
|
||||
},
|
||||
|
||||
new SysConfig
|
||||
{
|
||||
Id = 22222222222228,
|
||||
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
|
||||
ConfigKey = ConfigConst.CONFIG_COPYRIGHT,
|
||||
ConfigValue = "ThingsGateway ©2023 Diego",
|
||||
Remark = "系统版权",
|
||||
SortCode = 6,
|
||||
},
|
||||
|
||||
new SysConfig
|
||||
{
|
||||
Id = 22222222222299,
|
||||
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
|
||||
ConfigKey = ConfigConst.CONFIG_COPYRIGHT_URL,
|
||||
ConfigValue = "https://gitee.com/diego2098/ThingsGateway",
|
||||
Remark = "系统版权链接地址",
|
||||
SortCode = 7,
|
||||
},
|
||||
new SysConfig
|
||||
{
|
||||
Id = 22222222222229,
|
||||
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
|
||||
ConfigKey = ConfigConst.CONFIG_PAGETAB,
|
||||
ConfigValue = "true",
|
||||
Remark = "开启标签页",
|
||||
SortCode = 7,
|
||||
},
|
||||
new SysConfig
|
||||
{
|
||||
Id = 22222222222231,
|
||||
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
|
||||
ConfigKey = ConfigConst.CONFIG_PASSWORD,
|
||||
ConfigValue = "111111",
|
||||
Remark = "默认用户密码",
|
||||
SortCode = 8,
|
||||
},
|
||||
|
||||
new SysConfig
|
||||
{
|
||||
Id = 22222222222227,
|
||||
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
|
||||
ConfigKey = ConfigConst.CONFIG_VERIFICAT_EXPIRES,
|
||||
ConfigValue = "14400",
|
||||
Remark = "Verificat过期时间(分)",
|
||||
SortCode = 9,
|
||||
},
|
||||
|
||||
new SysConfig
|
||||
{
|
||||
Id = 22222222222232,
|
||||
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
|
||||
ConfigKey = ConfigConst.CONFIG_SINGLE_OPEN,
|
||||
ConfigValue = "false",
|
||||
Remark = "单用户登录开关",
|
||||
SortCode = 10,
|
||||
},
|
||||
|
||||
new SysConfig
|
||||
{
|
||||
Id = 22222222222230,
|
||||
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
|
||||
ConfigKey = ConfigConst.CONFIG_CAPTCHA_OPEN,
|
||||
ConfigValue = "true",
|
||||
Remark = "登录验证码开关",
|
||||
SortCode = 11,
|
||||
},
|
||||
|
||||
new SysConfig
|
||||
{
|
||||
Id = 22222222222225,
|
||||
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
|
||||
ConfigKey = ConfigConst.CONFIG_REMARK,
|
||||
ConfigValue = "边缘采集网关",
|
||||
Remark = "说明",
|
||||
SortCode = 12,
|
||||
}
|
||||
};
|
||||
return configList;
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 关系表种子数据
|
||||
/// </summary>
|
||||
public class SysRelationSeedData : ISqlSugarEntitySeedData<SysRelation>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<SysRelation> SeedData()
|
||||
{
|
||||
return SeedDataUtil.GetSeedData<SysRelation>("sys_relation.json");
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 资源表种子数据
|
||||
/// </summary>
|
||||
public class SysResourceSeedData : ISqlSugarEntitySeedData<SysResource>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<SysResource> SeedData()
|
||||
{
|
||||
return SeedDataUtil.GetSeedData<SysResource>("sys_resource.json");
|
||||
}
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 角色种子数据
|
||||
/// </summary>
|
||||
public class SysRoleSeedData : ISqlSugarEntitySeedData<SysRole>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<SysRole> SeedData()
|
||||
{
|
||||
List<SysRole> configList = new List<SysRole>
|
||||
{
|
||||
new SysRole
|
||||
{
|
||||
Id = 212725263001001,
|
||||
Code = RoleConst.SuperAdmin,
|
||||
Name = "超级管理员",
|
||||
SortCode = 1,
|
||||
},
|
||||
|
||||
new SysRole
|
||||
{
|
||||
Id = 212725263001002,
|
||||
Code = "admin",
|
||||
Name = "业务管理员",
|
||||
SortCode = 2,
|
||||
},
|
||||
};
|
||||
return configList;
|
||||
}
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 用户表种子数据
|
||||
/// </summary>
|
||||
public class SysUserSeedData : ISqlSugarEntitySeedData<SysUser>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<SysUser> SeedData()
|
||||
{
|
||||
List<SysUser> configList = new List<SysUser>
|
||||
{
|
||||
new SysUser
|
||||
{
|
||||
Id = 212725263002001,
|
||||
Account = RoleConst.SuperAdmin,
|
||||
Password = "111111",
|
||||
UserEnable = true,
|
||||
SortCode = 1,
|
||||
},
|
||||
|
||||
new SysUser
|
||||
{
|
||||
Id = 201725263002001,
|
||||
Account = "admin",
|
||||
Password = "111111",
|
||||
UserEnable = true,
|
||||
SortCode = 2,
|
||||
},
|
||||
};
|
||||
return configList;
|
||||
}
|
||||
}
|
@@ -1,26 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 即时通讯集线器
|
||||
/// </summary>
|
||||
public interface ISysHub
|
||||
{
|
||||
/// <summary>
|
||||
/// 退出登录
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
Task Logout(object context);
|
||||
}
|
@@ -1,112 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.InstantMessaging;
|
||||
|
||||
using Microsoft.AspNetCore.Http.Connections.Features;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="ISysHub"/>
|
||||
/// </summary>
|
||||
[MapHub(HubConst.SysHubUrl)]
|
||||
public class SysHub : Hub<ISysHub>
|
||||
{
|
||||
/// <summary>
|
||||
/// 分隔符
|
||||
/// </summary>
|
||||
public const string Separate = "_s_e_p_a_r_a_t_e_";
|
||||
|
||||
private readonly ILogger<ISysHub> _logger;
|
||||
private readonly IServiceScope _serviceScope;
|
||||
/// <inheritdoc cref="ISysHub"/>
|
||||
public SysHub(IServiceScopeFactory scopeFactory, ILogger<ISysHub> logger)
|
||||
{
|
||||
_serviceScope = scopeFactory.CreateScope();
|
||||
_logger = logger;
|
||||
}
|
||||
/// <summary>
|
||||
/// 连接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override async Task OnConnectedAsync()
|
||||
{
|
||||
var feature = Context.Features.Get<IHttpContextFeature>();
|
||||
var VerificatId = feature.HttpContext.Request.Headers[ClaimConst.VerificatId].FirstOrDefault().ToLong();
|
||||
|
||||
var userIdentifier = Context.UserIdentifier;//自定义的Id
|
||||
await UpdateVerificatAsync(userIdentifier, verificat: VerificatId);//更新cache
|
||||
await base.OnConnectedAsync();
|
||||
}
|
||||
/// <summary>
|
||||
/// 断开连接
|
||||
/// </summary>
|
||||
/// <param name="exception"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task OnDisconnectedAsync(Exception exception)
|
||||
{
|
||||
var userIdentifier = Context.UserIdentifier;//自定义的Id
|
||||
await UpdateVerificatAsync(userIdentifier, false);//更新cache
|
||||
await base.OnDisconnectedAsync(exception);
|
||||
}
|
||||
|
||||
#region 方法
|
||||
|
||||
/// <summary>
|
||||
/// 更新cache
|
||||
/// </summary>
|
||||
/// <param name="userIdentifier">用户id</param>
|
||||
/// <param name="verificat">上线时的验证id</param>
|
||||
/// <param name="isConnect">是否是上线</param>
|
||||
private async Task UpdateVerificatAsync(string userIdentifier, bool isConnect = true, long verificat = 0)
|
||||
{
|
||||
var userId = userIdentifier.Split(Separate)[0].ToLong();//分割取第一个
|
||||
if (userId > 0)
|
||||
{
|
||||
var _verificatService = _serviceScope.ServiceProvider.GetService<IVerificatService>();
|
||||
//获取cache当前用户的verificat信息列表
|
||||
List<VerificatInfo> verificatInfos = await _verificatService.GetVerificatIdAsync(userId);
|
||||
|
||||
if (verificatInfos != null)
|
||||
{
|
||||
if (isConnect)
|
||||
{
|
||||
//获取cache中当前verificat
|
||||
var verificatInfo = verificatInfos.Where(it => it.Id == verificat).FirstOrDefault();
|
||||
if (verificatInfo != null)
|
||||
{
|
||||
verificatInfo.ClientIds.Add(userIdentifier);//添加到客户端列表
|
||||
await _verificatService.SetVerificatIdAsync(userId, verificatInfos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//获取当前客户端ID所在的verificat信息
|
||||
var verificatInfo = verificatInfos.Where(it => it.ClientIds.Contains(userIdentifier)).FirstOrDefault();
|
||||
if (verificatInfo != null)
|
||||
{
|
||||
verificatInfo.ClientIds.RemoveWhere(it => it == userIdentifier);//从客户端列表删除
|
||||
await _verificatService.SetVerificatIdAsync(userId, verificatInfos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion 方法
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// AppStartup启动类
|
||||
/// </summary>
|
||||
[AppStartup(9997)]
|
||||
public class Startup : AppStartup
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置
|
||||
/// </summary>
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
|
||||
// 任务调度
|
||||
services.AddSchedule(options =>
|
||||
{
|
||||
options.AddPersistence<JobPersistence>();
|
||||
});
|
||||
|
||||
//事件总线
|
||||
services.AddEventBus();
|
||||
|
||||
}
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.EventBus;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 认证模块事件总线
|
||||
/// </summary>
|
||||
public class AuthEventSubscriber : IEventSubscriber, ISingleton
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录事件
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
[EventSubscribe(EventSubscriberConst.Login)]
|
||||
public async Task Login(EventHandlerExecutingContext context)
|
||||
{
|
||||
var loginEvent = (LoginEvent)context.Source.Payload;//获取参数
|
||||
var sysUser = loginEvent.SysUser;
|
||||
var db = DbContext.Db.CopyNew();
|
||||
|
||||
#region 重新赋值属性,设置本次登录信息为最新的信息
|
||||
|
||||
db.Tracking(sysUser);//创建跟踪,只更新修改字段
|
||||
sysUser.LastLoginDevice = sysUser.LatestLoginDevice;
|
||||
sysUser.LastLoginIp = sysUser.LatestLoginIp;
|
||||
sysUser.LastLoginTime = sysUser.LatestLoginTime;
|
||||
sysUser.LatestLoginDevice = loginEvent.Device.ToString();
|
||||
sysUser.LatestLoginIp = loginEvent.Ip;
|
||||
sysUser.LatestLoginTime = loginEvent.DateTime;
|
||||
|
||||
#endregion 重新赋值属性,设置本次登录信息为最新的信息
|
||||
|
||||
//更新用户信息
|
||||
if (await db.UpdateableWithAttr(sysUser).ExecuteCommandAsync() > 0)
|
||||
{
|
||||
App.GetService<MemoryCache>().Set(CacheConst.CACHE_SYSUSER + sysUser.Id, sysUser, false); //更新Cache信息
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,59 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.EventBus;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 用户模块事件总线
|
||||
/// </summary>
|
||||
public class UserEventSubscriber : IEventSubscriber, ISingleton
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="UserEventSubscriber"/>
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
public UserEventSubscriber(IServiceProvider services)
|
||||
{
|
||||
_services = services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据角色ID列表清除用户缓存
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
[EventSubscribe(EventSubscriberConst.ClearUserCache)]
|
||||
public async Task DeleteUserCacheByRoleIds(EventHandlerExecutingContext context)
|
||||
{
|
||||
var roleIds = (List<long>)context.Source.Payload;//获取角色ID
|
||||
// 创建新的作用域
|
||||
using var scope = _services.CreateScope();
|
||||
// 解析角色服务
|
||||
var relationService = scope.ServiceProvider.GetRequiredService<IRelationService>();
|
||||
//获取用户和角色关系
|
||||
var relations = await relationService.GetRelationListByTargetIdListAndCategoryAsync(roleIds.Select(it => it.ToString()).ToList(), CateGoryConst.Relation_SYS_USER_HAS_ROLE);
|
||||
if (relations.Count > 0)
|
||||
{
|
||||
var userIds = relations.Select(it => it.ObjectId).ToArray();//用户ID列表
|
||||
// 解析用户服务
|
||||
var userService = scope.ServiceProvider.GetRequiredService<ISysUserService>();
|
||||
//从缓存中删除
|
||||
userService.DeleteUserFromCache(userIds);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,240 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DataEncryption;
|
||||
using Furion.EventBus;
|
||||
using Furion.FriendlyException;
|
||||
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using System.Security.Claims;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <inheritdoc cref="IAuthService"/>
|
||||
public class AuthService : IAuthService
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IEventPublisher _eventPublisher;
|
||||
private readonly INoticeService _noticeService;
|
||||
private readonly IServiceScope _serviceScope;
|
||||
private readonly ISysUserService _userService;
|
||||
private readonly IVerificatService _verificatService;
|
||||
/// <inheritdoc cref="IAuthService"/>
|
||||
public AuthService(
|
||||
IEventPublisher eventPublisher,
|
||||
ISysUserService userService,
|
||||
IConfigService configService,
|
||||
IVerificatService verificatService,
|
||||
INoticeService noticeService, IServiceScopeFactory serviceScopeFactory
|
||||
)
|
||||
{
|
||||
_eventPublisher = eventPublisher;
|
||||
_userService = userService;
|
||||
_configService = configService;
|
||||
_verificatService = verificatService;
|
||||
_noticeService = noticeService;
|
||||
_serviceScope = serviceScopeFactory.CreateScope();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValidCodeOutput GetCaptchaInfo()
|
||||
{
|
||||
//生成验证码
|
||||
var captchInfo = new Random().Next(1111, 9999).ToString();
|
||||
//生成请求号,并将验证码放入cache
|
||||
var reqNo = YitIdHelper.NextId();
|
||||
//插入cache
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Set(CacheConst.LOGIN_CAPTCHA + reqNo, captchInfo, TimeSpan.FromMinutes(1), false);
|
||||
//返回验证码和请求号
|
||||
return new ValidCodeOutput { CodeValue = captchInfo, ValidCodeReqNo = reqNo };
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<SysUser> GetLoginUserAsync()
|
||||
{
|
||||
return await _userService.GetUserByIdAsync(UserManager.UserId);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<LoginOutput> LoginAsync(LoginInput input)
|
||||
{
|
||||
//判断是否有验证码
|
||||
var sysBase = await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_CAPTCHA_OPEN);
|
||||
|
||||
if (sysBase != null)//如果有这个配置项
|
||||
{
|
||||
if (sysBase.ConfigValue.ToBool(false))//如果需要验证码
|
||||
{
|
||||
//如果没填验证码,提示验证码不能为空
|
||||
if (input.ValidCode.IsNullOrEmpty() || input.ValidCodeReqNo == 0) throw Oops.Bah("验证码不能为空").StatusCode(410);
|
||||
ValidValidCode(input.ValidCode, input.ValidCodeReqNo);//校验验证码
|
||||
}
|
||||
}
|
||||
|
||||
var password = DESCEncryption.Decrypt(input.Password, DESCKeyConst.DESCKey); // 解密
|
||||
var userInfo = await _userService.GetUserByAccountAsync(input.Account) ?? throw Oops.Bah("用户不存在");//获取用户信息
|
||||
if (userInfo.Password != password) throw Oops.Bah("账号密码错误");//账号密码错误
|
||||
return await LoginAsync(userInfo, input.Device);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task LogoutAsync()
|
||||
{
|
||||
//获取用户信息
|
||||
var userinfo = await _userService.GetUserByAccountAsync(UserManager.UserAccount);
|
||||
if (userinfo != null)
|
||||
{
|
||||
LoginEvent loginEvent = new()
|
||||
{
|
||||
Ip = App.HttpContext.GetRemoteIpAddressToIPv4(),
|
||||
SysUser = userinfo,
|
||||
VerificatId = UserManager.VerificatId.ToLong(),
|
||||
};
|
||||
await RemoveVerificatAsync(loginEvent);//移除验证Id
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 校验验证码方法
|
||||
/// </summary>
|
||||
/// <param name="validCode">验证码</param>
|
||||
/// <param name="validCodeReqNo">请求号</param>
|
||||
/// <param name="isDelete">是否从Cache删除</param>
|
||||
private void ValidValidCode(string validCode, long validCodeReqNo, bool isDelete = true)
|
||||
{
|
||||
var code = _serviceScope.ServiceProvider.GetService<MemoryCache>().Get<string>(CacheConst.LOGIN_CAPTCHA + validCodeReqNo, false);//从cache拿数据
|
||||
if (isDelete) _serviceScope.ServiceProvider.GetService<MemoryCache>().Remove(CacheConst.LOGIN_CAPTCHA + validCodeReqNo);//删除验证码
|
||||
if (code != null)//如果有
|
||||
{
|
||||
//验证码如果不匹配直接抛错误,这里忽略大小写
|
||||
if (validCode.ToLower() != code.ToLower()) throw Oops.Bah("验证码错误");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Oops.Bah("验证码已过期");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行B端登录
|
||||
/// </summary>
|
||||
/// <param name="sysUser">用户信息</param>
|
||||
/// <param name="device">登录设备</param>
|
||||
/// <returns></returns>
|
||||
private async Task<LoginOutput> LoginAsync(SysUser sysUser, AuthDeviceTypeEnum device)
|
||||
{
|
||||
if (sysUser.UserEnable == false) throw Oops.Bah("账号已停用");//账号已停用
|
||||
|
||||
var sysBase = await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_VERIFICAT_EXPIRES);
|
||||
var sessionid = YitIdHelper.NextId();
|
||||
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
identity.AddClaim(new Claim(ClaimConst.VerificatId, sessionid.ToString()));
|
||||
identity.AddClaim(new Claim(ClaimConst.UserId, sysUser.Id.ToString()));
|
||||
identity.AddClaim(new Claim(ClaimConst.Account, sysUser.Account));
|
||||
identity.AddClaim(new Claim(ClaimConst.IsSuperAdmin, sysUser.RoleCodeList.Contains(RoleConst.SuperAdmin).ToString()));
|
||||
identity.AddClaim(new Claim(ClaimConst.IsOpenApi, false.ToString()));
|
||||
|
||||
var config = sysBase.ConfigValue.ToInt(2880);
|
||||
var diffTime = DateTimeExtensions.CurrentDateTime.AddMinutes(config);
|
||||
await App.HttpContext.SignInAsync(new ClaimsPrincipal(identity), new AuthenticationProperties()
|
||||
{
|
||||
IsPersistent = true,
|
||||
ExpiresUtc = diffTime,
|
||||
});
|
||||
|
||||
//登录事件参数
|
||||
var loginEvent = new LoginEvent
|
||||
{
|
||||
Ip = App.HttpContext.GetRemoteIpAddressToIPv4(),
|
||||
Device = device,
|
||||
Expire = config,
|
||||
SysUser = sysUser,
|
||||
VerificatId = sessionid,
|
||||
};
|
||||
|
||||
await SetVerificatAsync(loginEvent);//写入verificat
|
||||
|
||||
await _eventPublisher.PublishAsync(EventSubscriberConst.Login, loginEvent); //发布登录事件总线
|
||||
return new LoginOutput { VerificatId = sessionid, Account = sysUser.Account };
|
||||
}
|
||||
|
||||
|
||||
private async Task RemoveVerificatAsync(LoginEvent loginEvent)
|
||||
{
|
||||
//获取verificat列表
|
||||
List<VerificatInfo> verificatInfos = await _verificatService.GetVerificatIdAsync(loginEvent.SysUser.Id);
|
||||
if (verificatInfos != null)
|
||||
{
|
||||
//获取当前用户的verificat
|
||||
var verificat = verificatInfos.Where(it => it.Id == loginEvent.VerificatId).FirstOrDefault();
|
||||
if (verificat != null)
|
||||
verificatInfos.Remove(verificat);
|
||||
//更新verificat列表
|
||||
await _verificatService.SetVerificatIdAsync(loginEvent.SysUser.Id, verificatInfos);
|
||||
}
|
||||
await App.HttpContext?.SignOutAsync();
|
||||
App.HttpContext?.SignoutToSwagger();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入验证信息到缓存
|
||||
/// </summary>
|
||||
/// <param name="loginEvent"></param>
|
||||
/// <returns></returns>
|
||||
private async Task SetVerificatAsync(LoginEvent loginEvent)
|
||||
{
|
||||
//获取verificat列表
|
||||
List<VerificatInfo> verificatInfos = await _verificatService.GetVerificatIdAsync(loginEvent.SysUser.Id);
|
||||
var verificatTimeout = loginEvent.DateTime.AddMinutes(loginEvent.Expire);
|
||||
//生成verificat信息
|
||||
var verificatInfo = new VerificatInfo
|
||||
{
|
||||
Device = loginEvent.Device.ToString(),
|
||||
Expire = loginEvent.Expire,
|
||||
VerificatTimeout = verificatTimeout,
|
||||
Id = loginEvent.VerificatId,
|
||||
UserId = loginEvent.SysUser.Id,
|
||||
};
|
||||
if (verificatInfos != null)
|
||||
{
|
||||
bool isSingle = false;//默认不开启单用户登录
|
||||
|
||||
var singleConfig = await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SINGLE_OPEN);//获取系统单用户登录选项
|
||||
if (singleConfig != null) isSingle = singleConfig.ConfigValue.ToBool(false);//如果配置不为空则设置单用户登录选项为系统配置的值
|
||||
if (isSingle)//判断是否单用户登录
|
||||
{
|
||||
await _noticeService.LogoutAsync(loginEvent.SysUser.Id, verificatInfos.Where(it => it.Device == loginEvent.Device.ToString()).ToList(), "该账号已在别处登录!");//通知其他用户下线
|
||||
verificatInfos = verificatInfos.Where(it => it.Device != loginEvent.Device.ToString()).ToList();//去掉当前登录类型
|
||||
verificatInfos.Add(verificatInfo);//添加到列表
|
||||
}
|
||||
else
|
||||
{
|
||||
verificatInfos.Add(verificatInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
verificatInfos = new List<VerificatInfo> { verificatInfo };//直接就一个
|
||||
}
|
||||
|
||||
//添加到verificat列表
|
||||
await _verificatService.SetVerificatIdAsync(loginEvent.SysUser.Id, verificatInfos);
|
||||
}
|
||||
}
|
@@ -1,78 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 登录输入参数
|
||||
/// </summary>
|
||||
public class LoginInput : ValidCodeInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 账号
|
||||
///</summary>
|
||||
[Required(ErrorMessage = "账号不能为空"), MinLength(3, ErrorMessage = "账号不能少于4个字符")]
|
||||
public string Account { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备类型,默认PC
|
||||
/// </summary>
|
||||
/// <example>0</example>
|
||||
public AuthDeviceTypeEnum Device { get; set; } = AuthDeviceTypeEnum.PC;
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
///</summary>
|
||||
[Required(ErrorMessage = "密码不能为空"), MinLength(3, ErrorMessage = "密码不能少于3个字符")]
|
||||
public string Password { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 验证码输入
|
||||
/// </summary>
|
||||
public class ValidCodeInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证码
|
||||
/// </summary>
|
||||
public string ValidCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求号
|
||||
/// </summary>
|
||||
public long ValidCodeReqNo { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 登录设备类型枚举
|
||||
/// </summary>
|
||||
public enum AuthDeviceTypeEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// PC端
|
||||
/// </summary>
|
||||
[Description("PC端")]
|
||||
PC,
|
||||
|
||||
/// <summary>
|
||||
/// 移动端
|
||||
/// </summary>
|
||||
[Description("移动端")]
|
||||
APP,
|
||||
|
||||
/// <summary>
|
||||
/// Api
|
||||
/// </summary>
|
||||
[Description("Api")]
|
||||
Api,
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 登录返回参数
|
||||
/// </summary>
|
||||
public class BaseLoginOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
public string Account { get; set; }
|
||||
/// <summary>
|
||||
/// 验证ID
|
||||
/// </summary>
|
||||
public long VerificatId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证码值返回
|
||||
/// </summary>
|
||||
public class ValidCodeOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证码值
|
||||
/// </summary>
|
||||
public string CodeValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 验证码请求号
|
||||
/// </summary>
|
||||
public long ValidCodeReqNo { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 登录返回参数
|
||||
/// </summary>
|
||||
public class LoginOutput : BaseLoginOutput
|
||||
{
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 登录事件参数
|
||||
/// </summary>
|
||||
public class LoginEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// 时间
|
||||
/// </summary>
|
||||
public DateTime DateTime = DateTimeExtensions.CurrentDateTime;
|
||||
|
||||
/// <summary>
|
||||
/// 登录设备
|
||||
/// </summary>
|
||||
public AuthDeviceTypeEnum Device { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 过期时间(分)
|
||||
/// </summary>
|
||||
public int Expire { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ip地址
|
||||
/// </summary>
|
||||
public string Ip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户信息
|
||||
/// </summary>
|
||||
public SysUser SysUser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 验证Id
|
||||
/// </summary>
|
||||
public long VerificatId { get; set; }
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 权限校验服务
|
||||
/// </summary>
|
||||
public interface IAuthService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成验证码
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ValidCodeOutput GetCaptchaInfo();
|
||||
|
||||
/// <summary>
|
||||
/// 获取登录用户信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<SysUser> GetLoginUserAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 登录
|
||||
/// </summary>
|
||||
Task<LoginOutput> LoginAsync(LoginInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 退出登录
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task LogoutAsync();
|
||||
}
|
@@ -1,163 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.FriendlyException;
|
||||
|
||||
using Mapster;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="IButtonService"/>
|
||||
/// </summary>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class ButtonService : DbRepository<SysResource>, IButtonService
|
||||
{
|
||||
private readonly IRelationService _relationService;
|
||||
private readonly IResourceService _resourceService;
|
||||
|
||||
/// <inheritdoc cref="IButtonService"/>
|
||||
public ButtonService(
|
||||
IResourceService resourceService,
|
||||
IRelationService relationService
|
||||
)
|
||||
{
|
||||
_resourceService = resourceService;
|
||||
_relationService = relationService;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task AddAsync(ButtonAddInput input)
|
||||
{
|
||||
await CheckInputAsync(input);//检查参数
|
||||
var sysResource = input.Adapt<SysResource>();//实体转换
|
||||
if (await InsertAsync(sysResource))//插入数据
|
||||
_resourceService.RefreshCache(ResourceCategoryEnum.BUTTON);//刷新缓存
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("删除按钮")]
|
||||
public async Task DeleteAsync(params long[] input)
|
||||
{
|
||||
//获取所有ID
|
||||
var ids = input.ToList();
|
||||
//获取所有按钮集合
|
||||
var buttonList = await _resourceService.GetListByCategoryAsync(ResourceCategoryEnum.BUTTON);
|
||||
|
||||
#region 处理关系表角色资源信息
|
||||
|
||||
//获取所有菜单集合
|
||||
var menuList = await _resourceService.GetListByCategoryAsync(ResourceCategoryEnum.MENU);
|
||||
//获取按钮的父菜单id集合
|
||||
var parentIds = buttonList.Where(it => ids.Contains(it.Id)).Select(it => it.ParentId.ToString()).ToList();
|
||||
//获取关系表分类为SYS_ROLE_HAS_RESOURCE数据
|
||||
var roleResources = await _relationService.GetRelationByCategoryAsync(CateGoryConst.Relation_SYS_ROLE_HAS_RESOURCE);
|
||||
//获取相关关系表数据
|
||||
var relationList = roleResources
|
||||
.Where(it => parentIds.Contains(it.TargetId))//目标ID是父ID中
|
||||
.Where(it => it.ExtJson != null).ToList();//扩展信息不为空
|
||||
|
||||
//遍历关系表
|
||||
relationList.ForEach(it =>
|
||||
{
|
||||
var relationRoleResuorce = it.ExtJson.FromJsonString<RelationRoleResuorce>();//拓展信息转实体
|
||||
var buttonInfo = relationRoleResuorce.ButtonInfo;//获取按钮信息
|
||||
if (buttonInfo.Count > 0)
|
||||
{
|
||||
var diffArr = buttonInfo.Where(it => !buttonInfo.Contains(it)).ToList(); //找出不同的元素(即交集的补集)
|
||||
relationRoleResuorce.ButtonInfo = diffArr;//重新赋值按钮信息
|
||||
it.ExtJson = relationRoleResuorce.ToJsonString();//重新赋值拓展信息
|
||||
}
|
||||
});
|
||||
|
||||
#endregion 处理关系表角色资源信息
|
||||
|
||||
//事务
|
||||
var result = await itenant.UseTranAsync(async () =>
|
||||
{
|
||||
await DeleteByIdsAsync(ids.Cast<object>().ToArray());//删除按钮
|
||||
if (relationList.Count > 0)
|
||||
{
|
||||
await Context.Updateable(relationList).UpdateColumns(it => it.ExtJson).ExecuteCommandAsync();//修改拓展信息
|
||||
}
|
||||
});
|
||||
if (result.IsSuccess)//如果成功了
|
||||
{
|
||||
_resourceService.RefreshCache(ResourceCategoryEnum.BUTTON);//资源表按钮刷新缓存
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Oops.Oh(result.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("编辑按钮")]
|
||||
public async Task EditAsync(ButtonEditInput input)
|
||||
{
|
||||
await CheckInputAsync(input);//检查参数
|
||||
var sysResource = input.Adapt<SysResource>();//实体转换
|
||||
//事务
|
||||
var result = await itenant.UseTranAsync(async () =>
|
||||
{
|
||||
await UpdateAsync(sysResource); //更新按钮
|
||||
});
|
||||
if (result.IsSuccess)//如果成功了
|
||||
{
|
||||
_resourceService.RefreshCache(ResourceCategoryEnum.BUTTON);//资源表按钮刷新缓存
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Oops.Oh(result.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ISqlSugarPagedList<SysResource>> PageAsync(ButtonPageInput input)
|
||||
{
|
||||
var query = Context.Queryable<SysResource>()
|
||||
.Where(it => it.ParentId == input.ParentId && it.Category == ResourceCategoryEnum.BUTTON)
|
||||
.WhereIF(!string.IsNullOrEmpty(input.SearchKey), it => it.Title.Contains(input.SearchKey) || it.Component.Contains(input.SearchKey));//根据关键字查询
|
||||
for (int i = input.SortField.Count - 1; i >= 0; i--)
|
||||
{
|
||||
query = query.OrderByIF(!string.IsNullOrEmpty(input.SortField[i]), $"{input.SortField[i]} {(input.SortDesc[i] ? "desc" : "asc")}");
|
||||
}
|
||||
query = query.OrderBy(it => it.SortCode);//排序
|
||||
|
||||
var pageInfo = await query.ToPagedListAsync(input.Current, input.Size);//分页
|
||||
return pageInfo;
|
||||
}
|
||||
|
||||
#region 方法
|
||||
|
||||
/// <summary>
|
||||
/// 检查输入参数
|
||||
/// </summary>
|
||||
/// <param name="sysResource"></param>
|
||||
private async Task CheckInputAsync(SysResource sysResource)
|
||||
{
|
||||
//获取所有按钮和菜单
|
||||
var buttonList = await _resourceService.GetListByCategorysAsync(new List<ResourceCategoryEnum> { ResourceCategoryEnum.BUTTON, ResourceCategoryEnum.MENU });
|
||||
//判断code是否重复
|
||||
if (buttonList.Any(it => it.Code == sysResource.Code && it.Id != sysResource.Id))
|
||||
throw Oops.Bah($"存在重复的按钮编码:{sysResource.Code}");
|
||||
//判断菜单是否存在
|
||||
if (!buttonList.Any(it => it.Id == sysResource.ParentId))
|
||||
throw Oops.Bah($"不存在的父级菜单:{sysResource.ParentId}");
|
||||
sysResource.Category = ResourceCategoryEnum.BUTTON;//设置分类为按钮
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion 方法
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 添加按钮参数
|
||||
/// </summary>
|
||||
public class ButtonAddInput : SysResource
|
||||
{
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Code不能为空")]
|
||||
public override string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父ID
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "ParentId不能为空")]
|
||||
public override long ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Title不能为空")]
|
||||
public override string Title { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 按钮分页
|
||||
/// </summary>
|
||||
public class ButtonPageInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 父ID
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "ParentId不能为空")]
|
||||
public long? ParentId { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 按钮编辑
|
||||
/// </summary>
|
||||
public class ButtonEditInput : ButtonAddInput
|
||||
{
|
||||
/// <summary>
|
||||
/// ID
|
||||
/// </summary>
|
||||
[MinValue(1, ErrorMessage = "Id不能为空")]
|
||||
public override long Id { get; set; }
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 权限按钮服务
|
||||
/// </summary>
|
||||
public interface IButtonService : ITransient
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加按钮
|
||||
/// </summary>
|
||||
/// <param name="input">添加参数</param>
|
||||
/// <returns></returns>
|
||||
Task AddAsync(ButtonAddInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 删除按钮
|
||||
/// </summary>
|
||||
/// <param name="input">删除参数</param>
|
||||
/// <returns></returns>
|
||||
Task DeleteAsync(params long[] input);
|
||||
|
||||
/// <summary>
|
||||
/// 编辑按钮
|
||||
/// </summary>
|
||||
/// <param name="input">编辑参数</param>
|
||||
/// <returns></returns>
|
||||
Task EditAsync(ButtonEditInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 按钮分页查询
|
||||
/// </summary>
|
||||
/// <param name="input">查询条件</param>
|
||||
/// <returns>按钮分页列表</returns>
|
||||
Task<ISqlSugarPagedList<SysResource>> PageAsync(ButtonPageInput input);
|
||||
}
|
@@ -1,137 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.FriendlyException;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <inheritdoc cref="IConfigService"/>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class ConfigService : DbRepository<SysConfig>, IConfigService
|
||||
{
|
||||
private readonly IServiceScope _serviceScope;
|
||||
public ConfigService(IServiceScopeFactory serviceScopeFactory)
|
||||
{
|
||||
_serviceScope = serviceScopeFactory.CreateScope();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("编辑网关系统配置")]
|
||||
public async Task EditBatchAsync(List<SysConfig> sysConfigs)
|
||||
{
|
||||
if (await UpdateRangeAsync(sysConfigs))
|
||||
RefreshCache(sysConfigs.FirstOrDefault()?.Category);//刷新缓存
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("添加配置项")]
|
||||
public async Task AddAsync(ConfigAddInput input)
|
||||
{
|
||||
await CheckInputAsync(input);//检查
|
||||
var sysConfig = input.Adapt<SysConfig>();//实体转换
|
||||
if (await InsertAsync(sysConfig))//插入数据)
|
||||
RefreshCache(input.Category);//刷新缓存
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("删除配置项")]
|
||||
public async Task DeleteAsync(params long[] input)
|
||||
{
|
||||
await AsDeleteable().Where(it => input.Contains(it.Id)).ExecuteCommandAsync();
|
||||
RefreshCache(ConfigConst.SYS_CONFIGOTHER);//刷新缓存
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("编辑配置项")]
|
||||
public async Task EditAsync(ConfigEditInput input)
|
||||
{
|
||||
await CheckInputAsync(input);
|
||||
var sysConfig = input.Adapt<SysConfig>();//实体转换
|
||||
if (await UpdateAsync(sysConfig))//更新数据
|
||||
RefreshCache(input.Category);//刷新缓存
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<SysConfig> GetByConfigKeyAsync(string category, string configKey)
|
||||
{
|
||||
var configList = await GetListByCategoryAsync(category);//获取系统配置列表
|
||||
return configList.FirstOrDefault(it => it.ConfigKey == configKey);//根据configkey获取对应值
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SysConfig>> GetListByCategoryAsync(string category)
|
||||
{
|
||||
//先从Cache拿,需要获取新的对象,避免操作导致缓存中对象改变
|
||||
var configList = _serviceScope.ServiceProvider.GetService<MemoryCache>().Get<List<SysConfig>>(CacheConst.SYS_CONFIGCATEGORY + category, true);
|
||||
if (configList == null)
|
||||
{
|
||||
//cache没有再去数据可拿
|
||||
configList = await Context.Queryable<SysConfig>().Where(it => it.Category == category).OrderBy(it => it.SortCode).ToListAsync();//获取系统配置列表
|
||||
if (configList.Count > 0)
|
||||
{
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Set(CacheConst.SYS_CONFIGCATEGORY + category, configList, true);//如果不为空,插入cache
|
||||
}
|
||||
}
|
||||
return configList;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ISqlSugarPagedList<SysConfig>> PageAsync(ConfigPageInput input)
|
||||
{
|
||||
var query = Context.Queryable<SysConfig>()
|
||||
.Where(it => it.Category == ConfigConst.SYS_CONFIGOTHER)//自定义配置
|
||||
.WhereIF(!string.IsNullOrEmpty(input.SearchKey), it => it.ConfigKey.Contains(input.SearchKey) || it.ConfigKey.Contains(input.SearchKey));
|
||||
//根据关键字查询
|
||||
for (int i = input.SortField.Count - 1; i >= 0; i--)
|
||||
{
|
||||
query = query.OrderByIF(!string.IsNullOrEmpty(input.SortField[i]), $"{input.SortField[i]} {(input.SortDesc[i] ? "desc" : "asc")}");
|
||||
}
|
||||
query = query.OrderBy(it => it.SortCode);//排序
|
||||
|
||||
var pageInfo = await query.ToPagedListAsync(input.Current, input.Size);//分页
|
||||
return pageInfo;
|
||||
}
|
||||
|
||||
#region 方法
|
||||
|
||||
/// <summary>
|
||||
/// 检查输入参数,并设置分类为自定义分类
|
||||
/// </summary>
|
||||
/// <param name="sysConfig"></param>
|
||||
private async Task CheckInputAsync(SysConfig sysConfig)
|
||||
{
|
||||
var configs = await GetListByCategoryAsync(sysConfig.Category);//获取全部字典
|
||||
var hasSameKey = configs.Any(it => it.ConfigKey == sysConfig.ConfigKey && it.Id != sysConfig.Id);
|
||||
//判断是否从存在重复字典名
|
||||
if (hasSameKey)
|
||||
{
|
||||
throw Oops.Bah($"存在重复的配置键:{sysConfig.ConfigKey}");
|
||||
}
|
||||
sysConfig.Category = ConfigConst.SYS_CONFIGOTHER;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新缓存
|
||||
/// </summary>
|
||||
/// <param name="category">分类</param>
|
||||
/// <returns></returns>
|
||||
private void RefreshCache(string category)
|
||||
{
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Remove(CacheConst.SYS_CONFIGCATEGORY + category);//cache删除
|
||||
}
|
||||
|
||||
#endregion 方法
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 添加配置参数
|
||||
/// </summary>
|
||||
public class ConfigAddInput : SysConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 分类
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Category不能为空")]
|
||||
public override string Category { get; set; } = ConfigConst.SYS_CONFIGOTHER;
|
||||
|
||||
/// <summary>
|
||||
/// 配置键
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "configKey不能为空")]
|
||||
public override string ConfigKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 配置值
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "ConfigValue不能为空")]
|
||||
public override string ConfigValue { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编辑配置参数
|
||||
/// </summary>
|
||||
public class ConfigEditInput : ConfigAddInput
|
||||
{
|
||||
/// <summary>
|
||||
/// ID
|
||||
/// </summary>
|
||||
[MinValue(1, ErrorMessage = "Id不能为空")]
|
||||
public override long Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置分页参数
|
||||
/// </summary>
|
||||
public class ConfigPageInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 分类
|
||||
/// </summary>
|
||||
[Description("分类")]
|
||||
public string Category { get; set; }
|
||||
}
|
||||
|
@@ -1,70 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 系统配置服务
|
||||
/// </summary>
|
||||
public interface IConfigService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 批量编辑系统配置
|
||||
/// </summary>
|
||||
/// <param name="configs">配置列表</param>
|
||||
/// <returns></returns>
|
||||
Task EditBatchAsync(List<SysConfig> configs);
|
||||
/// <summary>
|
||||
/// 新增自定义配置
|
||||
/// </summary>
|
||||
/// <param name="input">新增参数</param>
|
||||
/// <returns></returns>
|
||||
Task AddAsync(ConfigAddInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 删除自定义配置
|
||||
/// </summary>
|
||||
/// <param name="input">删除</param>
|
||||
/// <returns></returns>
|
||||
Task DeleteAsync(params long[] input);
|
||||
|
||||
/// <summary>
|
||||
/// 修改自定义配置
|
||||
/// </summary>
|
||||
/// <param name="input">修改参数</param>
|
||||
/// <returns></returns>
|
||||
Task EditAsync(ConfigEditInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 根据分类和配置键获配置
|
||||
/// </summary>
|
||||
/// <param name="category">分类</param>
|
||||
/// <param name="configKey">配置键</param>
|
||||
/// <returns>配置信息</returns>
|
||||
Task<SysConfig> GetByConfigKeyAsync(string category, string configKey);
|
||||
|
||||
/// <summary>
|
||||
/// 根据分类获取配置列表
|
||||
/// </summary>
|
||||
/// <param name="category">分类名称</param>
|
||||
/// <returns>配置列表</returns>
|
||||
Task<List<SysConfig>> GetListByCategoryAsync(string category);
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询自定义配置
|
||||
/// </summary>
|
||||
/// <param name="input">查询参数</param>
|
||||
/// <returns>其他配置列表</returns>
|
||||
Task<ISqlSugarPagedList<SysConfig>> PageAsync(ConfigPageInput input);
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.FriendlyException;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="IFileService"/>
|
||||
/// </summary>
|
||||
public class FileService : IFileService
|
||||
{
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ImportVerification(IBrowserFile file, int maxSzie = 300, string[] allowTypes = null)
|
||||
{
|
||||
|
||||
if (file == null) throw Oops.Bah("文件不能为空");
|
||||
if (file.Size > maxSzie * 1024 * 1024) throw Oops.Bah($"文件大小不允许超过{maxSzie}M");
|
||||
var fileSuffix = Path.GetExtension(file.Name).ToLower().Split(".")[1]; // 文件后缀
|
||||
string[] allowTypeS = allowTypes ?? new string[] { "xlsx" };//允许上传的文件类型
|
||||
if (!allowTypeS.Contains(fileSuffix)) throw Oops.Bah(errorMessage: "文件格式错误");
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 文件管理服务
|
||||
/// </summary>
|
||||
public interface IFileService : ITransient
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 验证上传文件
|
||||
/// </summary>
|
||||
/// <param name="file">文件</param>
|
||||
/// <param name="maxSzie">最大体积(M)</param>
|
||||
/// <param name="allowTypes">允许上传类型</param>
|
||||
void ImportVerification(IBrowserFile file, int maxSzie = 30, string[] allowTypes = null);
|
||||
|
||||
|
||||
|
||||
}
|
@@ -1,91 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 添加菜单参数
|
||||
/// </summary>
|
||||
public class MenuAddInput : SysResource, IValidatableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 路径
|
||||
/// </summary>
|
||||
public override string Component { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Icon不能为空")]
|
||||
public override string Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父ID
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "ParentId不能为空")]
|
||||
public override long ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单类型
|
||||
/// </summary>
|
||||
public override TargetTypeEnum TargetType { get; set; } = TargetTypeEnum.SELF;
|
||||
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Title不能为空")]
|
||||
public override string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 特殊验证
|
||||
/// </summary>
|
||||
/// <param name="validationContext"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
//如果菜单类型是菜单
|
||||
if (TargetType == TargetTypeEnum.SELF)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Component))
|
||||
yield return new ValidationResult("路径不能为空", new[] { nameof(Component) });
|
||||
}
|
||||
//设置分类为菜单
|
||||
Category = ResourceCategoryEnum.MENU;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编辑菜单输入参数
|
||||
/// </summary>
|
||||
public class MenuEditInput : MenuAddInput
|
||||
{
|
||||
/// <summary>
|
||||
/// ID
|
||||
/// </summary>
|
||||
[MinValue(1, ErrorMessage = "Id不能为空")]
|
||||
public override long Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 菜单树查询参数
|
||||
/// </summary>
|
||||
public class MenuPageInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 父ID
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "ParentId不能为空")]
|
||||
public long ParentId { get; set; }
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 菜单服务
|
||||
/// </summary>
|
||||
public interface IMenuService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加菜单
|
||||
/// </summary>
|
||||
/// <param name="input">添加参数</param>
|
||||
/// <returns></returns>
|
||||
Task AddAsync(MenuAddInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 删除菜单
|
||||
/// </summary>
|
||||
/// <param name="input">删除菜单参数</param>
|
||||
/// <returns></returns>
|
||||
Task DeleteAsync(params long[] input);
|
||||
|
||||
/// <summary>
|
||||
/// 详情
|
||||
/// </summary>
|
||||
/// <param name="input">id</param>
|
||||
/// <returns>详细信息</returns>
|
||||
Task<SysResource> DetailAsync(BaseIdInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 编辑菜单
|
||||
/// </summary>
|
||||
/// <param name="input">菜单编辑参数</param>
|
||||
/// <returns></returns>
|
||||
Task EditAsync(MenuEditInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 根据模块获取菜单树
|
||||
/// </summary>
|
||||
/// <param name="input">菜单树查询参数</param>
|
||||
/// <returns>菜单树列表</returns>
|
||||
Task<List<SysResource>> TreeAsync(MenuPageInput input);
|
||||
}
|
@@ -1,166 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.FriendlyException;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="IMenuService"/>
|
||||
/// </summary>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class MenuService : DbRepository<SysResource>, IMenuService
|
||||
{
|
||||
private readonly IRelationService _relationService;
|
||||
private readonly IResourceService _resourceService;
|
||||
private readonly IRoleService _roleService;
|
||||
/// <inheritdoc cref="IMenuService"/>
|
||||
public MenuService(IResourceService resourceService, IRelationService relationService, IRoleService roleService)
|
||||
{
|
||||
_roleService = roleService;
|
||||
_resourceService = resourceService;
|
||||
_relationService = relationService;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("添加菜单")]
|
||||
public async Task AddAsync(MenuAddInput input)
|
||||
{
|
||||
await CheckInputAsync(input);//检查参数
|
||||
var sysResource = input.Adapt<SysResource>();//实体转换
|
||||
|
||||
if (await InsertAsync(sysResource))//插入数据
|
||||
_resourceService.RefreshCache(ResourceCategoryEnum.MENU);//刷新菜单缓存
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("删除菜单")]
|
||||
public async Task DeleteAsync(params long[] input)
|
||||
{
|
||||
//获取所有ID
|
||||
var ids = input.ToList();
|
||||
if (ids.Count > 0)
|
||||
{
|
||||
//获取所有菜单和按钮
|
||||
var resourceList = await _resourceService.GetListByCategorysAsync(new List<ResourceCategoryEnum> { ResourceCategoryEnum.MENU, ResourceCategoryEnum.BUTTON });
|
||||
//找到要删除的菜单
|
||||
var sysResources = resourceList.Where(it => ids.Contains(it.Id)).ToList();
|
||||
//查找内置菜单
|
||||
var system = sysResources.Where(it => it.Code == ResourceConst.System).FirstOrDefault();
|
||||
if (system != null)
|
||||
throw Oops.Bah($"不可删除系统菜单:{system.Title}");
|
||||
//需要删除的资源ID列表
|
||||
var resourceIds = new List<long>();
|
||||
//遍历菜单列表
|
||||
sysResources.ForEach(it =>
|
||||
{
|
||||
//获取菜单所有子节点
|
||||
var child = _resourceService.GetChildListById(resourceList, it.Id, false);
|
||||
//将子节点ID添加到删除资源ID列表
|
||||
resourceIds.AddRange(child.Select(it => it.Id).ToList());
|
||||
resourceIds.Add(it.Id);//添加到删除资源ID列表
|
||||
});
|
||||
ids.AddRange(resourceIds);//添加到删除ID列表
|
||||
//事务
|
||||
var result = await itenant.UseTranAsync(async () =>
|
||||
{
|
||||
await DeleteByIdsAsync(ids.Cast<object>().ToArray());//删除菜单和按钮
|
||||
await Context.Deleteable<SysRelation>()//关系表删除对应SYS_ROLE_HAS_RESOURCE
|
||||
.Where(it => it.Category == CateGoryConst.Relation_SYS_ROLE_HAS_RESOURCE && resourceIds.Contains(SqlFunc.ToInt64(it.TargetId))).ExecuteCommandAsync();
|
||||
});
|
||||
if (result.IsSuccess)//如果成功了
|
||||
{
|
||||
_resourceService.RefreshCache(ResourceCategoryEnum.MENU);//资源表菜单刷新缓存
|
||||
_resourceService.RefreshCache(ResourceCategoryEnum.BUTTON);//资源表按钮刷新缓存
|
||||
_relationService.RefreshCache(CateGoryConst.Relation_SYS_ROLE_HAS_RESOURCE);//关系表刷新缓存
|
||||
}
|
||||
else
|
||||
{
|
||||
//写日志
|
||||
throw Oops.Oh(result.ErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<SysResource> DetailAsync(BaseIdInput input)
|
||||
{
|
||||
var sysResources = await _resourceService.GetListByCategoryAsync(ResourceCategoryEnum.MENU);
|
||||
var resource = sysResources.Where(it => it.Id == input.Id).FirstOrDefault();
|
||||
return resource;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("编辑菜单")]
|
||||
public async Task EditAsync(MenuEditInput input)
|
||||
{
|
||||
await CheckInputAsync(input);//检查参数
|
||||
var sysResource = input.Adapt<SysResource>();//实体转换
|
||||
if (await UpdateAsync(sysResource))//更新数据
|
||||
{
|
||||
_resourceService.RefreshCache(ResourceCategoryEnum.MENU);//刷新菜单缓存
|
||||
//需要更新资源权限,因为地址可能改变,页面权限需要更改
|
||||
await _roleService.RefreshResourceAsync(input.Id);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<SysResource>> TreeAsync(MenuPageInput input)
|
||||
{
|
||||
//获取所有菜单
|
||||
var sysResources = await _resourceService.GetListByCategoryAsync(ResourceCategoryEnum.MENU);
|
||||
sysResources = sysResources
|
||||
.Where(it => it.ParentId == input.ParentId)
|
||||
.WhereIF(!string.IsNullOrEmpty(input.SearchKey), it => it.Title == input.SearchKey)//根据关键字查找
|
||||
.ToList();
|
||||
//构建菜单树
|
||||
var tree = _resourceService.ResourceListToTree(sysResources, input.ParentId);
|
||||
return tree;
|
||||
}
|
||||
|
||||
#region 方法
|
||||
|
||||
/// <summary>
|
||||
/// 检查输入参数
|
||||
/// </summary>
|
||||
/// <param name="sysResource"></param>
|
||||
private async Task CheckInputAsync(SysResource sysResource)
|
||||
{
|
||||
//获取所有菜单列表
|
||||
var menList = await _resourceService.GetListByCategoryAsync(ResourceCategoryEnum.MENU);
|
||||
//判断是否有同级且同名的菜单
|
||||
if (menList.Any(it => it.ParentId == sysResource.ParentId && it.Title == sysResource.Title && it.Id != sysResource.Id))
|
||||
throw Oops.Bah($"存在重复的菜单名称:{sysResource.Title}");
|
||||
if (sysResource.ParentId != 0)
|
||||
{
|
||||
//获取父级,判断父级ID正不正确
|
||||
var parent = menList.Where(it => it.Id == sysResource.ParentId).FirstOrDefault();
|
||||
if (parent != null)
|
||||
{
|
||||
if (parent.Id == sysResource.Id)
|
||||
throw Oops.Bah($"上级菜单不能选择自己");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Oops.Bah($"上级菜单不存在:{sysResource.ParentId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion 方法
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 通知服务
|
||||
/// </summary>
|
||||
public interface INoticeService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 通知用户下线
|
||||
/// </summary>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <param name="verificatInfos">验证列表</param>
|
||||
/// <param name="message">消息内容</param>
|
||||
/// <returns></returns>
|
||||
Task LogoutAsync(long userId, List<VerificatInfo> verificatInfos, string message);
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="INoticeService"/>
|
||||
/// </summary>
|
||||
public class NoticeService : INoticeService
|
||||
{
|
||||
private readonly IServiceScope _serviceScope;
|
||||
public NoticeService(IServiceScopeFactory serviceScopeFactory)
|
||||
{
|
||||
_serviceScope = serviceScopeFactory.CreateScope();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public async Task LogoutAsync(long userId, List<VerificatInfo> verificatInfos, string message)
|
||||
{
|
||||
//客户端ID列表
|
||||
var clientIds = new List<string>();
|
||||
//遍历cancellationToken列表获取客户端ID列表
|
||||
verificatInfos.ForEach(it =>
|
||||
{
|
||||
clientIds.AddRange(it.ClientIds);
|
||||
});
|
||||
//获取signalr实例
|
||||
var signalr = _serviceScope.ServiceProvider.GetService<IHubContext<SysHub, ISysHub>>();
|
||||
//发送其他客户端登录消息
|
||||
await signalr.Clients.Users(clientIds).Logout(message);
|
||||
}
|
||||
}
|
@@ -1,27 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 操作日志分页输入
|
||||
/// </summary>
|
||||
public class OperateLogPageInput : VisitLogPageInput
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// 操作日志分页输入
|
||||
/// </summary>
|
||||
public class OperateLogInput : VisitLogInput
|
||||
{
|
||||
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 操作日志服务
|
||||
/// </summary>
|
||||
public interface IOperateLogService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据分类删除操作日志
|
||||
/// </summary>
|
||||
/// <param name="category">分类名称</param>
|
||||
/// <returns></returns>
|
||||
Task DeleteAsync(params string[] category);
|
||||
/// <summary>
|
||||
/// 导出后台日志
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<MemoryStream> ExportFileAsync(List<SysOperateLog> input = null);
|
||||
/// <summary>
|
||||
/// 导出后台日志
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<MemoryStream> ExportFileAsync(OperateLogInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 操作日志分页查询
|
||||
/// </summary>
|
||||
/// <param name="input">查询参数</param>
|
||||
/// <returns>分页列表</returns>
|
||||
Task<ISqlSugarPagedList<SysOperateLog>> PageAsync(OperateLogPageInput input);
|
||||
}
|
@@ -1,105 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using MiniExcelLibs;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="IOperateLogService"/>
|
||||
/// </summary>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class OperateLogService : DbRepository<SysOperateLog>, IOperateLogService
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[OperDesc("删除操作日志")]
|
||||
public async Task DeleteAsync(params string[] category)
|
||||
{
|
||||
await AsDeleteable().Where(it => category.Contains(it.Category)).ExecuteCommandAsync();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("导出操作日志", IsRecordPar = false)]
|
||||
public async Task<MemoryStream> ExportFileAsync(List<SysOperateLog> input = null)
|
||||
{
|
||||
input ??= await GetListAsync();
|
||||
|
||||
//总数据
|
||||
Dictionary<string, object> sheets = new();
|
||||
List<Dictionary<string, object>> devExports = new();
|
||||
foreach (var devData in input)
|
||||
{
|
||||
#region sheet
|
||||
//变量页
|
||||
var data = devData.GetType().GetProperties();
|
||||
Dictionary<string, object> devExport = new();
|
||||
foreach (var item in data)
|
||||
{
|
||||
//描述
|
||||
var desc = item.FindDisplayAttribute();
|
||||
//数据源增加
|
||||
devExport.Add(desc ?? item.Name, item.GetValue(devData)?.ToString());
|
||||
}
|
||||
|
||||
devExports.Add(devExport);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
sheets.Add("操作日志", devExports);
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
await memoryStream.SaveAsAsync(sheets);
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("导出操作日志", IsRecordPar = false)]
|
||||
public async Task<MemoryStream> ExportFileAsync(OperateLogInput input)
|
||||
{
|
||||
var query = GetPage(input.Adapt<OperateLogPageInput>());
|
||||
var data = await query.ToListAsync();
|
||||
return await ExportFileAsync(data);
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public async Task<ISqlSugarPagedList<SysOperateLog>> PageAsync(OperateLogPageInput input)
|
||||
{
|
||||
var query = GetPage(input);
|
||||
var pageInfo = await query.ToPagedListAsync(input.Current, input.Size);//分页
|
||||
return pageInfo;
|
||||
}
|
||||
|
||||
private ISugarQueryable<SysOperateLog> GetPage(OperateLogPageInput input)
|
||||
{
|
||||
var query = Context.Queryable<SysOperateLog>()
|
||||
.WhereIF(input.StartTime != null, a => a.OpTime >= input.StartTime.Value.ToLocalTime())
|
||||
.WhereIF(input.EndTime != null, a => a.OpTime <= input.EndTime.Value.ToLocalTime())
|
||||
.WhereIF(!string.IsNullOrEmpty(input.Account), it => it.OpAccount == input.Account)//根据账号查询
|
||||
.WhereIF(!string.IsNullOrEmpty(input.Category), it => it.Category == input.Category)//根据分类查询
|
||||
.WhereIF(!string.IsNullOrEmpty(input.ExeStatus), it => it.ExeStatus == input.ExeStatus)//根据结果查询
|
||||
.WhereIF(!string.IsNullOrEmpty(input.SearchKey), it => it.Name.Contains(input.SearchKey) || it.OpIp.Contains(input.SearchKey));//根据关键字查询
|
||||
|
||||
|
||||
for (int i = input.SortField.Count - 1; i >= 0; i--)
|
||||
{
|
||||
query = query.OrderByIF(!string.IsNullOrEmpty(input.SortField[i]), $"{input.SortField[i]} {(input.SortDesc[i] ? "desc" : "asc")}");
|
||||
}
|
||||
query = query.OrderBy(it => it.Id, OrderByType.Desc);//排序
|
||||
return query;
|
||||
}
|
||||
}
|
@@ -1,97 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 关系服务
|
||||
/// </summary>
|
||||
public interface IRelationService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取关系表用户工作台
|
||||
/// </summary>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <returns>关系表数据</returns>
|
||||
Task<SysRelation> GetWorkbenchAsync(long userId);
|
||||
|
||||
/// <summary>
|
||||
/// 根据分类获取关系表信息
|
||||
/// </summary>
|
||||
/// <param name="category">分类名称</param>
|
||||
/// <returns>关系表</returns>
|
||||
Task<List<SysRelation>> GetRelationByCategoryAsync(string category);
|
||||
|
||||
/// <summary>
|
||||
/// 通过对象ID和分类获取关系列表
|
||||
/// </summary>
|
||||
/// <param name="objectId">对象ID</param>
|
||||
/// <param name="category">分类</param>
|
||||
/// <returns></returns>
|
||||
Task<List<SysRelation>> GetRelationListByObjectIdAndCategoryAsync(long objectId, string category);
|
||||
|
||||
/// <summary>
|
||||
/// 通过对象ID列表和分类获取关系列表
|
||||
/// </summary>
|
||||
/// <param name="objectIds">对象ID</param>
|
||||
/// <param name="category">分类</param>
|
||||
/// <returns></returns>
|
||||
Task<List<SysRelation>> GetRelationListByObjectIdListAndCategoryAsync(List<long> objectIds, string category);
|
||||
|
||||
/// <summary>
|
||||
/// 通过目标ID和分类获取关系列表
|
||||
/// </summary>
|
||||
/// <param name="targetId">目标ID</param>
|
||||
/// <param name="category">分类</param>
|
||||
/// <returns></returns>
|
||||
Task<List<SysRelation>> GetRelationListByTargetIdAndCategoryAsync(string targetId, string category);
|
||||
|
||||
/// <summary>
|
||||
/// 通过目标ID列表和分类获取关系列表
|
||||
/// </summary>
|
||||
/// <param name="targetIds"></param>
|
||||
/// <param name="category"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<SysRelation>> GetRelationListByTargetIdListAndCategoryAsync(List<string> targetIds, string category);
|
||||
|
||||
/// <summary>
|
||||
/// 更新缓存
|
||||
/// </summary>
|
||||
/// <param name="category">分类</param>
|
||||
/// <returns></returns>
|
||||
void RefreshCache(string category);
|
||||
|
||||
/// <summary>
|
||||
/// 保存关系
|
||||
/// </summary>
|
||||
/// <param name="category">分类</param>
|
||||
/// <param name="objectId">对象ID</param>
|
||||
/// <param name="targetId">目标ID</param>
|
||||
/// <param name="extJson">拓展信息</param>
|
||||
/// <param name="clear">是否清除老的数据</param>
|
||||
/// <param name="refreshCache">是否刷新缓存</param>
|
||||
/// <returns></returns>
|
||||
Task SaveRelationAsync(string category, long objectId, string targetId, string extJson, bool clear, bool refreshCache = true);
|
||||
|
||||
/// <summary>
|
||||
/// 批量保存关系
|
||||
/// </summary>
|
||||
/// <param name="category">分类</param>
|
||||
/// <param name="objectId">对象ID</param>
|
||||
/// <param name="targetIds">目标ID列表</param>
|
||||
/// <param name="extJsons">拓展信息列表</param>
|
||||
/// <param name="clear">是否清除老的数据</param>
|
||||
/// <returns></returns>
|
||||
Task SaveRelationBatchAsync(string category, long objectId, List<string> targetIds, List<string> extJsons, bool clear);
|
||||
}
|
@@ -1,150 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.FriendlyException;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <inheritdoc cref="IRelationService"/>
|
||||
public class RelationService : DbRepository<SysRelation>, IRelationService
|
||||
{
|
||||
private readonly IServiceScope _serviceScope;
|
||||
public RelationService(IServiceScopeFactory serviceScopeFactory)
|
||||
{
|
||||
_serviceScope = serviceScopeFactory.CreateScope();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SysRelation>> GetRelationByCategoryAsync(string category)
|
||||
{
|
||||
//先从Cache拿,需要获取新的对象,避免操作导致缓存中对象改变
|
||||
var sysRelations = _serviceScope.ServiceProvider.GetService<MemoryCache>().Get<List<SysRelation>>(CacheConst.CACHE_SYSRELATION + category, true);
|
||||
if (sysRelations == null)
|
||||
{
|
||||
//cache没有就去数据库拿
|
||||
sysRelations = await GetListAsync(it => it.Category == category);
|
||||
if (sysRelations.Count > 0)
|
||||
{
|
||||
//插入Cache
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Set(CacheConst.CACHE_SYSRELATION + category, sysRelations, true);
|
||||
}
|
||||
}
|
||||
return sysRelations;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SysRelation>> GetRelationListByObjectIdAndCategoryAsync(long objectId, string category)
|
||||
{
|
||||
var sysRelations = await GetRelationByCategoryAsync(category);
|
||||
var result = sysRelations.Where(it => it.ObjectId == objectId).ToList();//获取关系集合
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SysRelation>> GetRelationListByObjectIdListAndCategoryAsync(List<long> objectIds, string category)
|
||||
{
|
||||
var sysRelations = await GetRelationByCategoryAsync(category);
|
||||
var result = sysRelations.Where(it => objectIds.Contains(it.ObjectId)).ToList();//获取关系集合
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SysRelation>> GetRelationListByTargetIdAndCategoryAsync(string targetId, string category)
|
||||
{
|
||||
var sysRelations = await GetRelationByCategoryAsync(category);
|
||||
var result = sysRelations.Where(it => it.TargetId == targetId).ToList();//获取关系集合
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SysRelation>> GetRelationListByTargetIdListAndCategoryAsync(List<string> targetIds, string category)
|
||||
{
|
||||
var sysRelations = await GetRelationByCategoryAsync(category);
|
||||
var result = sysRelations.Where(it => targetIds.Contains(it.TargetId)).ToList();//获取关系集合
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<SysRelation> GetWorkbenchAsync(long userId)
|
||||
{
|
||||
var sysRelations = await GetRelationByCategoryAsync(CateGoryConst.Relation_SYS_USER_WORKBENCH_DATA);
|
||||
var result = sysRelations.FirstOrDefault(it => it.ObjectId == userId);//获取个人工作台
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RefreshCache(string category)
|
||||
{
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Remove(CacheConst.CACHE_SYSRELATION + category);//删除cache
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task SaveRelationAsync(string category, long objectId, string targetId, string extJson, bool clear, bool refreshCache = true)
|
||||
{
|
||||
var sysRelation = new SysRelation
|
||||
{
|
||||
ObjectId = objectId,
|
||||
TargetId = targetId,
|
||||
Category = category,
|
||||
ExtJson = extJson
|
||||
};
|
||||
//事务
|
||||
var result = await itenant.UseTranAsync(async () =>
|
||||
{
|
||||
if (clear)
|
||||
await DeleteAsync(it => it.ObjectId == objectId && it.Category == category);//删除老的
|
||||
await InsertAsync(sysRelation);//添加新的
|
||||
});
|
||||
if (result.IsSuccess)//如果成功了
|
||||
{
|
||||
if (refreshCache)
|
||||
RefreshCache(category);
|
||||
}
|
||||
else
|
||||
{
|
||||
//写日志
|
||||
throw Oops.Oh(result.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task SaveRelationBatchAsync(string category, long objectId, List<string> targetIds, List<string> extJsons, bool clear)
|
||||
{
|
||||
var sysRelations = new List<SysRelation>();//要添加的列表
|
||||
for (int i = 0; i < targetIds.Count; i++)
|
||||
{
|
||||
sysRelations.Add(new SysRelation
|
||||
{
|
||||
ObjectId = objectId,
|
||||
TargetId = targetIds[i],
|
||||
Category = category,
|
||||
ExtJson = extJsons?[i]
|
||||
});
|
||||
}
|
||||
|
||||
var result = await itenant.UseTranAsync(async () =>
|
||||
{
|
||||
if (clear)
|
||||
await DeleteAsync(it => it.ObjectId == objectId && it.Category == category);//删除老的
|
||||
await InsertRangeAsync(sysRelations);//添加新的
|
||||
});
|
||||
if (result.IsSuccess)//如果成功了
|
||||
{
|
||||
RefreshCache(category);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Oops.Oh(result.ErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,72 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 角色按钮资源
|
||||
/// </summary>
|
||||
public class RoleGrantResourceButton
|
||||
{
|
||||
/// <summary>
|
||||
/// 按钮id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 授权菜单类
|
||||
/// </summary>
|
||||
public class RoleGrantResourceMenu
|
||||
{
|
||||
/// <summary>
|
||||
/// 菜单下按钮集合
|
||||
/// </summary>
|
||||
public List<RoleGrantResourceButton> Button { get; set; } = new List<RoleGrantResourceButton>();
|
||||
|
||||
/// <summary>
|
||||
/// 菜单id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父id
|
||||
/// </summary>
|
||||
public long ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父名称
|
||||
/// </summary>
|
||||
public string ParentName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单名称
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Blazor Server的组件路由内容
|
||||
/// </summary>
|
||||
public class PermissionTreeSelector
|
||||
{
|
||||
/// <summary>
|
||||
/// 路由名称
|
||||
/// </summary>
|
||||
public string ApiRoute { get; set; }
|
||||
}
|
@@ -1,98 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 资源服务
|
||||
/// </summary>
|
||||
public interface IResourceService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取所有的菜单和模块以及单页面列表,并按分类和排序码排序,不会形成树列表
|
||||
/// </summary>
|
||||
/// <returns>所有的菜单和模块以及单页面列表</returns>
|
||||
Task<List<SysResource>> GetaMenuAndSpaListAsync();
|
||||
/// <summary>
|
||||
/// 获取子资源
|
||||
/// </summary>
|
||||
/// <param name="sysResources"></param>
|
||||
/// <param name="resId"></param>
|
||||
/// <param name="isContainOneself"></param>
|
||||
/// <returns></returns>
|
||||
List<SysResource> GetChildListById(List<SysResource> sysResources, long resId, bool isContainOneself = true);
|
||||
|
||||
/// <summary>
|
||||
/// 获取ID获取Code列表
|
||||
/// </summary>
|
||||
/// <param name="ids">id列表</param>
|
||||
/// <param name="category">分类</param>
|
||||
/// <returns>Code列表</returns>
|
||||
Task<List<string>> GetCodeByIdsAsync(List<long> ids, ResourceCategoryEnum category);
|
||||
|
||||
/// <summary>
|
||||
/// 根据分类获取资源列表
|
||||
/// </summary>
|
||||
/// <param name="category">分类名称</param>
|
||||
/// <returns>资源列表</returns>
|
||||
Task<List<SysResource>> GetListByCategoryAsync(ResourceCategoryEnum category);
|
||||
|
||||
/// <summary>
|
||||
/// 资源分类列表,如果是空的则获取全部资源
|
||||
/// </summary>
|
||||
/// <param name="categorys">资源分类列表</param>
|
||||
/// <returns></returns>
|
||||
Task<List<SysResource>> GetListByCategorysAsync(List<ResourceCategoryEnum> categorys = null);
|
||||
/// <summary>
|
||||
/// 获取资源所有下级
|
||||
/// </summary>
|
||||
/// <param name="resourceList">资源列表</param>
|
||||
/// <param name="parentId">父ID</param>
|
||||
/// <returns></returns>
|
||||
List<SysResource> GetResourceChilden(List<SysResource> resourceList, long parentId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取上级
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<SysResource> GetResourceParent(List<SysResource> resourceList, long parentId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取授权菜单
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<RoleGrantResourceMenu>> GetRoleGrantResourceMenusAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 刷新缓存
|
||||
/// </summary>
|
||||
/// <param name="category">分类名称</param>
|
||||
/// <returns></returns>
|
||||
void RefreshCache(ResourceCategoryEnum category);
|
||||
|
||||
/// <summary>
|
||||
/// 构建菜单树形结构
|
||||
/// </summary>
|
||||
/// <param name="resourceList">菜单列表</param>
|
||||
/// <param name="parentId">父ID</param>
|
||||
/// <returns>菜单形结构</returns>
|
||||
/// <inheritdoc/>
|
||||
List<SysResource> ResourceListToTree(List<SysResource> resourceList, long parentId = 0);
|
||||
/// <summary>
|
||||
/// 多个树转列表
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
List<SysResource> ResourceTreeToList(List<SysResource> data);
|
||||
|
||||
}
|
@@ -1,269 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
||||
/// <inheritdoc cref="IResourceService"/>
|
||||
public class ResourceService : DbRepository<SysResource>, IResourceService
|
||||
{
|
||||
private readonly IServiceScope _serviceScope;
|
||||
public ResourceService(IServiceScopeFactory serviceScopeFactory)
|
||||
{
|
||||
_serviceScope = serviceScopeFactory.CreateScope();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SysResource>> GetaMenuAndSpaListAsync()
|
||||
{
|
||||
//获取所有的菜单以及单页面
|
||||
var sysResources = await GetListByCategorysAsync((List<ResourceCategoryEnum>)new() { ResourceCategoryEnum.MENU, ResourceCategoryEnum.SPA });
|
||||
return sysResources?.OrderBy(it => it.Category).ThenBy(it => it.SortCode).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<SysResource> GetChildListById(List<SysResource> sysResources, long resId, bool isContainOneself = true)
|
||||
{
|
||||
//查找下级
|
||||
var childLsit = GetResourceChilden(sysResources, resId);
|
||||
if (isContainOneself)//如果包含自己
|
||||
{
|
||||
//获取自己
|
||||
var self = sysResources.Where(it => it.Id == resId).FirstOrDefault();
|
||||
if (self != null) childLsit.Insert(0, self);//如果不为空就插到第一个
|
||||
}
|
||||
return childLsit;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<string>> GetCodeByIdsAsync(List<long> ids, ResourceCategoryEnum category)
|
||||
{
|
||||
//根据分类获取所有
|
||||
var sysResources = await GetListByCategoryAsync(category);
|
||||
return sysResources.Where(it => ids.Contains(it.Id)).Select(it => it.Code).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<SysResource>> GetListByCategoryAsync(ResourceCategoryEnum category)
|
||||
{
|
||||
//先从Cache拿,需要获取新的对象,避免操作导致缓存中对象改变
|
||||
var sysResources = _serviceScope.ServiceProvider.GetService<MemoryCache>().Get<List<SysResource>>(CacheConst.CACHE_SYSRESOURCE + category.ToString(), true);
|
||||
if (sysResources == null)
|
||||
{
|
||||
//cache没有就去数据库拿
|
||||
sysResources = await GetListAsync(it => it.Category == category);
|
||||
if (sysResources.Count > 0)
|
||||
{
|
||||
//插入Cache
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Set(CacheConst.CACHE_SYSRESOURCE + category.ToString(), sysResources, true);
|
||||
}
|
||||
}
|
||||
return sysResources;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SysResource>> GetListByCategorysAsync(List<ResourceCategoryEnum> categoryList = null)
|
||||
{
|
||||
//定义结果
|
||||
var sysResources = new List<SysResource>();
|
||||
|
||||
//定义资源分类列表,如果是空的则获取全部资源
|
||||
categoryList = categoryList != null ? categoryList
|
||||
: new List<ResourceCategoryEnum> { ResourceCategoryEnum.MENU, ResourceCategoryEnum.BUTTON, ResourceCategoryEnum.SPA };
|
||||
//遍历列表
|
||||
foreach (var category in categoryList)
|
||||
{
|
||||
//根据分类获取到资源列表
|
||||
var data = await GetListByCategoryAsync(category);
|
||||
//添加到结果集
|
||||
sysResources.AddRange(data);
|
||||
}
|
||||
return sysResources;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public List<SysResource> GetResourceChilden(List<SysResource> resourceList, long parentId)
|
||||
{
|
||||
//找下级资源ID列表
|
||||
var resources = resourceList.Where(it => it.ParentId == parentId).ToList();
|
||||
if (resources.Count > 0)//如果数量大于0
|
||||
{
|
||||
var data = new List<SysResource>();
|
||||
foreach (var item in resources)//遍历资源
|
||||
{
|
||||
var res = GetResourceChilden(resourceList, item.Id);
|
||||
data.AddRange(res);//添加子节点;
|
||||
data.Add(item);//添加到列表
|
||||
}
|
||||
return data;//返回结果
|
||||
}
|
||||
return new List<SysResource>();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public List<SysResource> GetResourceParent(List<SysResource> resourceList, long parentId)
|
||||
{
|
||||
//找上级资源ID列表
|
||||
var resources = resourceList.Where(it => it.Id == parentId).FirstOrDefault();
|
||||
if (resources != null)//如果数量大于0
|
||||
{
|
||||
var data = new List<SysResource>();
|
||||
var parents = GetResourceParent(resourceList, resources.ParentId);
|
||||
data.AddRange(parents);//添加子节点;
|
||||
data.Add(resources);//添加到列表
|
||||
return data;//返回结果
|
||||
}
|
||||
return new List<SysResource>();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<RoleGrantResourceMenu>> GetRoleGrantResourceMenusAsync()
|
||||
{
|
||||
var roleGrantResourceMenus = new List<RoleGrantResourceMenu>();//定义结果
|
||||
List<SysResource> allMenuList = (await GetListByCategoryAsync(ResourceCategoryEnum.MENU));//获取所有菜单列表
|
||||
List<SysResource> allButtonList = await GetListByCategoryAsync(ResourceCategoryEnum.BUTTON);//获取所有按钮列表
|
||||
var parentMenuList = allMenuList.Where(it => it.ParentId == 0).ToList();//获取一级目录
|
||||
|
||||
//遍历一级目录
|
||||
foreach (var parent in parentMenuList)
|
||||
{
|
||||
//如果是目录则去遍历下级
|
||||
if (parent.TargetType == TargetTypeEnum.None)
|
||||
{
|
||||
//获取所有下级菜单
|
||||
var menuList = GetChildListById(allMenuList, parent.Id, false);
|
||||
|
||||
//遍历下级菜单
|
||||
foreach (var menu in menuList)
|
||||
{
|
||||
//如果菜单类型是菜单
|
||||
if (menu.TargetType == TargetTypeEnum.SELF)
|
||||
{
|
||||
//获取菜单下按钮集合并转换成对应实体
|
||||
var buttonList = allButtonList.Where(it => it.ParentId == menu.Id).ToList();
|
||||
var buttons = buttonList.Adapt<List<RoleGrantResourceButton>>();
|
||||
roleGrantResourceMenus.Add(new()
|
||||
{
|
||||
Id = menu.Id,
|
||||
ParentId = parent.Id,
|
||||
ParentName = parent.Title,
|
||||
Title = GetRoleGrantResourceMenuTitle(parentMenuList, menu),//菜单名称需要特殊处理因为有二级菜单
|
||||
Button = buttons
|
||||
});
|
||||
}
|
||||
else if (menu.TargetType == TargetTypeEnum.BLANK || menu.TargetType == TargetTypeEnum.CALLBACK)//如果是内链或者外链
|
||||
{
|
||||
//直接加到资源列表
|
||||
roleGrantResourceMenus.Add(new()
|
||||
{
|
||||
Id = menu.Id,
|
||||
ParentId = parent.Id,
|
||||
ParentName = parent.Title,
|
||||
Title = menu.Title,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//否则就将自己加到一级目录里面
|
||||
roleGrantResourceMenus.Add(new()
|
||||
{
|
||||
Id = parent.Id,
|
||||
ParentId = parent.Id,
|
||||
ParentName = parent.Title,
|
||||
Title = parent.Title,
|
||||
});
|
||||
}
|
||||
}
|
||||
return roleGrantResourceMenus;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RefreshCache(ResourceCategoryEnum category)
|
||||
{
|
||||
//如果分类是空的
|
||||
if (category == ResourceCategoryEnum.None)
|
||||
{
|
||||
//删除全部key
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Remove(CacheConst.CACHE_SYSRESOURCE + ResourceCategoryEnum.SPA.ToString());
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Remove(CacheConst.CACHE_SYSRESOURCE + ResourceCategoryEnum.BUTTON.ToString());
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Remove(CacheConst.CACHE_SYSRESOURCE + ResourceCategoryEnum.MENU.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
//否则只删除一个Key
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Remove(CacheConst.CACHE_SYSRESOURCE + category.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<SysResource> ResourceListToTree(List<SysResource> resourceList, long parentId = 0)
|
||||
{
|
||||
//找下级资源ID列表
|
||||
var resources = resourceList
|
||||
.Where(it => it.ParentId == parentId).OrderBy(it => it.SortCode).ToList();
|
||||
if (resources.Count > 0)//如果数量大于0
|
||||
{
|
||||
var data = new List<SysResource>();
|
||||
foreach (var item in resources)//遍历资源
|
||||
{
|
||||
var children = ResourceListToTree(resourceList, item.Id);//添加子节点
|
||||
item.Children = children.Count > 0 ? children : null;
|
||||
data.Add(item);//添加到列表
|
||||
}
|
||||
return data;//返回结果
|
||||
}
|
||||
return new List<SysResource>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<SysResource> ResourceTreeToList(List<SysResource> data)
|
||||
{
|
||||
List<SysResource> list = new();
|
||||
foreach (var item in data)
|
||||
{
|
||||
list.Add(item);
|
||||
if (item.Children != null && item.Children.Count > 0)
|
||||
{
|
||||
list.AddRange(ResourceTreeToList(item.Children));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取授权菜单类菜单名称
|
||||
/// </summary>
|
||||
/// <param name="menuList">菜单列表</param>
|
||||
/// <param name="menu">当前菜单</param>
|
||||
/// <returns></returns>
|
||||
private string GetRoleGrantResourceMenuTitle(List<SysResource> menuList, SysResource menu)
|
||||
{
|
||||
//查找菜单上级
|
||||
var parentList = GetResourceParent(menuList, menu.ParentId);
|
||||
//如果有父级菜单
|
||||
if (parentList.Count > 0)
|
||||
{
|
||||
var titles = parentList.Select(it => it.Title).ToList();//提取出父级的name
|
||||
var title = $"{string.Join("- ", titles)}-{menu.Title}";//根据-分割,转换成字符串并在最后加上菜单的title
|
||||
return title;
|
||||
}
|
||||
else
|
||||
{
|
||||
return menu.Title;//原路返回
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,82 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 角色授权资源参数
|
||||
/// </summary>
|
||||
public class GrantResourceInput : RoleOwnResourceOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 授权资源信息
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "授权资源信息表不能为空")]
|
||||
public override List<RelationRoleResuorce> GrantInfoList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色Id
|
||||
/// </summary>
|
||||
[MinValue(1, ErrorMessage = "Id不能为空")]
|
||||
public override long Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 角色授权用户参数
|
||||
/// </summary>
|
||||
public class GrantUserInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 授权权限信息
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "GrantInfoList不能为空")]
|
||||
public List<long> GrantInfoList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Id不能为空")]
|
||||
public long? Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 角色添加参数
|
||||
/// </summary>
|
||||
public class RoleAddInput : SysRole
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Name不能为空")]
|
||||
public override string Name { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 角色编辑参数
|
||||
/// </summary>
|
||||
public class RoleEditInput : RoleAddInput
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
[MinValue(1, ErrorMessage = "Id不能为空")]
|
||||
public override long Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 角色查询参数
|
||||
/// </summary>
|
||||
public class RolePageInput : BasePageInput
|
||||
{
|
||||
}
|
@@ -1,105 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 角色服务
|
||||
/// </summary>
|
||||
public interface IRoleService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加角色
|
||||
/// </summary>
|
||||
/// <param name="input">添加参数</param>
|
||||
/// <returns></returns>
|
||||
Task AddAsync(RoleAddInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 删除角色
|
||||
/// </summary>
|
||||
/// <param name="input">删除参数</param>
|
||||
/// <returns></returns>
|
||||
Task DeleteAsync(params long[] input);
|
||||
|
||||
/// <summary>
|
||||
/// 编辑角色
|
||||
/// </summary>
|
||||
/// <param name="input">编辑角色</param>
|
||||
/// <returns></returns>
|
||||
Task EditAsync(RoleEditInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 根据用户ID获取用户角色Id集合
|
||||
/// </summary>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <returns></returns>
|
||||
Task<List<long>> GetRoleIdListByUserIdAsync(long userId);
|
||||
|
||||
/// <summary>
|
||||
/// 根据用户ID获取用户角色集合
|
||||
/// </summary>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <returns></returns>
|
||||
Task<List<SysRole>> GetRoleListByUserIdAsync(long userId);
|
||||
|
||||
/// <summary>
|
||||
/// 给角色授权资源
|
||||
/// </summary>
|
||||
/// <param name="input">授权参数</param>
|
||||
/// <returns></returns>
|
||||
Task GrantResourceAsync(GrantResourceInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 给角色授权用户
|
||||
/// </summary>
|
||||
/// <param name="input">授权信息</param>
|
||||
/// <returns></returns>
|
||||
Task GrantUserAsync(GrantUserInput input);
|
||||
/// <summary>
|
||||
/// 角色拥有资源
|
||||
/// </summary>
|
||||
/// <param name="input">角色id</param>
|
||||
/// <returns>角色拥有资源信息</returns>
|
||||
Task<RoleOwnResourceOutput> OwnResourceAsync(long input);
|
||||
|
||||
/// <summary>
|
||||
/// 获取角色下的用户
|
||||
/// </summary>
|
||||
/// <param name="input">角色ID</param>
|
||||
/// <returns></returns>
|
||||
Task<List<long>> OwnUserAsync(long input);
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询角色
|
||||
/// </summary>
|
||||
/// <param name="input">查询参数</param>
|
||||
/// <returns></returns>
|
||||
Task<ISqlSugarPagedList<SysRole>> PageAsync(RolePageInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 刷新缓存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
void RefreshCache();
|
||||
|
||||
/// <summary>
|
||||
/// 角色刷新资源
|
||||
/// </summary>
|
||||
Task RefreshResourceAsync(long? menuId = null);
|
||||
/// <summary>
|
||||
/// 角色选择器
|
||||
/// </summary>
|
||||
Task<List<SysRole>> RoleSelectorAsync(string searchKey = null);
|
||||
}
|
@@ -1,410 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.EventBus;
|
||||
using Furion.FriendlyException;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
namespace ThingsGateway.Admin.Application
|
||||
{
|
||||
/// <inheritdoc cref="IRoleService"/>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class RoleService : DbRepository<SysRole>, IRoleService
|
||||
{
|
||||
private readonly IEventPublisher _eventPublisher;
|
||||
private readonly IRelationService _relationService;
|
||||
private readonly IResourceService _resourceService;
|
||||
private readonly IServiceScope _serviceScope;
|
||||
|
||||
/// <inheritdoc cref="IRoleService"/>
|
||||
public RoleService(
|
||||
IRelationService relationService,
|
||||
IResourceService resourceService,
|
||||
IEventPublisher eventPublisher,
|
||||
IServiceScopeFactory serviceScopeFactory)
|
||||
{
|
||||
_relationService = relationService;
|
||||
_resourceService = resourceService;
|
||||
_eventPublisher = eventPublisher;
|
||||
_serviceScope = serviceScopeFactory.CreateScope();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("添加角色")]
|
||||
public async Task AddAsync(RoleAddInput input)
|
||||
{
|
||||
await CheckInput(input);//检查参数
|
||||
var sysRole = input.Adapt<SysRole>();//实体转换
|
||||
sysRole.Code = YitIdHelper.NextId().ToString();//赋值Code
|
||||
if (await InsertAsync(sysRole))//插入数据
|
||||
RefreshCache();//刷新缓存
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("删除角色")]
|
||||
public async Task DeleteAsync(params long[] input)
|
||||
{
|
||||
//获取所有ID
|
||||
var ids = input.ToList();
|
||||
if (ids.Count > 0)
|
||||
{
|
||||
var sysRoles = await GetListAsync();//获取所有角色
|
||||
var hasSuperAdmin = sysRoles.Any(it => it.Code == RoleConst.SuperAdmin && ids.Contains(it.Id));//判断是否有超级管理员
|
||||
if (hasSuperAdmin) throw Oops.Bah($"不可删除系统内置超管角色");
|
||||
|
||||
//数据库是string所以这里转下
|
||||
var targetIds = ids.Select(it => it.ToString()).ToList();
|
||||
//定义删除的关系
|
||||
var delRelations = new List<string> { CateGoryConst.Relation_SYS_ROLE_HAS_RESOURCE, CateGoryConst.Relation_SYS_ROLE_HAS_PERMISSION };
|
||||
//事务
|
||||
var result = await itenant.UseTranAsync(async () =>
|
||||
{
|
||||
await DeleteByIdsAsync(ids.Cast<object>().ToArray());//删除按钮
|
||||
|
||||
//删除关系表角色与资源关系,角色与权限关系
|
||||
await Context.Deleteable<SysRelation>().Where(it => ids.Contains(it.ObjectId) && delRelations.Contains(it.Category)).ExecuteCommandAsync();
|
||||
//删除关系表角色与用户关系
|
||||
await Context.Deleteable<SysRelation>().Where(it => targetIds.Contains(it.TargetId) && it.Category == CateGoryConst.Relation_SYS_USER_HAS_ROLE).ExecuteCommandAsync();
|
||||
|
||||
});
|
||||
if (result.IsSuccess)//如果成功了
|
||||
{
|
||||
RefreshCache();//刷新缓存
|
||||
_relationService.RefreshCache(CateGoryConst.Relation_SYS_USER_HAS_ROLE);//关系表刷新SYS_USER_HAS_ROLE缓存
|
||||
_relationService.RefreshCache(CateGoryConst.Relation_SYS_ROLE_HAS_RESOURCE);//关系表刷新SYS_ROLE_HAS_RESOURCE缓存
|
||||
_relationService.RefreshCache(CateGoryConst.Relation_SYS_ROLE_HAS_PERMISSION);//关系表刷新SYS_ROLE_HAS_PERMISSION缓存
|
||||
await _eventPublisher.PublishAsync(EventSubscriberConst.ClearUserCache, ids);//清除角色下用户缓存
|
||||
}
|
||||
else
|
||||
{
|
||||
//写日志
|
||||
throw Oops.Oh(result.ErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("编辑角色")]
|
||||
public async Task EditAsync(RoleEditInput input)
|
||||
{
|
||||
//判断是否超管
|
||||
if (input.Code == RoleConst.SuperAdmin)
|
||||
throw Oops.Bah($"不可编辑超管角色");
|
||||
await CheckInput(input);//检查参数
|
||||
var role = await GetFirstAsync(it => it.Id == input.Id);//获取角色
|
||||
if (role != null)
|
||||
{
|
||||
var permissions = new List<SysRelation>();
|
||||
|
||||
var sysRole = input.Adapt<SysRole>();//实体转换
|
||||
//事务
|
||||
var result = await itenant.UseTranAsync(async () =>
|
||||
{
|
||||
await UpdateAsync(sysRole);//更新角色
|
||||
if (permissions.Any())//如果有授权权限就更新
|
||||
await Context.Updateable(permissions).ExecuteCommandAsync();
|
||||
});
|
||||
if (result.IsSuccess)//如果成功了
|
||||
{
|
||||
RefreshCache();//刷新缓存
|
||||
if (permissions.Any())//如果有授权
|
||||
_relationService.RefreshCache(CateGoryConst.Relation_SYS_ROLE_HAS_PERMISSION);//关系表刷新SYS_ROLE_HAS_PERMISSION缓存
|
||||
await _eventPublisher.PublishAsync(EventSubscriberConst.ClearUserCache, new List<long> { input.Id });//清除角色下用户缓存
|
||||
}
|
||||
else
|
||||
{
|
||||
//写日志
|
||||
throw Oops.Oh(result.ErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有角色
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override async Task<List<SysRole>> GetListAsync()
|
||||
{
|
||||
//先从Cache拿,需要获取新的对象,避免操作导致缓存中对象改变
|
||||
var sysRoles = _serviceScope.ServiceProvider.GetService<MemoryCache>().Get<List<SysRole>>(CacheConst.CACHE_SYSROLE, true);
|
||||
if (sysRoles == null)
|
||||
{
|
||||
//cache没有就去数据库拿
|
||||
sysRoles = await base.GetListAsync();
|
||||
if (sysRoles.Count > 0)
|
||||
{
|
||||
//插入Cache
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Set(CacheConst.CACHE_SYSROLE, sysRoles, true);
|
||||
}
|
||||
}
|
||||
return sysRoles;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<long>> GetRoleIdListByUserIdAsync(long userId)
|
||||
{
|
||||
List<SysRole> cods = new();//角色代码集合
|
||||
var roleList = await _relationService.GetRelationListByObjectIdAndCategoryAsync(userId, CateGoryConst.Relation_SYS_USER_HAS_ROLE);//根据用户ID获取角色ID
|
||||
var roleIdList = roleList.Select(x => x.TargetId.ToLong()).ToList();//角色ID列表
|
||||
return roleIdList;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<SysRole>> GetRoleListByUserIdAsync(long userId)
|
||||
{
|
||||
List<SysRole> cods = new();//角色代码集合
|
||||
var roleList = await _relationService.GetRelationListByObjectIdAndCategoryAsync(userId, CateGoryConst.Relation_SYS_USER_HAS_ROLE);//根据用户ID获取角色ID
|
||||
var roleIdList = roleList.Select(x => x.TargetId.ToLong()).ToList();//角色ID列表
|
||||
if (roleIdList.Count > 0)
|
||||
{
|
||||
cods = await GetListAsync(it => roleIdList.Contains(it.Id));
|
||||
}
|
||||
return cods;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("角色授权")]
|
||||
public async Task GrantResourceAsync(GrantResourceInput input)
|
||||
{
|
||||
var menuIds = input.GrantInfoList.Select(it => it.MenuId).ToList();//菜单ID
|
||||
var extJsons = input.GrantInfoList.Select(it => it.ToJsonString()).ToList();//拓展信息
|
||||
var relationRoles = new List<SysRelation>();//要添加的角色资源和授权关系表
|
||||
var sysRole = (await GetListAsync()).Where(it => it.Id == input.Id).FirstOrDefault();//获取角色
|
||||
if (sysRole != null)
|
||||
{
|
||||
#region 角色资源处理
|
||||
|
||||
//遍历角色列表
|
||||
for (int i = 0; i < menuIds.Count; i++)
|
||||
{
|
||||
//将角色资源添加到列表
|
||||
relationRoles.Add(new SysRelation
|
||||
{
|
||||
ObjectId = sysRole.Id,
|
||||
TargetId = menuIds[i].ToString(),
|
||||
Category = CateGoryConst.Relation_SYS_ROLE_HAS_RESOURCE,
|
||||
ExtJson = extJsons?[i]
|
||||
});
|
||||
}
|
||||
|
||||
#endregion 角色资源处理
|
||||
|
||||
#region 角色权限处理
|
||||
|
||||
var relationRolePer = new List<SysRelation>();//要添加的角色有哪些权限列表
|
||||
|
||||
//获取菜单信息
|
||||
var menus = await GetMenuByMenuIds(menuIds);
|
||||
if (menus.Count > 0)
|
||||
{
|
||||
//获取权限授权树
|
||||
var permissions = PermissionUtil.PermissionTreeSelector(menus.Select(it => it.Component).ToList());
|
||||
permissions.ForEach(it =>
|
||||
{
|
||||
//新建角色权限关系
|
||||
relationRolePer.Add(new SysRelation
|
||||
{
|
||||
ObjectId = sysRole.Id,
|
||||
TargetId = it.ApiRoute,
|
||||
Category = CateGoryConst.Relation_SYS_ROLE_HAS_PERMISSION,
|
||||
ExtJson = new RelationRolePermission
|
||||
{
|
||||
ApiUrl = it.ApiRoute,
|
||||
}.ToJsonString()
|
||||
});
|
||||
});
|
||||
}
|
||||
relationRoles.AddRange(relationRolePer);//合并列表
|
||||
|
||||
#endregion 角色权限处理
|
||||
|
||||
#region 保存数据库
|
||||
|
||||
//事务
|
||||
var result = await itenant.UseTranAsync(async () =>
|
||||
{
|
||||
//删除老的
|
||||
await Context.Deleteable<SysRelation>().Where(it => it.ObjectId == sysRole.Id
|
||||
&&
|
||||
(it.Category == CateGoryConst.Relation_SYS_ROLE_HAS_PERMISSION
|
||||
|| it.Category == CateGoryConst.Relation_SYS_ROLE_HAS_RESOURCE)
|
||||
)
|
||||
.ExecuteCommandAsync();
|
||||
await Context.Insertable(relationRoles).ExecuteCommandAsync();
|
||||
});
|
||||
if (result.IsSuccess)//如果成功了
|
||||
{
|
||||
_relationService.RefreshCache(CateGoryConst.Relation_SYS_ROLE_HAS_RESOURCE);//刷新关系缓存
|
||||
_relationService.RefreshCache(CateGoryConst.Relation_SYS_ROLE_HAS_PERMISSION);//刷新关系缓存
|
||||
await _eventPublisher.PublishAsync(EventSubscriberConst.ClearUserCache, new List<long> { input.Id });//发送事件清除角色下用户缓存
|
||||
}
|
||||
else
|
||||
{
|
||||
//写日志
|
||||
throw Oops.Oh(result.ErrorMessage);
|
||||
}
|
||||
|
||||
#endregion 保存数据库
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("用户授权")]
|
||||
public async Task GrantUserAsync(GrantUserInput input)
|
||||
{
|
||||
var sysRelations = new List<SysRelation>();//关系列表
|
||||
|
||||
//遍历用户ID
|
||||
input.GrantInfoList.ForEach(it =>
|
||||
{
|
||||
sysRelations.Add(new SysRelation
|
||||
{
|
||||
ObjectId = it,
|
||||
TargetId = input.Id.ToString(),
|
||||
Category = CateGoryConst.Relation_SYS_USER_HAS_ROLE
|
||||
});
|
||||
});
|
||||
|
||||
//事务
|
||||
var result = await itenant.UseTranAsync(async () =>
|
||||
{
|
||||
//删除老的
|
||||
await Context.Deleteable<SysRelation>().Where(it => it.TargetId == input.Id.ToString() && it.Category == CateGoryConst.Relation_SYS_USER_HAS_ROLE).ExecuteCommandAsync();
|
||||
await Context.Insertable(sysRelations).ExecuteCommandAsync();//添加新的
|
||||
|
||||
});
|
||||
if (result.IsSuccess)//如果成功了
|
||||
{
|
||||
_relationService.RefreshCache(CateGoryConst.Relation_SYS_USER_HAS_ROLE);//刷新关系表SYS_USER_HAS_ROLE缓存
|
||||
await _eventPublisher.PublishAsync(EventSubscriberConst.ClearUserCache, new List<long> { input.Id.Value });//清除角色下用户缓存
|
||||
}
|
||||
else
|
||||
{
|
||||
//写日志
|
||||
throw Oops.Oh(result.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<RoleOwnResourceOutput> OwnResourceAsync(long input)
|
||||
{
|
||||
RoleOwnResourceOutput roleOwnResource = new() { Id = input };//定义结果集
|
||||
List<RelationRoleResuorce> GrantInfoList = new();//已授权信息集合
|
||||
//获取关系列表
|
||||
var relations = await _relationService.GetRelationListByObjectIdAndCategoryAsync(input, CateGoryConst.Relation_SYS_ROLE_HAS_RESOURCE);
|
||||
//遍历关系表
|
||||
relations.ForEach(it =>
|
||||
{
|
||||
//将扩展信息转为实体
|
||||
var relationRole = it.ExtJson.FromJsonString<RelationRoleResuorce>();
|
||||
GrantInfoList.Add(relationRole);//添加到已授权信息
|
||||
});
|
||||
roleOwnResource.GrantInfoList = GrantInfoList;//赋值已授权信息
|
||||
return roleOwnResource;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<long>> OwnUserAsync(long input)
|
||||
{
|
||||
//获取关系列表
|
||||
var relations = await _relationService.GetRelationListByTargetIdAndCategoryAsync(input.ToString(), CateGoryConst.Relation_SYS_USER_HAS_ROLE);
|
||||
return relations.Select(it => it.ObjectId).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ISqlSugarPagedList<SysRole>> PageAsync(RolePageInput input)
|
||||
{
|
||||
var query = Context.Queryable<SysRole>()
|
||||
.WhereIF(!string.IsNullOrEmpty(input.SearchKey), it => it.Name.Contains(input.SearchKey));//根据关键字查询
|
||||
for (int i = input.SortField.Count - 1; i >= 0; i--)
|
||||
{
|
||||
query = query.OrderByIF(!string.IsNullOrEmpty(input.SortField[i]), $"{input.SortField[i]} {(input.SortDesc[i] ? "desc" : "asc")}");
|
||||
}
|
||||
query = query.OrderBy(it => it.SortCode);//排序
|
||||
|
||||
var pageInfo = await query.ToPagedListAsync(input.Current, input.Size);//分页
|
||||
return pageInfo;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RefreshCache()
|
||||
{
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Remove(CacheConst.CACHE_SYSROLE);//删除KEY
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task RefreshResourceAsync(long? menuId = null)
|
||||
{
|
||||
var data = await GetListAsync();
|
||||
foreach (var item in data)
|
||||
{
|
||||
var r1 = await OwnResourceAsync(item.Id);
|
||||
if (menuId == null || r1.GrantInfoList.Any(a => a.MenuId == menuId))
|
||||
{
|
||||
await GrantResourceAsync(new GrantResourceInput() { Id = item.Id, GrantInfoList = r1.GrantInfoList });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<SysRole>> RoleSelectorAsync(string searchKey = null)
|
||||
{
|
||||
var result = await Context.Queryable<SysRole>()
|
||||
.WhereIF(!string.IsNullOrEmpty(searchKey), it => it.Name.Contains(searchKey))//根据关键字查询
|
||||
.ToListAsync();
|
||||
return result;
|
||||
}
|
||||
|
||||
#region 方法
|
||||
|
||||
/// <summary>
|
||||
/// 检查输入参数
|
||||
/// </summary>
|
||||
/// <param name="sysRole"></param>
|
||||
private async Task CheckInput(SysRole sysRole)
|
||||
{
|
||||
var sysRoles = await GetListAsync();//获取所有
|
||||
var repeatName = sysRoles.Any(it => it.Name == sysRole.Name && it.Id != sysRole.Id);//是否有重复角色名称
|
||||
if (repeatName)//如果有
|
||||
{
|
||||
throw Oops.Bah($"存在重复的角色:{sysRole.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据菜单ID获取菜单
|
||||
/// </summary>
|
||||
/// <param name="menuIds"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<List<SysResource>> GetMenuByMenuIds(List<long> menuIds)
|
||||
{
|
||||
//获取所有菜单
|
||||
var menuList = await _resourceService.GetListByCategoryAsync(ResourceCategoryEnum.MENU);
|
||||
//获取菜单信息
|
||||
var menus = menuList.Where(it => menuIds.Contains(it.Id)).ToList();
|
||||
|
||||
return menus;
|
||||
}
|
||||
|
||||
#endregion 方法
|
||||
}
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 会话分页查询
|
||||
/// </summary>
|
||||
public class SessionPageInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
[Description("账号")]
|
||||
public string Account { get; set; }
|
||||
/// <summary>
|
||||
/// 最新登录IP
|
||||
/// </summary>
|
||||
[Description("最新登录IP")]
|
||||
public string LatestLoginIp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 姓名
|
||||
/// </summary>
|
||||
[Description("姓名")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 退出参数
|
||||
/// </summary>
|
||||
public class ExitVerificatInput : BaseIdInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证ID列表
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "VerificatIds不能为空")]
|
||||
public List<long> VerificatIds { get; set; }
|
||||
/// <summary>
|
||||
/// 用户Id
|
||||
/// </summary>
|
||||
[MinValue(1, ErrorMessage = "Id不能为空")]
|
||||
public override long Id { get; set; }
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 会话输出
|
||||
/// </summary>
|
||||
public class SessionOutput : PrimaryKeyEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// 账号
|
||||
///</summary>
|
||||
[Description("账号")]
|
||||
[DataTable(Order = 1, IsShow = true, Sortable = true)]
|
||||
public virtual string Account { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最新登录ip
|
||||
///</summary>
|
||||
[Description("最新登录ip")]
|
||||
[DataTable(Order = 3, IsShow = true, Sortable = true)]
|
||||
public string LatestLoginIp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最新登录时间
|
||||
///</summary>
|
||||
[Description("最新登录时间")]
|
||||
[DataTable(Order = 4, IsShow = true, Sortable = true)]
|
||||
public DateTime? LatestLoginTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 在线状态
|
||||
/// </summary>
|
||||
[Description("在线状态")]
|
||||
[DataTable(Order = 2, IsShow = true, Sortable = true)]
|
||||
public bool OnlineStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 令牌数量
|
||||
/// </summary>
|
||||
[Description("令牌数量")]
|
||||
[DataTable(Order = 5, IsShow = true, Sortable = false)]
|
||||
public int VerificatCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 令牌信息集合
|
||||
/// </summary>
|
||||
[Description("令牌列表")]
|
||||
public List<VerificatInfo> VerificatSignList { get; set; }
|
||||
}
|
@@ -1,40 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 会话管理服务
|
||||
/// </summary>
|
||||
public interface ISessionService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 强退会话
|
||||
/// </summary>
|
||||
/// <param name="input">用户ID</param>
|
||||
Task ExitSessionAsync(long input);
|
||||
|
||||
/// <summary>
|
||||
/// 强退verificat
|
||||
/// </summary>
|
||||
/// <param name="input">verificat列表</param>
|
||||
Task ExitVerificatAsync(ExitVerificatInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 会话分页查询
|
||||
/// </summary>
|
||||
/// <param name="input">查询参数</param>
|
||||
/// <returns>会话列表</returns>
|
||||
Task<ISqlSugarPagedList<SessionOutput>> PageAsync(SessionPageInput input);
|
||||
}
|
@@ -1,116 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="ISessionService"/>
|
||||
/// </summary>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class SessionService : DbRepository<SysUser>, ISessionService
|
||||
{
|
||||
private readonly INoticeService _noticeService;
|
||||
private readonly IVerificatService _verificatService;
|
||||
|
||||
/// <inheritdoc cref="ISessionService"/>
|
||||
public SessionService(IVerificatService verificatService, INoticeService noticeService)
|
||||
{
|
||||
_verificatService = verificatService;
|
||||
_noticeService = noticeService;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("强退会话")]
|
||||
public async Task ExitSessionAsync(long input)
|
||||
{
|
||||
//verificat列表
|
||||
List<VerificatInfo> verificatInfos = await _verificatService.GetVerificatIdAsync(input);
|
||||
//从列表中删除
|
||||
await _verificatService.SetVerificatIdAsync(input, new());
|
||||
var message = "您已被强制下线!";
|
||||
await _noticeService.LogoutAsync(input, verificatInfos, message);//通知下线
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("强退令牌")]
|
||||
public async Task ExitVerificatAsync(ExitVerificatInput input)
|
||||
{
|
||||
//获取该用户的verificat信息
|
||||
List<VerificatInfo> verificatInfos = await _verificatService.GetVerificatIdAsync(input.Id);
|
||||
|
||||
//踢掉包含verificat列表的verificat信息
|
||||
var setVerificats = verificatInfos.Where(it => !input.VerificatIds.Contains(it.Id)).ToList();
|
||||
var deleteVerificats = verificatInfos.Where(it => input.VerificatIds.Contains(it.Id)).ToList();
|
||||
await _verificatService.SetVerificatIdAsync(input.Id, setVerificats);//如果还有verificat则更新verificat
|
||||
|
||||
var message = "您已被强制下线!";
|
||||
await _noticeService.LogoutAsync(input.Id, deleteVerificats, message);//通知下线
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ISqlSugarPagedList<SessionOutput>> PageAsync(SessionPageInput input)
|
||||
{
|
||||
var query = Context.Queryable<SysUser>()
|
||||
.WhereIF(!string.IsNullOrEmpty(input.Account), it => it.Account.Contains(input.Account))//根据账号查询
|
||||
.WhereIF(!string.IsNullOrEmpty(input.LatestLoginIp), it => it.LatestLoginIp.Contains(input.LatestLoginIp))//根据IP查询
|
||||
.OrderBy(it => it.LatestLoginTime, OrderByType.Desc)
|
||||
.Select<SessionOutput>()
|
||||
.Mapper(async it =>
|
||||
{
|
||||
var verificatInfos = await _verificatService.GetVerificatIdAsync(it.Id);
|
||||
if (verificatInfos != null)
|
||||
{
|
||||
GetVerificatInfos(ref verificatInfos);//获取剩余时间
|
||||
it.VerificatCount = verificatInfos.Count;//令牌数量
|
||||
it.VerificatSignList = verificatInfos;//令牌列表
|
||||
|
||||
//如果有客户端ID就是在线
|
||||
it.OnlineStatus = verificatInfos.Any(it => it.ClientIds.Count > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
it.VerificatSignList = new();
|
||||
}
|
||||
|
||||
});
|
||||
for (int i = input.SortField.Count - 1; i >= 0; i--)
|
||||
{
|
||||
query = query.OrderByIF(!string.IsNullOrEmpty(input.SortField[i]), $"{input.SortField[i]} {(input.SortDesc[i] ? "desc" : "asc")}");
|
||||
}
|
||||
|
||||
|
||||
var pageInfo = await query.ToPagedListAsync(input.Current, input.Size);//分页
|
||||
return pageInfo;
|
||||
}
|
||||
|
||||
#region 方法
|
||||
|
||||
/// <summary>
|
||||
/// 获取verificat剩余时间信息
|
||||
/// </summary>
|
||||
private static void GetVerificatInfos(ref List<VerificatInfo> verificatInfos)
|
||||
{
|
||||
verificatInfos.ForEach(it =>
|
||||
{
|
||||
var now = DateTimeExtensions.CurrentDateTime;
|
||||
it.VerificatRemain = now.GetDiffTime(it.VerificatTimeout);//获取时间差
|
||||
var verificatSecond = it.VerificatTimeout.AddMinutes(-it.Expire).ToLong();//颁发时间转为时间戳
|
||||
var timeoutSecond = it.VerificatTimeout.ToLong();//过期时间转为时间戳
|
||||
});
|
||||
}
|
||||
|
||||
#endregion 方法
|
||||
}
|
@@ -1,67 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 单页输入参数
|
||||
/// </summary>
|
||||
public class SpaAddInput : SysResource
|
||||
{
|
||||
/// <summary>
|
||||
/// 路径
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Component不能为空")]
|
||||
public override string Component { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Icon不能为空")]
|
||||
public override string Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单类型
|
||||
/// </summary>
|
||||
public override TargetTypeEnum TargetType { get; set; } = TargetTypeEnum.SELF;
|
||||
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Title不能为空")]
|
||||
public override string Title { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单页输入参数
|
||||
/// </summary>
|
||||
public class SpaPageInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 跳转类型
|
||||
/// </summary>
|
||||
public TargetTypeEnum TargetType { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单页修改参数
|
||||
/// </summary>
|
||||
public class SpaEditInput : SpaAddInput
|
||||
{
|
||||
/// <summary>
|
||||
/// ID
|
||||
/// </summary>
|
||||
[MinValue(1, ErrorMessage = "Id不能为空")]
|
||||
public override long Id { get; set; }
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 单页服务
|
||||
/// </summary>
|
||||
public interface ISpaService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加单页
|
||||
/// </summary>
|
||||
/// <param name="input">添加参数</param>
|
||||
/// <returns></returns>
|
||||
Task AddAsync(SpaAddInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 删除单页
|
||||
/// </summary>
|
||||
/// <param name="input">删除参数</param>
|
||||
/// <returns></returns>
|
||||
Task DeleteAsync(params long[] input);
|
||||
|
||||
/// <summary>
|
||||
/// 编辑单页
|
||||
/// </summary>
|
||||
/// <param name="input">编辑参数</param>
|
||||
/// <returns></returns>
|
||||
Task EditAsync(SpaEditInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<ISqlSugarPagedList<SysResource>> PageAsync(SpaPageInput input);
|
||||
}
|
@@ -1,125 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.FriendlyException;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="ISpaService"/>
|
||||
/// </summary>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class SpaService : DbRepository<SysResource>, ISpaService
|
||||
{
|
||||
private readonly IResourceService _resourceService;
|
||||
|
||||
/// <inheritdoc cref="ISpaService"/>
|
||||
public SpaService(IResourceService resourceService)
|
||||
{
|
||||
this._resourceService = resourceService;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("添加单页")]
|
||||
public async Task AddAsync(SpaAddInput input)
|
||||
{
|
||||
CheckInput(input);//检查参数
|
||||
input.Code = YitIdHelper.NextId().ToString();//code取随机值
|
||||
var sysResource = input.Adapt<SysResource>();//实体转换
|
||||
if (await InsertAsync(sysResource))//插入数据
|
||||
_resourceService.RefreshCache(ResourceCategoryEnum.SPA);//刷新缓存
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("删除单页")]
|
||||
public async Task DeleteAsync(params long[] input)
|
||||
{
|
||||
//获取所有ID
|
||||
var ids = input.ToList();
|
||||
if (ids.Count > 0)
|
||||
{
|
||||
//获取所有
|
||||
var resourceList = await _resourceService.GetListByCategoryAsync(ResourceCategoryEnum.SPA);
|
||||
//找到要删除的
|
||||
var sysresources = resourceList.Where(it => ids.Contains(it.Id)).ToList();
|
||||
//查找内置单页面
|
||||
var system = sysresources.Where(it => it.Code == ResourceConst.System).FirstOrDefault();
|
||||
if (system != null)
|
||||
throw Oops.Bah($"不可删除系统内置单页面:{system.Title}");
|
||||
//删除菜单
|
||||
await DeleteAsync(sysresources);
|
||||
_resourceService.RefreshCache(ResourceCategoryEnum.SPA);//刷新缓存
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("编辑单页")]
|
||||
public async Task EditAsync(SpaEditInput input)
|
||||
{
|
||||
CheckInput(input);//检查参数
|
||||
var sysResource = input.Adapt<SysResource>();//实体转换
|
||||
if (await UpdateAsync(sysResource))//更新数据
|
||||
_resourceService.RefreshCache(ResourceCategoryEnum.SPA);//刷新缓存
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ISqlSugarPagedList<SysResource>> PageAsync(SpaPageInput input)
|
||||
{
|
||||
var query = Context.Queryable<SysResource>()
|
||||
.Where(it => it.Category == ResourceCategoryEnum.SPA)//单页
|
||||
.WhereIF(input.TargetType != 0, it => it.TargetType == input.TargetType)//根据菜单类型查询
|
||||
.WhereIF(!string.IsNullOrEmpty(input.SearchKey), it => it.Title.Contains(input.SearchKey) || it.Component.Contains(input.SearchKey));//根据关键字查询
|
||||
for (int i = input.SortField.Count - 1; i >= 0; i--)
|
||||
{
|
||||
query = query.OrderByIF(!string.IsNullOrEmpty(input.SortField[i]), $"{input.SortField[i]} {(input.SortDesc[i] ? "desc" : "asc")}");
|
||||
}
|
||||
query = query.OrderBy(it => it.SortCode);//排序
|
||||
|
||||
var pageInfo = await query.ToPagedListAsync(input.Current, input.Size);//分页
|
||||
return pageInfo;
|
||||
}
|
||||
|
||||
#region 方法
|
||||
|
||||
/// <summary>
|
||||
/// 检查输入参数
|
||||
/// </summary>
|
||||
/// <param name="sysResource"></param>
|
||||
private void CheckInput(SysResource sysResource)
|
||||
{
|
||||
//判断菜单类型
|
||||
if (sysResource.TargetType == TargetTypeEnum.SELF)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sysResource.Component))
|
||||
{
|
||||
throw Oops.Bah($"组件地址不能为空");
|
||||
}
|
||||
}
|
||||
else if (sysResource.TargetType == TargetTypeEnum.BLANK)//如果是内链或者外链
|
||||
{
|
||||
sysResource.Component = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Oops.Bah($"单页类型错误:{sysResource.TargetType}");//都不是
|
||||
}
|
||||
//设置为单页
|
||||
sysResource.Category = ResourceCategoryEnum.SPA;
|
||||
}
|
||||
|
||||
#endregion 方法
|
||||
}
|
@@ -1,76 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 添加用户参数
|
||||
/// </summary>
|
||||
public class UserAddInput : SysUser
|
||||
{
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "账号不能为空"), MinLength(3, ErrorMessage = "账号不能少于4个字符")]
|
||||
public override string Account { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编辑用户参数
|
||||
/// </summary>
|
||||
public class UserEditInput : UserAddInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "账号不能为空"), MinLength(3, ErrorMessage = "账号不能少于4个字符")]
|
||||
public override string Account { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
[MinValue(1, ErrorMessage = "Id不能为空")]
|
||||
public override long Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户分页查询参数
|
||||
/// </summary>
|
||||
public class UserPageInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 动态查询条件
|
||||
/// </summary>
|
||||
public Expressionable<SysUser> Expression { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户授权角色参数
|
||||
/// </summary>
|
||||
public class UserGrantRoleInput
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 授权权限信息
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "RoleIdList不能为空")]
|
||||
public List<long> RoleIdList { get; set; }
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 选择用户输出参数
|
||||
/// </summary>
|
||||
public class UserSelectorOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
public string Account { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 姓名
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
@@ -1,124 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 用户服务
|
||||
/// </summary>
|
||||
public interface ISysUserService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加用户
|
||||
/// </summary>
|
||||
/// <param name="input">添加参数</param>
|
||||
/// <returns></returns>
|
||||
Task AddAsync(UserAddInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 删除用户
|
||||
/// </summary>
|
||||
/// <param name="input">Id列表</param>
|
||||
/// <returns></returns>
|
||||
Task DeleteAsync(params long[] input);
|
||||
|
||||
/// <summary>
|
||||
/// 从cache中删除用户信息
|
||||
/// </summary>
|
||||
/// <param name="ids">用户ID列表</param>
|
||||
void DeleteUserFromCache(params long[] ids);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 禁用用户
|
||||
/// </summary>
|
||||
/// <param name="input">用户Id</param>
|
||||
/// <returns></returns>
|
||||
Task DisableUserAsync(long input);
|
||||
|
||||
/// <summary>
|
||||
/// 编辑
|
||||
/// </summary>
|
||||
/// <param name="input">编辑参数</param>
|
||||
/// <returns></returns>
|
||||
Task EditAsync(UserEditInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 启用用户
|
||||
/// </summary>
|
||||
/// <param name="input">用户Id</param>
|
||||
/// <returns></returns>
|
||||
Task EnableUserAsync(long input);
|
||||
|
||||
/// <summary>
|
||||
/// 根据用户ID获取按钮ID集合
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<string>> GetButtonCodeListAsync(long userId);
|
||||
|
||||
/// <summary>
|
||||
///根据用户账号获取用户ID
|
||||
/// </summary>
|
||||
/// <param name="account">用户账号</param>
|
||||
/// <returns></returns>
|
||||
Task<long> GetIdByAccountAsync(string account);
|
||||
|
||||
/// <summary>
|
||||
/// 根据账号获取用户信息
|
||||
/// </summary>
|
||||
/// <param name="account">用户名</param>
|
||||
/// <returns>用户信息</returns>
|
||||
Task<SysUser> GetUserByAccountAsync(string account);
|
||||
/// <summary>
|
||||
/// 根据ID获取用户信息
|
||||
/// </summary>
|
||||
/// <param name="Id">用户ID</param>
|
||||
/// <returns>用户信息</returns>
|
||||
Task<SysUser> GetUserByIdAsync(long Id);
|
||||
|
||||
/// <summary>
|
||||
/// 给用户授权角色
|
||||
/// </summary>
|
||||
/// <param name="input">授权参数</param>
|
||||
/// <returns></returns>
|
||||
Task GrantRoleAsync(UserGrantRoleInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户拥有角色
|
||||
/// </summary>
|
||||
/// <param name="input">用户ID</param>
|
||||
/// <returns></returns>
|
||||
Task<List<long>> OwnRoleAsync(BaseIdInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 用户分页查询
|
||||
/// </summary>
|
||||
/// <param name="input">查询参数</param>
|
||||
/// <returns>用户分页列表</returns>
|
||||
Task<ISqlSugarPagedList<SysUser>> PageAsync(UserPageInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 重置密码
|
||||
/// </summary>
|
||||
/// <param name="input">用户Id</param>
|
||||
/// <returns></returns>
|
||||
Task ResetPasswordAsync(long input);
|
||||
|
||||
/// <summary>
|
||||
/// 用户选择器
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<UserSelectorOutput>> UserSelectorAsync(string searchKey);
|
||||
}
|
@@ -1,422 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DataEncryption;
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.FriendlyException;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <inheritdoc cref="ISysUserService"/>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class SysUserService : DbRepository<SysUser>, ISysUserService
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IRelationService _relationService;
|
||||
private readonly IResourceService _resourceService;
|
||||
private readonly IRoleService _roleService;
|
||||
private readonly IVerificatService _verificatService;
|
||||
private readonly IServiceScope _serviceScope;
|
||||
/// <inheritdoc cref="ISysUserService"/>
|
||||
public SysUserService(
|
||||
IRelationService relationService,
|
||||
IResourceService resourceService,
|
||||
IVerificatService verificatService,
|
||||
IRoleService roleService,
|
||||
IConfigService configService,
|
||||
IServiceScopeFactory serviceScopeFactory)
|
||||
{
|
||||
_relationService = relationService;
|
||||
_resourceService = resourceService;
|
||||
_roleService = roleService;
|
||||
_configService = configService;
|
||||
_verificatService = verificatService;
|
||||
_serviceScope = serviceScopeFactory.CreateScope();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("添加用户")]
|
||||
public async Task AddAsync(UserAddInput input)
|
||||
{
|
||||
await CheckInputAsync(input);//检查参数
|
||||
var account_Id = await GetIdByAccountAsync(input.Account);
|
||||
if (account_Id > 0)
|
||||
throw Oops.Bah($"存在重复的账号:{input.Account}");
|
||||
|
||||
var sysUser = input.Adapt<SysUser>();//实体转换
|
||||
|
||||
//获取默认密码
|
||||
sysUser.Password = await GetDefaultPassWord();//设置密码
|
||||
sysUser.UserEnable = true;//默认状态
|
||||
await InsertAsync(sysUser);//添加数据
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("删除用户")]
|
||||
public async Task DeleteAsync(params long[] ids)
|
||||
{
|
||||
//获取所有ID
|
||||
if (ids.Length > 0)
|
||||
{
|
||||
var containsSuperAdmin = await IsAnyAsync(it => it.Account == RoleConst.SuperAdmin && ids.Contains(it.Id));//判断是否有超管
|
||||
if (containsSuperAdmin)
|
||||
throw Oops.Bah($"不可删除系统内置超管用户");
|
||||
if (ids.Contains(UserManager.UserId))
|
||||
throw Oops.Bah($"不可删除自己");
|
||||
|
||||
var result = await DeleteByIdsAsync(ids.Cast<object>().ToArray());
|
||||
if (result)
|
||||
{
|
||||
//从列表中删除
|
||||
foreach (var id in ids)
|
||||
{
|
||||
await _verificatService.SetVerificatIdAsync(id, new());
|
||||
}
|
||||
DeleteUserFromCache(ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DeleteUserFromCache(params long[] ids)
|
||||
{
|
||||
List<SysUser> sysUsers = new();
|
||||
foreach (var item in ids)
|
||||
{
|
||||
var user = _serviceScope.ServiceProvider.GetService<MemoryCache>().Get<SysUser>(CacheConst.CACHE_SYSUSER + item, false);//获取用户列表
|
||||
sysUsers.Add(user);
|
||||
//删除账号
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Remove(CacheConst.CACHE_SYSUSER + item);
|
||||
}
|
||||
sysUsers = sysUsers.Where(it => it != null).ToList();//过滤掉不存在的
|
||||
if (sysUsers.Count > 0)
|
||||
{
|
||||
var accounts = sysUsers.Select(it => it.Account).ToArray();//账号集合
|
||||
foreach (var item in accounts)
|
||||
{
|
||||
//删除账号
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Remove(CacheConst.CAHCE_SYSUSERACCOUNT + item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("禁用用户")]
|
||||
public async Task DisableUserAsync(long input)
|
||||
{
|
||||
var sysUser = await GetUserByIdAsync(input);//获取用户信息
|
||||
if (sysUser != null)
|
||||
{
|
||||
var isSuperAdmin = sysUser.Account == RoleConst.SuperAdmin;//判断是否有超管
|
||||
if (isSuperAdmin)
|
||||
throw Oops.Bah($"不可禁用系统内置超管用户账号");
|
||||
CheckSelf(input, AdminConst.Disable);//判断是不是自己
|
||||
//设置状态为禁用
|
||||
if (await UpdateAsync(it => new SysUser { UserEnable = false }, it => it.Id == input))
|
||||
{
|
||||
//从列表中删除
|
||||
await _verificatService.SetVerificatIdAsync(input, new());
|
||||
DeleteUserFromCache(input);//从cache删除用户信息
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("编辑用户")]
|
||||
public async Task EditAsync(UserEditInput input)
|
||||
{
|
||||
await CheckInputAsync(input);//检查参数
|
||||
var exist = await GetUserByIdAsync(input.Id);//获取用户信息
|
||||
if (exist != null)
|
||||
{
|
||||
var isSuperAdmin = exist.Account == RoleConst.SuperAdmin;//判断是否有超管
|
||||
if (isSuperAdmin && !UserManager.IsSuperAdmin)
|
||||
throw Oops.Bah($"不可修改系统内置超管用户账号");
|
||||
var sysUser = input.Adapt<SysUser>();//实体转换
|
||||
if (await Context.Updateable(sysUser).IgnoreColumns(it =>
|
||||
new
|
||||
{
|
||||
//忽略更新字段
|
||||
it.Password,
|
||||
it.LastLoginDevice,
|
||||
it.LastLoginIp,
|
||||
it.LastLoginTime,
|
||||
it.LatestLoginDevice,
|
||||
it.LatestLoginIp,
|
||||
it.LatestLoginTime
|
||||
}).ExecuteCommandAsync() > 0)//修改数据
|
||||
DeleteUserFromCache(sysUser.Id);//用户缓存到cache
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("启用用户")]
|
||||
public async Task EnableUserAsync(long input)
|
||||
{
|
||||
CheckSelf(input, AdminConst.Enable);//判断是不是自己
|
||||
|
||||
//设置状态为启用
|
||||
if (await UpdateAsync(it => new SysUser { UserEnable = true }, it => it.Id == input))
|
||||
DeleteUserFromCache(input);//从cache删除用户信息
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<string>> GetButtonCodeListAsync(long userId)
|
||||
{
|
||||
List<string> buttonCodeList = new();//按钮ID集合
|
||||
|
||||
//获取关系集合
|
||||
var roleList = await _relationService.GetRelationListByObjectIdAndCategoryAsync(userId, CateGoryConst.Relation_SYS_USER_HAS_ROLE);
|
||||
var roleIdList = roleList.Select(x => x.TargetId.ToLong()).ToList();//角色ID列表
|
||||
if (roleIdList.Count > 0)//如果该用户有角色
|
||||
{
|
||||
List<long> buttonIdList = new();//按钮ID集合
|
||||
var resourceList = await _relationService.GetRelationListByObjectIdListAndCategoryAsync(roleIdList, CateGoryConst.Relation_SYS_ROLE_HAS_RESOURCE);//获取资源集合
|
||||
resourceList.ForEach(it =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(it.ExtJson)) buttonIdList.AddRange(it.ExtJson.FromJsonString<RelationRoleResuorce>().ButtonInfo);//如果有按钮权限,将按钮ID放到buttonIdList
|
||||
});
|
||||
if (buttonIdList.Count > 0)
|
||||
{
|
||||
buttonCodeList = await _resourceService.GetCodeByIdsAsync(buttonIdList, ResourceCategoryEnum.BUTTON);
|
||||
}
|
||||
}
|
||||
return buttonCodeList;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<long> GetIdByAccountAsync(string account)
|
||||
{
|
||||
//先从Cache拿
|
||||
var userId = _serviceScope.ServiceProvider.GetService<MemoryCache>().Get<long>(CacheConst.CAHCE_SYSUSERACCOUNT + account, false);
|
||||
if (userId == 0)
|
||||
{
|
||||
//单查获取用户账号对应ID
|
||||
userId = await GetFirstAsync(it => it.Account == account, it => it.Id);
|
||||
if (userId != 0)
|
||||
{
|
||||
//插入Cache
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Set(CacheConst.CAHCE_SYSUSERACCOUNT + account, userId, false);
|
||||
}
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<string>> GetPermissionListByUserIdAsync(long userId)
|
||||
{
|
||||
var permissions = new List<string>();//权限集合
|
||||
var roleIdList = await _relationService.GetRelationListByObjectIdAndCategoryAsync(userId, CateGoryConst.Relation_SYS_USER_HAS_ROLE);//根据用户ID获取角色ID
|
||||
if (roleIdList.Count > 0)//如果角色ID不为空
|
||||
{
|
||||
//获取角色权限信息
|
||||
var sysRelations = await _relationService.GetRelationListByObjectIdListAndCategoryAsync(roleIdList.Select(it => it.TargetId.ToLong()).ToList(), CateGoryConst.Relation_SYS_ROLE_HAS_PERMISSION);
|
||||
var relationGroup = sysRelations.GroupBy(it => it.TargetId).ToList();//根据目标ID,也就是接口名分组,因为存在一个用户多个角色
|
||||
|
||||
//遍历分组
|
||||
relationGroup.ForEach(it =>
|
||||
{
|
||||
HashSet<string> scopeSet = new();//定义不可重复列表
|
||||
var relationList = it.ToList();//关系列表
|
||||
relationList.ForEach(it =>
|
||||
{
|
||||
var rolePermission = it.ExtJson.FromJsonString<RelationRolePermission>();
|
||||
scopeSet.Add(rolePermission.ApiUrl);
|
||||
});
|
||||
permissions.AddRange(scopeSet);//将改URL的权限集合加入权限集合列表
|
||||
});
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<SysUser> GetUserByAccountAsync(string account)
|
||||
{
|
||||
var userId = await GetIdByAccountAsync(account);//获取用户ID
|
||||
if (userId > 0)
|
||||
{
|
||||
var sysUser = await GetUserByIdAsync(userId);//获取用户信息
|
||||
if (sysUser.Account == account)//这里做了比较用来限制大小写
|
||||
return sysUser;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<SysUser> GetUserByIdAsync(long Id)
|
||||
{
|
||||
//先从Cache拿,需要获取新的对象,避免操作导致缓存中对象改变
|
||||
var sysUser = _serviceScope.ServiceProvider.GetService<MemoryCache>().Get<SysUser>(CacheConst.CACHE_SYSUSER + Id.ToString(), true);
|
||||
if (sysUser == null)
|
||||
{
|
||||
sysUser = await Context.Queryable<SysUser>()
|
||||
.Where(u => u.Id == Id)
|
||||
.FirstAsync();
|
||||
if (sysUser != null)
|
||||
{
|
||||
//获取按钮码
|
||||
var buttonCodeList = await GetButtonCodeListAsync(sysUser.Id);
|
||||
//获取角色码
|
||||
var roleCodeList = await _roleService.GetRoleListByUserIdAsync(sysUser.Id);
|
||||
//获取权限码
|
||||
var permissionCodeList = await GetPermissionListByUserIdAsync(sysUser.Id);
|
||||
|
||||
//权限码赋值
|
||||
sysUser.ButtonCodeList = buttonCodeList;
|
||||
sysUser.RoleCodeList = roleCodeList.Select(it => it.Code).ToList();
|
||||
sysUser.RoleIdList = roleCodeList.Select(it => it.Id).ToList();
|
||||
sysUser.PermissionCodeList = permissionCodeList;
|
||||
//插入Cache
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Set(CacheConst.CACHE_SYSUSER + sysUser.Id.ToString(), sysUser, true);
|
||||
}
|
||||
}
|
||||
return sysUser;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("用户授权")]
|
||||
public async Task GrantRoleAsync(UserGrantRoleInput input)
|
||||
{
|
||||
var sysUser = await GetUserByIdAsync(input.Id);//获取用户信息
|
||||
if (sysUser != null)
|
||||
{
|
||||
var isSuperAdmin = sysUser.Account == RoleConst.SuperAdmin;//判断是否有超管
|
||||
if (isSuperAdmin)
|
||||
throw Oops.Bah($"不能给超管分配角色");
|
||||
CheckSelf(input.Id, AdminConst.GrantRole);//判断是不是自己
|
||||
|
||||
//给用户赋角色
|
||||
await _relationService.SaveRelationBatchAsync(CateGoryConst.Relation_SYS_USER_HAS_ROLE, input.Id, input.RoleIdList.Select(it => it.ToString()).ToList(), null, true);
|
||||
DeleteUserFromCache(input.Id);//从cache删除用户信息
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<long>> OwnRoleAsync(BaseIdInput input)
|
||||
{
|
||||
var relations = await _relationService.GetRelationListByObjectIdAndCategoryAsync(input.Id, CateGoryConst.Relation_SYS_USER_HAS_ROLE);
|
||||
return relations.Select(it => it.TargetId.ToLong()).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ISqlSugarPagedList<SysUser>> PageAsync(UserPageInput input)
|
||||
{
|
||||
var query = Context.Queryable<SysUser>()
|
||||
.WhereIF(input.Expression != null, input.Expression?.ToExpression())//动态查询
|
||||
.WhereIF(!string.IsNullOrEmpty(input.SearchKey), u => u.Account.Contains(input.SearchKey))//根据关键字查询
|
||||
.Mapper(u =>
|
||||
{
|
||||
u.Password = null;//密码清空
|
||||
});
|
||||
for (int i = input.SortField.Count - 1; i >= 0; i--)
|
||||
{
|
||||
query = query.OrderByIF(!string.IsNullOrEmpty(input.SortField[i]), $"{input.SortField[i]} {(input.SortDesc[i] ? "desc" : "asc")}");
|
||||
}
|
||||
query = query.OrderBy(it => it.SortCode);//排序
|
||||
query = query.OrderBy(u => u.Id);//排序
|
||||
|
||||
var pageInfo = await query.ToPagedListAsync(input.Current, input.Size);//分页
|
||||
return pageInfo;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("重置密码")]
|
||||
public async Task ResetPasswordAsync(long input)
|
||||
{
|
||||
var password = await GetDefaultPassWord(true);//获取默认密码,这里不走Aop所以需要加密一下
|
||||
//重置密码
|
||||
if (await UpdateAsync(it => new SysUser { Password = password }, it => it.Id == input))
|
||||
{
|
||||
//从列表中删除
|
||||
await _verificatService.SetVerificatIdAsync(input, new());
|
||||
DeleteUserFromCache(input);//从cache删除用户信息
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<UserSelectorOutput>> UserSelectorAsync(string searchKey)
|
||||
{
|
||||
var result = await Context.Queryable<SysUser>()
|
||||
.WhereIF(!string.IsNullOrEmpty(searchKey), it => it.Account.Contains(searchKey))//根据关键字查询
|
||||
.Select<UserSelectorOutput>()//映射成SysUserSelectorOutput
|
||||
.ToListAsync();
|
||||
return result;
|
||||
}
|
||||
|
||||
#region 方法
|
||||
|
||||
/// <summary>
|
||||
/// 检查输入参数
|
||||
/// </summary>
|
||||
/// <param name="sysUser"></param>
|
||||
private async Task CheckInputAsync(SysUser sysUser)
|
||||
{
|
||||
//判断账号重复,直接从cache拿
|
||||
var account_Id = await GetIdByAccountAsync(sysUser.Account);
|
||||
if (account_Id > 0 && account_Id != sysUser.Id)
|
||||
throw Oops.Bah($"存在重复的账号:{sysUser.Account}");
|
||||
//如果手机号不是空
|
||||
if (!string.IsNullOrEmpty(sysUser.Phone))
|
||||
{
|
||||
if (!sysUser.Phone.MatchPhoneNumber())//验证手机格式
|
||||
throw Oops.Bah($"手机号码:{sysUser.Phone} 格式错误");
|
||||
sysUser.Phone = DESCEncryption.Encrypt(sysUser.Phone, DESCKeyConst.DESCKey);
|
||||
|
||||
}
|
||||
//如果邮箱不是空
|
||||
if (!string.IsNullOrEmpty(sysUser.Email))
|
||||
{
|
||||
var ismatch = sysUser.Email.MatchEmail();//验证邮箱格式
|
||||
if (!ismatch)
|
||||
throw Oops.Bah($"邮箱:{sysUser.Email} 格式错误");
|
||||
if (await IsAnyAsync(it => it.Email == sysUser.Email && it.Id != sysUser.Id))
|
||||
throw Oops.Bah($"存在重复的邮箱:{sysUser.Email}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否为自己
|
||||
/// </summary>
|
||||
private void CheckSelf(long id, string operate)
|
||||
{
|
||||
if (id == UserManager.UserId)//如果是自己
|
||||
{
|
||||
throw Oops.Bah($"禁止{operate}自己");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取默认密码
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task<string> GetDefaultPassWord(bool isSm4 = false)
|
||||
{
|
||||
//获取默认密码
|
||||
var defaultPassword = (await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_PASSWORD)).ConfigValue;
|
||||
return isSm4 ? DESCEncryption.Encrypt(defaultPassword, DESCKeyConst.DESCKey) : defaultPassword;//判断是否需要加密
|
||||
}
|
||||
|
||||
#endregion 方法
|
||||
}
|
@@ -1,59 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 编辑个人信息参数
|
||||
/// </summary>
|
||||
public class UpdateInfoInput : SysUser
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
[MinValue(1, ErrorMessage = "Id不能为空")]
|
||||
public override long Id { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 修改密码
|
||||
/// </summary>
|
||||
public class PasswordInfoInput : BaseIdInput, IValidatableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 旧密码
|
||||
/// </summary>
|
||||
[Description("旧密码")]
|
||||
[Required(ErrorMessage = "不能为空")]
|
||||
public string OldPassword { get; set; }
|
||||
/// <summary>
|
||||
/// 新密码
|
||||
/// </summary>
|
||||
[Description("新密码")]
|
||||
[Required(ErrorMessage = "不能为空")]
|
||||
public string NewPassword { get; set; }
|
||||
/// <summary>
|
||||
/// 确认密码
|
||||
/// </summary>
|
||||
[Description("确认密码")]
|
||||
[Required(ErrorMessage = "不能为空")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (NewPassword != ConfirmPassword)
|
||||
yield return new ValidationResult("两次密码不一致", new[] { nameof(ConfirmPassword) });
|
||||
}
|
||||
}
|
@@ -1,67 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 个人信息中心服务
|
||||
/// </summary>
|
||||
public interface IUserCenterService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 更改密码
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task EditPasswordAsync(PasswordInfoInput input);
|
||||
/// <summary>
|
||||
/// 获取个人主页
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
Task<long> GetLoginDefaultRazorAsync(long userId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取个人首页快捷方式
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<long>> GetLoginWorkbenchAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 获取个人菜单
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<SysResource>> GetOwnMenuAsync(string UserAccount = null);
|
||||
|
||||
/// <summary>
|
||||
/// 设置个人主页
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="defaultRazor"></param>
|
||||
/// <returns></returns>
|
||||
Task UpdateUserDefaultRazorAsync(long userId, long defaultRazor);
|
||||
|
||||
/// <summary>
|
||||
/// 更新个人信息
|
||||
/// </summary>
|
||||
/// <param name="input">信息参数</param>
|
||||
/// <returns></returns>
|
||||
Task UpdateUserInfoAsync(UpdateInfoInput input);
|
||||
/// <summary>
|
||||
/// 编辑个人工作台
|
||||
/// </summary>
|
||||
/// <param name="input">工作台字符串</param>
|
||||
/// <returns></returns>
|
||||
Task UpdateWorkbenchAsync(List<long> input);
|
||||
}
|
@@ -1,214 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DataEncryption;
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.FriendlyException;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
||||
/// <inheritdoc cref="IUserCenterService"/>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class UserCenterService : DbRepository<SysUser>, IUserCenterService
|
||||
{
|
||||
private readonly IRelationService _relationService;
|
||||
private readonly IResourceService _resourceService;
|
||||
private readonly ISysUserService _userService;
|
||||
private readonly IVerificatService _verificatService;
|
||||
|
||||
/// <inheritdoc cref="IUserCenterService"/>
|
||||
public UserCenterService(ISysUserService userService,
|
||||
IRelationService relationService,
|
||||
IResourceService resourceService,
|
||||
IVerificatService verificatService
|
||||
)
|
||||
{
|
||||
_userService = userService;
|
||||
_relationService = relationService;
|
||||
_resourceService = resourceService;
|
||||
_verificatService = verificatService;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("修改密码")]
|
||||
public async Task EditPasswordAsync(PasswordInfoInput input)
|
||||
{
|
||||
var password = DESCEncryption.Encrypt(input.ConfirmPassword, DESCKeyConst.DESCKey);
|
||||
var user = await _userService.GetUserByIdAsync(input.Id);
|
||||
if (user.Password != input.OldPassword)
|
||||
throw Oops.Bah("旧密码不正确");
|
||||
|
||||
if (await UpdateAsync(it => new SysUser { Password = password }, it => it.Id == input.Id))
|
||||
{
|
||||
//从列表中删除
|
||||
await _verificatService.SetVerificatIdAsync(input.Id, new());
|
||||
_userService.DeleteUserFromCache(input.Id);//从cache删除用户信息
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<long>> GetLoginWorkbenchAsync()
|
||||
{
|
||||
//获取个人工作台信息
|
||||
var sysRelation = await _relationService.GetWorkbenchAsync(UserManager.UserId);
|
||||
if (sysRelation != null)
|
||||
{
|
||||
//如果有数据直接返回个人工作台
|
||||
return sysRelation.ExtJson.FromJsonString<List<long>>();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<long> GetLoginDefaultRazorAsync(long userId)
|
||||
{
|
||||
var sysRelations = await _relationService.GetRelationByCategoryAsync(CateGoryConst.Relation_SYS_USER_DEFAULTRAZOR);
|
||||
var result = sysRelations.FirstOrDefault(it => it.ObjectId == userId);//获取个人工作台
|
||||
if (result != null)
|
||||
return result.ExtJson.FromJsonString<long>();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public async Task UpdateUserDefaultRazorAsync(long userId, long defaultRazor)
|
||||
{
|
||||
await _relationService.SaveRelationAsync(CateGoryConst.Relation_SYS_USER_DEFAULTRAZOR, userId, null, defaultRazor.ToJsonString(), true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<SysResource>> GetOwnMenuAsync(string UserAccount = null)
|
||||
{
|
||||
var result = new List<SysResource>();
|
||||
//获取用户信息
|
||||
var userInfo = await _userService.GetUserByAccountAsync(UserAccount ?? UserManager.UserAccount);
|
||||
if (userInfo != null)
|
||||
{
|
||||
//获取所有的菜单和模块和菜单目录以及单页面列表,并按分类和排序码排序
|
||||
var allMenuAndSpaList = await _resourceService.GetaMenuAndSpaListAsync();
|
||||
List<SysResource> allMenuList = new();//菜单列表
|
||||
List<SysResource> allSpaList = new();//单页列表
|
||||
//遍历菜单集合
|
||||
allMenuAndSpaList.ForEach(it =>
|
||||
{
|
||||
switch (it.Category)
|
||||
{
|
||||
case ResourceCategoryEnum.MENU://菜单
|
||||
allMenuList.Add(it);//添加到菜单列表
|
||||
break;
|
||||
|
||||
case ResourceCategoryEnum.SPA://单页
|
||||
allSpaList.Add(it);//添加到单页列表
|
||||
break;
|
||||
}
|
||||
});
|
||||
//输出的用户权限菜单
|
||||
List<SysResource> myMenus = new();
|
||||
//管理员拥有全部权限
|
||||
if (UserManager.IsSuperAdmin)
|
||||
{
|
||||
myMenus = allMenuList;
|
||||
}
|
||||
else
|
||||
{
|
||||
//获取角色所拥有的资源集合
|
||||
var resourceList = await _relationService.GetRelationListByObjectIdListAndCategoryAsync(userInfo.RoleIdList, CateGoryConst.Relation_SYS_ROLE_HAS_RESOURCE);
|
||||
//定义菜单ID列表
|
||||
HashSet<long> rolesMenuIdList = new();
|
||||
//获取拥有权限的菜单Id集合
|
||||
rolesMenuIdList.AddRange(resourceList.Select(r => r.TargetId.ToLong()).ToList());
|
||||
//获取我的菜单列表
|
||||
myMenus = allMenuList.Where(it => rolesMenuIdList.Contains(it.Id)).ToList();
|
||||
}
|
||||
|
||||
// 对获取到的角色对应的菜单列表进行处理,获取父列表
|
||||
var parentList = GetMyParentMenus(allMenuList, myMenus);
|
||||
myMenus.AddRange(parentList);//合并列表
|
||||
|
||||
myMenus.Add(allSpaList.OrderBy(it => it.SortCode).FirstOrDefault());//第一个SPA会添加到菜单作为首页
|
||||
|
||||
//构建菜单树
|
||||
result = _resourceService.ResourceListToTree(myMenus);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
[OperDesc("用户更新个人信息")]
|
||||
public async Task UpdateUserInfoAsync(UpdateInfoInput input)
|
||||
{
|
||||
var newInput = input.Adapt<UpdateInfoInput>();
|
||||
//如果手机号不是空
|
||||
if (!string.IsNullOrEmpty(newInput.Phone))
|
||||
{
|
||||
if (!newInput.Phone.MatchPhoneNumber())//判断是否是手机号格式
|
||||
throw Oops.Bah($"手机号码格式错误");
|
||||
newInput.Phone = DESCEncryption.Encrypt(newInput.Phone, DESCKeyConst.DESCKey);
|
||||
var any = await IsAnyAsync(it => it.Phone == newInput.Phone && it.Id != UserManager.UserId);//判断是否有重复的
|
||||
if (any)
|
||||
throw Oops.Bah($"系统已存在该手机号");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(newInput.Email))
|
||||
{
|
||||
var match = newInput.Email.MatchEmail();
|
||||
if (!match)
|
||||
throw Oops.Bah($"邮箱格式错误");
|
||||
}
|
||||
//更新指定字段
|
||||
var result = await UpdateAsync(it => new SysUser
|
||||
{
|
||||
Email = newInput.Email,
|
||||
Phone = newInput.Phone,
|
||||
}, it => it.Id == UserManager.UserId);
|
||||
if (result)
|
||||
_userService.DeleteUserFromCache(UserManager.UserId);//cache删除用户数据
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[OperDesc("用户更新工作台信息")]
|
||||
public async Task UpdateWorkbenchAsync(List<long> input)
|
||||
{
|
||||
//关系表保存个人工作台
|
||||
await _relationService.SaveRelationAsync(CateGoryConst.Relation_SYS_USER_WORKBENCH_DATA, UserManager.UserId, null, input.ToJsonString(), true);
|
||||
}
|
||||
#region 方法
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取父菜单集合,已过滤掉同时存在的父节点
|
||||
/// </summary>
|
||||
/// <param name="allMenuList">所有菜单列表</param>
|
||||
/// <param name="myMenus">我的菜单列表</param>
|
||||
/// <returns></returns>
|
||||
private List<SysResource> GetMyParentMenus(List<SysResource> allMenuList, List<SysResource> myMenus)
|
||||
{
|
||||
var parentList = new List<SysResource>();
|
||||
myMenus.ForEach(it =>
|
||||
{
|
||||
//找到父ID对应的菜单
|
||||
var parent = allMenuList.Where(r => r.Id == it.ParentId).FirstOrDefault();
|
||||
if (parent != null && !parentList.Contains(parent) && !myMenus.Contains(parent))//如果不为空且夫列表里没有
|
||||
{
|
||||
parentList.Add(parent);//添加到父列表
|
||||
}
|
||||
});
|
||||
return parentList;
|
||||
}
|
||||
|
||||
#endregion 方法
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 验证Id服务
|
||||
/// </summary>
|
||||
public interface IVerificatService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取验证ID
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<VerificatInfo>> GetOpenApiVerificatIdAsync(long userId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取验证ID
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<VerificatInfo>> GetVerificatIdAsync(long userId);
|
||||
/// <summary>
|
||||
/// 设置验证ID
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="values"></param>
|
||||
Task SetOpenApiVerificatIdAsync(long userId, List<VerificatInfo> values);
|
||||
|
||||
/// <summary>
|
||||
/// 设置验证ID
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="values"></param>
|
||||
Task SetVerificatIdAsync(long userId, List<VerificatInfo> values);
|
||||
}
|
@@ -1,110 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <inheritdoc cref="IVerificatService"/>
|
||||
public class VerificatService : DbRepository<SysVerificat>, IVerificatService
|
||||
{
|
||||
private readonly IServiceScope _serviceScope;
|
||||
public VerificatService(IServiceScopeFactory serviceScopeFactory)
|
||||
{
|
||||
_serviceScope = serviceScopeFactory.CreateScope();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<VerificatInfo>> GetOpenApiVerificatIdAsync(long userId)
|
||||
{
|
||||
//先从Cache拿,需要获取新的对象,避免操作导致缓存中对象改变
|
||||
var data = _serviceScope.ServiceProvider.GetService<MemoryCache>().Get<List<VerificatInfo>>(CacheConst.CACHE_OPENAPIUSERVERIFICAT + userId, true);
|
||||
if (data != null)
|
||||
{
|
||||
var infos = data.Where(it => it.VerificatTimeout > DateTimeExtensions.CurrentDateTime).ToList();//去掉登录超时的
|
||||
if (infos.Count != data.Count)
|
||||
await SetOpenApiVerificatIdAsync(userId, infos);
|
||||
return infos;
|
||||
}
|
||||
else
|
||||
{
|
||||
var sys = await Context.Queryable<SysVerificat>().Where(it => it.Id == userId).FirstAsync();
|
||||
if (sys != null)
|
||||
{
|
||||
var infos = sys.VerificatInfos.Where(it => it.VerificatTimeout > DateTimeExtensions.CurrentDateTime).ToList();//去掉登录超时的
|
||||
await SetOpenApiVerificatIdAsync(userId, infos);
|
||||
return infos;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<VerificatInfo>> GetVerificatIdAsync(long userId)
|
||||
{
|
||||
//先从Cache拿,需要获取新的对象,避免操作导致缓存中对象改变
|
||||
var data = _serviceScope.ServiceProvider.GetService<MemoryCache>().Get<List<VerificatInfo>>(CacheConst.CACHE_USERVERIFICAT + userId, true);
|
||||
if (data != null)
|
||||
{
|
||||
var infos = data.Where(it => it.VerificatTimeout > DateTimeExtensions.CurrentDateTime).ToList();//去掉登录超时的
|
||||
if (infos.Count != data.Count)
|
||||
await SetVerificatIdAsync(userId, infos);
|
||||
return infos;
|
||||
}
|
||||
else
|
||||
{
|
||||
var sys = await Context.Queryable<SysVerificat>().Where(it => it.Id == userId).FirstAsync();
|
||||
if (sys != null)
|
||||
{
|
||||
var infos = sys.VerificatInfos.Where(it => it.VerificatTimeout > DateTimeExtensions.CurrentDateTime).ToList();//去掉登录超时的
|
||||
await SetVerificatIdAsync(userId, infos);
|
||||
return infos;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task SetOpenApiVerificatIdAsync(long userId, List<VerificatInfo> values)
|
||||
{
|
||||
SysVerificat sysverificat = new()
|
||||
{
|
||||
Id = userId,
|
||||
VerificatInfos = values
|
||||
};
|
||||
//数据库变化后,更新缓存
|
||||
var x = Context.Storageable(sysverificat).ToStorage();
|
||||
var i1 = await x.AsInsertable.ExecuteCommandAsync();//不存在插入
|
||||
var i2 = await x.AsUpdateable.ExecuteCommandAsync();//存在更新
|
||||
if (i1 + i2 > 0)
|
||||
{
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Set(CacheConst.CACHE_OPENAPIUSERVERIFICAT + userId, values, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task SetVerificatIdAsync(long userId, List<VerificatInfo> values)
|
||||
{
|
||||
SysVerificat sysverificat = new()
|
||||
{
|
||||
Id = userId,
|
||||
VerificatInfos = values
|
||||
};
|
||||
//数据库变化后,更新缓存
|
||||
var x = Context.Storageable(sysverificat).ToStorage();
|
||||
var i1 = await x.AsInsertable.ExecuteCommandAsync();//不存在插入
|
||||
var i2 = await x.AsUpdateable.ExecuteCommandAsync();//存在更新
|
||||
if (i1 + i2 > 0)
|
||||
{
|
||||
_serviceScope.ServiceProvider.GetService<MemoryCache>().Set(CacheConst.CACHE_USERVERIFICAT + userId, values, false);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user