mirror of
				https://gitee.com/ThingsGateway/ThingsGateway.git
				synced 2025-10-31 23:53:58 +08:00 
			
		
		
		
	Compare commits
	
		
			1241 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 6a025ceee5 | ||
|   | 6b2e53d6dc | ||
|   | b989aa5561 | ||
|   | f5b0b7ebd2 | ||
|   | 16881ae076 | ||
|   | af04112656 | ||
|   | a2863112dc | ||
|   | f531e4dfc5 | ||
|   | 8db9b32ba7 | ||
|   | 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 | 
							
								
								
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -362,7 +362,7 @@ MigrationBackup/ | |||||||
| # Fody - auto-generated XML schema | # Fody - auto-generated XML schema | ||||||
| FodyWeavers.xsd | FodyWeavers.xsd | ||||||
|  |  | ||||||
|  | /src/*Pro*/ | ||||||
| /framework/*pro* | /src/*Pro* | ||||||
| /framework/*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 | # 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 | ||||||
|  |  | ||||||
| ## 赞助 | docker pull registry.cn-shenzhen.aliyuncs.com/thingsgateway/thingsgateway_arm64 | ||||||
|  | ``` | ||||||
| [ThingsGateway赞助途径](https://diego2098.gitee.io/thingsgateway-docs/docs/donate) |  | ||||||
|  |  | ||||||
| ## 社区 |  | ||||||
|  |  | ||||||
| QQ群:605534569 |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### 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.9</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