Browse Source

解衝突

upon 10 months ago
parent
commit
6cc0aff7d0
100 changed files with 43611 additions and 8 deletions
  1. 16 2
      TEAMModelBI/Controllers/RepairApi/SchoolRepController.cs
  2. 3 3
      TEAMModelBI/TEAMModelBI.csproj
  3. 0 0
      TEAMModelOS.Extension/Contest.Client/.eslintrc.cjs
  4. 0 0
      TEAMModelOS.Extension/Contest.Client/.gitignore
  5. 0 0
      TEAMModelOS.Extension/Contest.Client/Contest.Client.esproj
  6. 0 0
      TEAMModelOS.Extension/Contest.Client/README.md
  7. 0 0
      TEAMModelOS.Extension/Contest.Client/babel.config.js
  8. 0 0
      TEAMModelOS.Extension/Contest.Client/index.html
  9. 0 0
      TEAMModelOS.Extension/Contest.Client/jsconfig.json
  10. 0 0
      TEAMModelOS.Extension/Contest.Client/nuget.config
  11. 0 0
      TEAMModelOS.Extension/Contest.Client/package.json
  12. 0 0
      TEAMModelOS.Extension/Contest.Client/public/favicon.ico
  13. 0 0
      TEAMModelOS.Extension/Contest.Client/public/index.html
  14. 0 0
      TEAMModelOS.Extension/Contest.Client/public/reset.css
  15. 0 0
      TEAMModelOS.Extension/Contest.Client/src/App.vue
  16. 0 0
      TEAMModelOS.Extension/Contest.Client/src/api/http.js
  17. 0 0
      TEAMModelOS.Extension/Contest.Client/src/api/index.js
  18. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/img/events.jpg
  19. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/img/fengj.jpg
  20. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/img/fengjing.jpg
  21. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/img/no-poster-cn.jpg
  22. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/img/no-poster-cn.png
  23. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/img/noData.png
  24. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/img/noData1.jpg
  25. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/img/zhProcess.png
  26. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/logo.png
  27. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/source/audio.png
  28. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/source/excel.png
  29. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/source/folder.png
  30. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/source/image.png
  31. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/source/item.png
  32. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/source/link.png
  33. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/source/pdf.png
  34. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/source/ppt.png
  35. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/source/unknow.png
  36. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/source/video.png
  37. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/source/word.png
  38. 0 0
      TEAMModelOS.Extension/Contest.Client/src/assets/source/zip.png
  39. 0 0
      TEAMModelOS.Extension/Contest.Client/src/common/Loading.vue
  40. 0 0
      TEAMModelOS.Extension/Contest.Client/src/components/HelloWorld.vue
  41. 0 0
      TEAMModelOS.Extension/Contest.Client/src/locale/i18n.js
  42. 0 0
      TEAMModelOS.Extension/Contest.Client/src/locale/index.js
  43. 0 0
      TEAMModelOS.Extension/Contest.Client/src/locale/lang/en-US.js
  44. 0 0
      TEAMModelOS.Extension/Contest.Client/src/locale/lang/zh-CN.js
  45. 0 0
      TEAMModelOS.Extension/Contest.Client/src/locale/lang/zh-TW.js
  46. 0 0
      TEAMModelOS.Extension/Contest.Client/src/main.js
  47. 0 0
      TEAMModelOS.Extension/Contest.Client/src/pinia/common.js
  48. 0 0
      TEAMModelOS.Extension/Contest.Client/src/pinia/index.js
  49. 0 0
      TEAMModelOS.Extension/Contest.Client/src/router/router.js
  50. 0 0
      TEAMModelOS.Extension/Contest.Client/src/store/index.js
  51. 0 0
      TEAMModelOS.Extension/Contest.Client/src/store/module/config.js
  52. 0 0
      TEAMModelOS.Extension/Contest.Client/src/utils/Global.js
  53. 0 0
      TEAMModelOS.Extension/Contest.Client/src/utils/blobTool.js
  54. 0 0
      TEAMModelOS.Extension/Contest.Client/src/utils/common.js
  55. 0 0
      TEAMModelOS.Extension/Contest.Client/src/utils/directive.js
  56. 0 0
      TEAMModelOS.Extension/Contest.Client/src/utils/js-fn.js
  57. 0 0
      TEAMModelOS.Extension/Contest.Client/src/view/Home.vue
  58. 0 0
      TEAMModelOS.Extension/Contest.Client/src/view/Login.vue
  59. 0 0
      TEAMModelOS.Extension/Contest.Client/src/view/activitylist/ActivityInfo.less
  60. 0 0
      TEAMModelOS.Extension/Contest.Client/src/view/activitylist/ActivityInfo.vue
  61. 0 0
      TEAMModelOS.Extension/Contest.Client/src/view/activitylist/ActivityList.less
  62. 0 0
      TEAMModelOS.Extension/Contest.Client/src/view/activitylist/ActivityList.vue
  63. 0 0
      TEAMModelOS.Extension/Contest.Client/src/view/activitylist/united.json
  64. 0 0
      TEAMModelOS.Extension/Contest.Client/src/view/basicInfo/BasicInfo.vue
  65. 0 0
      TEAMModelOS.Extension/Contest.Client/src/view/homepage/HomePage.vue
  66. 0 0
      TEAMModelOS.Extension/Contest.Client/src/view/myactivity/MyActivity.less
  67. 0 0
      TEAMModelOS.Extension/Contest.Client/src/view/myactivity/MyActivity.vue
  68. 0 0
      TEAMModelOS.Extension/Contest.Client/src/view/myactivity/MyReview.less
  69. 0 0
      TEAMModelOS.Extension/Contest.Client/src/view/myactivity/MyReview.vue
  70. 0 0
      TEAMModelOS.Extension/Contest.Client/vue.config.js
  71. 3 3
      TEAMModelContest/Contest.Server/Contest.Server.csproj
  72. 0 0
      TEAMModelOS.Extension/Contest.Server/Program.cs
  73. 0 0
      TEAMModelOS.Extension/Contest.Server/Properties/ServiceDependencies/contest - Web Deploy/profile.arm.json
  74. 0 0
      TEAMModelOS.Extension/Contest.Server/Properties/ServiceDependencies/contest-test - Web Deploy/profile.arm.json
  75. 0 0
      TEAMModelOS.Extension/Contest.Server/Properties/ServiceDependencies/contest-test - Web Deploy1/profile.arm.json
  76. 0 0
      TEAMModelOS.Extension/Contest.Server/Properties/launchSettings.json
  77. 0 0
      TEAMModelOS.Extension/Contest.Server/appsettings.Development.json
  78. 0 0
      TEAMModelOS.Extension/Contest.Server/appsettings.json
  79. 198 0
      TEAMModelOS.Extension/HTEX.Complex/Controllers/IndexController.cs
  80. 220 0
      TEAMModelOS.Extension/HTEX.Complex/Controllers/OfficialController.cs
  81. 25 0
      TEAMModelOS.Extension/HTEX.Complex/Dockerfile
  82. 20 0
      TEAMModelOS.Extension/HTEX.Complex/HTEX.Complex.csproj
  83. 6 0
      TEAMModelOS.Extension/HTEX.Complex/HTEX.Complex.http
  84. BIN
      TEAMModelOS.Extension/HTEX.Complex/JsonFiles/ip2region.db
  85. 42708 0
      TEAMModelOS.Extension/HTEX.Complex/JsonFiles/latlng.json
  86. 126 0
      TEAMModelOS.Extension/HTEX.Complex/Program.cs
  87. 52 0
      TEAMModelOS.Extension/HTEX.Complex/Properties/launchSettings.json
  88. 188 0
      TEAMModelOS.Extension/HTEX.Complex/Services/SignalRScreenServerHub.cs
  89. 23 0
      TEAMModelOS.Extension/HTEX.Complex/appsettings.Development.json
  90. 23 0
      TEAMModelOS.Extension/HTEX.Complex/appsettings.json
  91. 0 0
      TEAMModelOS.Extension/HTEX.Lib/COMM/Globals.cs
  92. 0 0
      TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/CollectionHelper.cs
  93. 0 0
      TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/ContentTypeDict.cs
  94. 0 0
      TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/CustomXmlResolver.cs
  95. 0 0
      TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/HtmlHelper.cs
  96. 0 0
      TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/StringHelper.cs
  97. 0 0
      TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/WMFConverter/Gdi/BrushDIBColorsEnum.cs
  98. 0 0
      TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/WMFConverter/Gdi/BrushEnum.cs
  99. 0 0
      TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/WMFConverter/Gdi/BrushHSEnum.cs
  100. 0 0
      TEAMModelOS.HTEXLib/COMM/Helpers/WMFConverter/Gdi/FontCharsetEnum.cs

+ 16 - 2
TEAMModelBI/Controllers/RepairApi/SchoolRepController.cs

@@ -576,19 +576,33 @@ namespace TEAMModelBI.Controllers.RepairApi
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("set-allProdAnalysis")]
-        public async Task<IActionResult> SetAllProdAnalysis()
+        public async Task<IActionResult> SetAllProdAnalysis(JsonElement jsonElement)
         {
             var _azureCosmosClient = _azureCosmos.GetCosmosClient();
             var _azureCosmosClientCsv2 = _azureCosmos.GetCosmosClient(name: "CoreServiceV2");
             var _azureCosmosClientCsv2Read = _azureCosmos.GetCosmosClient(name: "CoreServiceV2CnRead");
             var datetime = DateTimeOffset.UtcNow;
             var y = $"{datetime.Year}";
+            string month = (jsonElement.TryGetProperty("month", out JsonElement _month)) ? $"{_month}" : string.Empty;
+            string day = (jsonElement.TryGetProperty("day", out JsonElement _day)) ? $"{_day}" : string.Empty;
             var redisClinet2 = _azureRedis.GetRedisClient(2);
             var keys = new HashSet<RedisKey>();
             int nextCursor = 0;
             do
             {
-                RedisResult redisResult = redisClinet2.Execute("SCAN", nextCursor.ToString(), "MATCH", "TeachingData:*", "COUNT", "1000");
+                string sql = "TeachingData:*";
+                if (!string.IsNullOrWhiteSpace(month)) {
+                    int _m = 0;
+                    string mString = (Int32.TryParse(month, out _m) && _m > 0 && _m < 10) ? $"0{_m}" : $"{_m}";
+                    sql = $"TeachingData:{mString}*"; //[例]TeachingData:08*
+                    if(!string.IsNullOrWhiteSpace(day))
+                    {
+                        int _d = 0;
+                        string dString = (Int32.TryParse(day, out _d) && _d > 0 && _d < 10) ? $"0{_d}" : $"{_d}";
+                        sql = $"TeachingData:{mString}{dString}"; //[例]TeachingData:0801
+                    }
+                }
+                RedisResult redisResult = redisClinet2.Execute("SCAN", nextCursor.ToString(), "MATCH", $"{sql}", "COUNT", "1000");
                 var innerResult = (RedisResult[])redisResult;
                 nextCursor = int.Parse((string)innerResult[0]);
                 List<RedisKey> resultLines = ((RedisKey[])innerResult[1]).ToList();

+ 3 - 3
TEAMModelBI/TEAMModelBI.csproj

@@ -65,9 +65,9 @@
 		<SpaRoot>ClientApp\</SpaRoot>
 		<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
 		<UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-		<Version>5.2407.31</Version>
-		<AssemblyVersion>5.2407.31.1</AssemblyVersion>
-		<FileVersion>5.2407.31.1</FileVersion>
+		<Version>5.2408.14</Version>
+		<AssemblyVersion>5.2408.14.1</AssemblyVersion>
+		<FileVersion>5.2408.14.1</FileVersion>
 		<Description>TEAMModelBI(BI)</Description>
 		<PackageReleaseNotes>BI版本说明版本切换标记2022000908</PackageReleaseNotes>
 		<PackageId>TEAMModelBI</PackageId>

TEAMModelContest/contest.client/.eslintrc.cjs → TEAMModelOS.Extension/Contest.Client/.eslintrc.cjs


TEAMModelContest/contest.client/.gitignore → TEAMModelOS.Extension/Contest.Client/.gitignore


TEAMModelContest/contest.client/contest.client.esproj → TEAMModelOS.Extension/Contest.Client/Contest.Client.esproj


TEAMModelContest/contest.client/README.md → TEAMModelOS.Extension/Contest.Client/README.md


TEAMModelContest/contest.client/babel.config.js → TEAMModelOS.Extension/Contest.Client/babel.config.js


TEAMModelContest/contest.client/index.html → TEAMModelOS.Extension/Contest.Client/index.html


TEAMModelContest/contest.client/jsconfig.json → TEAMModelOS.Extension/Contest.Client/jsconfig.json


TEAMModelContest/contest.client/nuget.config → TEAMModelOS.Extension/Contest.Client/nuget.config


TEAMModelContest/contest.client/package.json → TEAMModelOS.Extension/Contest.Client/package.json


TEAMModelContest/contest.client/public/favicon.ico → TEAMModelOS.Extension/Contest.Client/public/favicon.ico


TEAMModelContest/contest.client/public/index.html → TEAMModelOS.Extension/Contest.Client/public/index.html


TEAMModelContest/contest.client/public/reset.css → TEAMModelOS.Extension/Contest.Client/public/reset.css


TEAMModelContest/contest.client/src/App.vue → TEAMModelOS.Extension/Contest.Client/src/App.vue


TEAMModelContest/contest.client/src/api/http.js → TEAMModelOS.Extension/Contest.Client/src/api/http.js


TEAMModelContest/contest.client/src/api/index.js → TEAMModelOS.Extension/Contest.Client/src/api/index.js


TEAMModelContest/contest.client/src/assets/img/events.jpg → TEAMModelOS.Extension/Contest.Client/src/assets/img/events.jpg


TEAMModelContest/contest.client/src/assets/img/fengj.jpg → TEAMModelOS.Extension/Contest.Client/src/assets/img/fengj.jpg


TEAMModelContest/contest.client/src/assets/img/fengjing.jpg → TEAMModelOS.Extension/Contest.Client/src/assets/img/fengjing.jpg


TEAMModelContest/contest.client/src/assets/img/no-poster-cn.jpg → TEAMModelOS.Extension/Contest.Client/src/assets/img/no-poster-cn.jpg


TEAMModelContest/contest.client/src/assets/img/no-poster-cn.png → TEAMModelOS.Extension/Contest.Client/src/assets/img/no-poster-cn.png


TEAMModelContest/contest.client/src/assets/img/noData.png → TEAMModelOS.Extension/Contest.Client/src/assets/img/noData.png


TEAMModelContest/contest.client/src/assets/img/noData1.jpg → TEAMModelOS.Extension/Contest.Client/src/assets/img/noData1.jpg


TEAMModelContest/contest.client/src/assets/img/zhProcess.png → TEAMModelOS.Extension/Contest.Client/src/assets/img/zhProcess.png


TEAMModelContest/contest.client/src/assets/logo.png → TEAMModelOS.Extension/Contest.Client/src/assets/logo.png


TEAMModelContest/contest.client/src/assets/source/audio.png → TEAMModelOS.Extension/Contest.Client/src/assets/source/audio.png


TEAMModelContest/contest.client/src/assets/source/excel.png → TEAMModelOS.Extension/Contest.Client/src/assets/source/excel.png


TEAMModelContest/contest.client/src/assets/source/folder.png → TEAMModelOS.Extension/Contest.Client/src/assets/source/folder.png


TEAMModelContest/contest.client/src/assets/source/image.png → TEAMModelOS.Extension/Contest.Client/src/assets/source/image.png


TEAMModelContest/contest.client/src/assets/source/item.png → TEAMModelOS.Extension/Contest.Client/src/assets/source/item.png


TEAMModelContest/contest.client/src/assets/source/link.png → TEAMModelOS.Extension/Contest.Client/src/assets/source/link.png


TEAMModelContest/contest.client/src/assets/source/pdf.png → TEAMModelOS.Extension/Contest.Client/src/assets/source/pdf.png


TEAMModelContest/contest.client/src/assets/source/ppt.png → TEAMModelOS.Extension/Contest.Client/src/assets/source/ppt.png


TEAMModelContest/contest.client/src/assets/source/unknow.png → TEAMModelOS.Extension/Contest.Client/src/assets/source/unknow.png


TEAMModelContest/contest.client/src/assets/source/video.png → TEAMModelOS.Extension/Contest.Client/src/assets/source/video.png


TEAMModelContest/contest.client/src/assets/source/word.png → TEAMModelOS.Extension/Contest.Client/src/assets/source/word.png


TEAMModelContest/contest.client/src/assets/source/zip.png → TEAMModelOS.Extension/Contest.Client/src/assets/source/zip.png


TEAMModelContest/contest.client/src/common/Loading.vue → TEAMModelOS.Extension/Contest.Client/src/common/Loading.vue


TEAMModelContest/contest.client/src/components/HelloWorld.vue → TEAMModelOS.Extension/Contest.Client/src/components/HelloWorld.vue


TEAMModelContest/contest.client/src/locale/i18n.js → TEAMModelOS.Extension/Contest.Client/src/locale/i18n.js


TEAMModelContest/contest.client/src/locale/index.js → TEAMModelOS.Extension/Contest.Client/src/locale/index.js


TEAMModelContest/contest.client/src/locale/lang/en-US.js → TEAMModelOS.Extension/Contest.Client/src/locale/lang/en-US.js


TEAMModelContest/contest.client/src/locale/lang/zh-CN.js → TEAMModelOS.Extension/Contest.Client/src/locale/lang/zh-CN.js


TEAMModelContest/contest.client/src/locale/lang/zh-TW.js → TEAMModelOS.Extension/Contest.Client/src/locale/lang/zh-TW.js


TEAMModelContest/contest.client/src/main.js → TEAMModelOS.Extension/Contest.Client/src/main.js


TEAMModelContest/contest.client/src/pinia/common.js → TEAMModelOS.Extension/Contest.Client/src/pinia/common.js


TEAMModelContest/contest.client/src/pinia/index.js → TEAMModelOS.Extension/Contest.Client/src/pinia/index.js


TEAMModelContest/contest.client/src/router/router.js → TEAMModelOS.Extension/Contest.Client/src/router/router.js


TEAMModelContest/contest.client/src/store/index.js → TEAMModelOS.Extension/Contest.Client/src/store/index.js


TEAMModelContest/contest.client/src/store/module/config.js → TEAMModelOS.Extension/Contest.Client/src/store/module/config.js


TEAMModelContest/contest.client/src/utils/Global.js → TEAMModelOS.Extension/Contest.Client/src/utils/Global.js


TEAMModelContest/contest.client/src/utils/blobTool.js → TEAMModelOS.Extension/Contest.Client/src/utils/blobTool.js


TEAMModelContest/contest.client/src/utils/common.js → TEAMModelOS.Extension/Contest.Client/src/utils/common.js


TEAMModelContest/contest.client/src/utils/directive.js → TEAMModelOS.Extension/Contest.Client/src/utils/directive.js


TEAMModelContest/contest.client/src/utils/js-fn.js → TEAMModelOS.Extension/Contest.Client/src/utils/js-fn.js


TEAMModelContest/contest.client/src/view/Home.vue → TEAMModelOS.Extension/Contest.Client/src/view/Home.vue


TEAMModelContest/contest.client/src/view/Login.vue → TEAMModelOS.Extension/Contest.Client/src/view/Login.vue


TEAMModelContest/contest.client/src/view/activitylist/ActivityInfo.less → TEAMModelOS.Extension/Contest.Client/src/view/activitylist/ActivityInfo.less


TEAMModelContest/contest.client/src/view/activitylist/ActivityInfo.vue → TEAMModelOS.Extension/Contest.Client/src/view/activitylist/ActivityInfo.vue


TEAMModelContest/contest.client/src/view/activitylist/ActivityList.less → TEAMModelOS.Extension/Contest.Client/src/view/activitylist/ActivityList.less


TEAMModelContest/contest.client/src/view/activitylist/ActivityList.vue → TEAMModelOS.Extension/Contest.Client/src/view/activitylist/ActivityList.vue


TEAMModelContest/contest.client/src/view/activitylist/united.json → TEAMModelOS.Extension/Contest.Client/src/view/activitylist/united.json


TEAMModelContest/contest.client/src/view/basicInfo/BasicInfo.vue → TEAMModelOS.Extension/Contest.Client/src/view/basicInfo/BasicInfo.vue


TEAMModelContest/contest.client/src/view/homepage/HomePage.vue → TEAMModelOS.Extension/Contest.Client/src/view/homepage/HomePage.vue


TEAMModelContest/contest.client/src/view/myactivity/MyActivity.less → TEAMModelOS.Extension/Contest.Client/src/view/myactivity/MyActivity.less


TEAMModelContest/contest.client/src/view/myactivity/MyActivity.vue → TEAMModelOS.Extension/Contest.Client/src/view/myactivity/MyActivity.vue


TEAMModelContest/contest.client/src/view/myactivity/MyReview.less → TEAMModelOS.Extension/Contest.Client/src/view/myactivity/MyReview.less


TEAMModelContest/contest.client/src/view/myactivity/MyReview.vue → TEAMModelOS.Extension/Contest.Client/src/view/myactivity/MyReview.vue


TEAMModelContest/contest.client/vue.config.js → TEAMModelOS.Extension/Contest.Client/vue.config.js


+ 3 - 3
TEAMModelContest/Contest.Server/Contest.Server.csproj

@@ -1,16 +1,16 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
+<Project Sdk="Microsoft.NET.Sdk.Web">
 
   <PropertyGroup>
     <TargetFramework>net8.0</TargetFramework>
     <Nullable>enable</Nullable>
     <ImplicitUsings>enable</ImplicitUsings>
-    <SpaRoot>..\contest.client</SpaRoot>
+    <SpaRoot>..\Contest.Client</SpaRoot>
     <SpaProxyLaunchCommand>npm run dev</SpaProxyLaunchCommand>
     <SpaProxyServerUrl>https://localhost:5173</SpaProxyServerUrl>
   </PropertyGroup>
 
   <ItemGroup>
-    <ProjectReference Include="..\contest.client\contest.client.esproj">
+    <ProjectReference Include="..\Contest.Client\Contest.Client.esproj">
       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
     </ProjectReference>
   </ItemGroup>

TEAMModelContest/Contest.Server/Program.cs → TEAMModelOS.Extension/Contest.Server/Program.cs


TEAMModelContest/Contest.Server/Properties/ServiceDependencies/contest - Web Deploy/profile.arm.json → TEAMModelOS.Extension/Contest.Server/Properties/ServiceDependencies/contest - Web Deploy/profile.arm.json


TEAMModelContest/Contest.Server/Properties/ServiceDependencies/contest-test - Web Deploy/profile.arm.json → TEAMModelOS.Extension/Contest.Server/Properties/ServiceDependencies/contest-test - Web Deploy/profile.arm.json


TEAMModelContest/Contest.Server/Properties/ServiceDependencies/contest-test - Web Deploy1/profile.arm.json → TEAMModelOS.Extension/Contest.Server/Properties/ServiceDependencies/contest-test - Web Deploy1/profile.arm.json


TEAMModelContest/Contest.Server/Properties/launchSettings.json → TEAMModelOS.Extension/Contest.Server/Properties/launchSettings.json


TEAMModelContest/Contest.Server/appsettings.Development.json → TEAMModelOS.Extension/Contest.Server/appsettings.Development.json


TEAMModelContest/Contest.Server/appsettings.json → TEAMModelOS.Extension/Contest.Server/appsettings.json


+ 198 - 0
TEAMModelOS.Extension/HTEX.Complex/Controllers/IndexController.cs

@@ -0,0 +1,198 @@
+using Azure.Storage.Blobs.Models;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using static TEAMModelOS.SDK.Models.Service.SystemService;
+using System.Collections.Concurrent;
+using System.Text.Json;
+using System.Text;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Models.Service;
+using TEAMModelOS.SDK;
+using TEAMModelOS.SDK.Extension;
+using Azure.Storage.Blobs.Specialized;
+
+namespace HTEX.Complex.Controllers
+{
+    [ApiController]
+    [Route("api")]
+    public class IndexController : ControllerBase
+    {
+        private readonly DingDing _dingDing;
+        private readonly IHttpClientFactory _httpClient;
+        private readonly IConfiguration _configuration;
+        private readonly AzureStorageFactory _azureStorage;
+        private readonly AzureRedisFactory _azureRedis;
+        private readonly IPSearcher _ipSearcher;
+        private readonly Region2LongitudeLatitudeTranslator _longitudeLatitudeTranslator;
+        public IndexController(AzureRedisFactory azureRedis, Region2LongitudeLatitudeTranslator longitudeLatitudeTranslator, IHttpClientFactory httpClient, IConfiguration configuration, AzureStorageFactory azureStorage, IPSearcher searcher, DingDing dingDing)
+        {
+            _httpClient = httpClient;
+            _configuration = configuration;
+            _azureStorage = azureStorage;
+            _ipSearcher = searcher;
+            _dingDing = dingDing;
+            _azureRedis=azureRedis;
+            _longitudeLatitudeTranslator = longitudeLatitudeTranslator;
+        }
+        /// <summary>
+        ///  上传到blob
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [HttpPost("http-log")]
+
+        [RequestSizeLimit(102_400_000_00)] //最大10000m左右
+        public async Task<IActionResult> HttpLog(JsonElement json)
+        {
+            try
+            {
+                string data = json.ToJsonString();
+                var gmt8Time = DateTimeOffset.Now.GetGMTTime(8);
+                var appendBlob = _azureStorage.GetBlobContainerClient("0-service-log").GetAppendBlobClient($"http-log/{gmt8Time:yyyy}/{gmt8Time:MM}/{gmt8Time:dd}/{gmt8Time:HH}.log");
+                if (!await appendBlob.ExistsAsync())
+                {
+                    await appendBlob.CreateAsync();
+                }
+                using (var stream = new MemoryStream(Encoding.UTF8.GetBytes($"{data},\n")))
+                {
+                    await appendBlob.AppendBlockAsync(stream);
+                }
+                return Ok(new { code = 1 });
+            }
+            catch (Exception ex)
+            {
+                return Ok(new { code = 1 });
+            }
+        }
+
+        [HttpPost("report-api-settle")]
+
+        [AllowAnonymous]
+        [RequestSizeLimit(102_400_000_00)] //最大10000m左右
+        public async Task<IActionResult> ReportApiSettle(JsonElement json)
+        {
+
+            List<string> times = json.GetProperty("times").ToObject<List<string>>();
+
+            return Ok(new { });
+        }
+        [HttpPost("report-api-reload")]
+
+        [AllowAnonymous]
+        [RequestSizeLimit(102_400_000_00)] //最大10000m左右
+        public async Task<IActionResult> ReportApiTest(JsonElement json)
+        {
+            try
+            {
+                List<string> times = json.GetProperty("times").ToObject<List<string>>();
+                foreach (var timeDate in times)
+                {
+                    if (DateTimeOffset.TryParse(timeDate, out DateTimeOffset date))
+                    {
+                        var gmt8Time = date.GetGMTTime(8);
+                        var nowGmt8Time = DateTimeOffset.Now.GetGMTTime(8);
+                        List<string> logs = await _azureStorage.GetBlobContainerClient("0-service-log").List($"http-log/{date:yyyy}/{date:MM}/{date:dd}");
+                        List<HttpLog> httpLogs = new List<HttpLog>();
+                        foreach (var log in logs)
+                        {
+                            string nowPath = $"{nowGmt8Time:yyyy/MM/dd/HH}.log";
+                            if (!log.Contains("index.log")  && !log.Contains(".json") &&!log.Contains(nowPath))
+                            {
+                                BlobDownloadResult result = await _azureStorage.GetBlobContainerClient("0-service-log").GetBlobBaseClient(log).DownloadContentAsync();
+                                var content = result.Content.ToString();
+                                content= content.Substring(0, content.Length-2);
+                                if (content.EndsWith("}"))
+                                {
+                                    content=$"[{content}]";
+                                }
+                                else
+                                {
+                                    content=$"[{content}}}]";
+                                }
+                                httpLogs.AddRange(content.ToObject<List<HttpLog>>());
+                            }
+                        }
+                        (ConcurrentBag<ApiVisit> visits, ConcurrentBag<(string uuid, HttpLog httpLog, List<string> tmdid, List<string> school)> uuidInfo)   =
+                            await SystemService.ConvertHttpLog(httpLogs, _azureRedis, _ipSearcher, _longitudeLatitudeTranslator, gmt8Time, true);
+                        if (visits!=null  && visits.Count>0)
+                        {
+                            var appendDayBlob = _azureStorage.GetBlobContainerClient("0-service-log").GetAppendBlobClient($"http-log/{gmt8Time:yyyy}/{gmt8Time:MM}/{gmt8Time:dd}/index.log");
+                            if (!await appendDayBlob.ExistsAsync())
+                            {
+
+                                await appendDayBlob.CreateAsync();
+                            }
+                            else
+                            {
+                                await appendDayBlob.DeleteAsync();
+                                await appendDayBlob.CreateAsync();
+                            }
+                            int maxSize = 4*1024 * 1024; // 1M
+                            List<string> parts = new List<string>();
+                            StringBuilder sb = new StringBuilder();
+
+                            foreach (var item in visits)
+                            {
+                                string jsonString = $"{item.ToJsonString()},\n";
+                                int currentSize = Encoding.UTF8.GetByteCount(sb.ToString());
+
+                                if (currentSize + Encoding.UTF8.GetByteCount(jsonString) > maxSize)
+                                {
+                                    parts.Add(sb.ToString());
+                                    sb.Clear();
+                                }
+
+                                sb.Append(jsonString);
+                            }
+
+                            if (sb.Length > 0)
+                            {
+                                parts.Add(sb.ToString());
+                            }
+
+                            foreach (string part in parts)
+                            {
+                                using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(part)))
+                                {
+                                    await appendDayBlob.AppendBlockAsync(stream);
+                                }
+                            }
+
+
+                            //using (var stream = new MemoryStream(Encoding.UTF8.GetBytes($"{sb}")))
+                            //{
+                            //    await appendDayBlob.AppendBlockAsync(stream);
+                            //}
+                        }
+                    }
+                }
+
+                //全网:用户访问数,学校访问数,学生访问数,不同业务访问量,
+                return Ok(new { });
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
+            }
+            return Ok();
+        }
+
+        /// <summary>
+        /// 使用时长,一天内累计
+        /// </summary>
+        /// <param name="json"></param>
+        /// <returns></returns>
+        [HttpPost("report-api")]
+
+        [AllowAnonymous]
+        [RequestSizeLimit(102_400_000_00)] //最大10000m左右
+        public async Task<IActionResult> ReportApi(JsonElement json)
+        {
+            var force = json.GetProperty("force").GetString();
+            List<string> times = json.GetProperty("times").ToObject<List<string>>();
+            await SystemService.VisitSettle(times, _azureStorage, _azureRedis, _longitudeLatitudeTranslator, _ipSearcher, $"{force}");
+            return Ok(new { code = 200 });
+        }
+
+    }
+}

+ 220 - 0
TEAMModelOS.Extension/HTEX.Complex/Controllers/OfficialController.cs

@@ -0,0 +1,220 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Azure.Cosmos;
+using System.Text.Json;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK;
+
+namespace HTEX.Complex.Controllers
+{
+    [Route("official")]
+    [ApiController]
+    public class OfficialController : ControllerBase
+    {
+
+        private readonly DingDing _dingDing;
+        // private readonly SnowflakeId _snowflakeId;
+        // private readonly ServerSentEventsService _sse;
+        private readonly AzureCosmosFactory _azureCosmos3Factory;
+        private readonly System.Net.Http.IHttpClientFactory _httpClientFactory;
+        //private readonly Models.Option _option;
+        // private readonly MailFactory _mailFactory;
+        private readonly AzureRedisFactory _azureRedis;
+        private readonly AzureStorageFactory _azureStorage;
+        private readonly IWebHostEnvironment _environment;
+        private readonly IConfiguration _configuration;
+        // private readonly CoreAPIHttpService _coreAPIHttpService;
+        private readonly IPSearcher _searcher;
+        public OfficialController(IWebHostEnvironment environment, IConfiguration configuration,
+            AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, System.Net.Http.IHttpClientFactory httpClientFactory, AzureCosmosFactory azureCosmos3Factory,
+            // IOptionsSnapshot<Option> option,  
+            DingDing dingDing, IPSearcher searcher)
+        {
+            _dingDing = dingDing;
+            _azureCosmos3Factory = azureCosmos3Factory;
+            _httpClientFactory = httpClientFactory;
+            _azureRedis = azureRedis;
+            _azureStorage = azureStorage;
+            _environment = environment;
+            _configuration = configuration;
+            _searcher = searcher;
+        }
+
+        [ProducesDefaultResponseType]
+        [RequestSizeLimit(102_400_000_00)] //最大10000m左右
+        [HttpPost("video-ls")]
+        public async Task<IActionResult> VideoUpload()
+        {
+            List<string> students = new List<string>();
+            //var result= await _azureCosmos3Factory.GetCosmosClient().GetContainer("winteachos", Constant.Teacher)
+            //    .GetList<Teacher>( "select value c from c", "Base");
+
+            await foreach (var item in _azureCosmos3Factory.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student)
+                .GetItemQueryIteratorSql<string>(queryText: "select value c.id from c", requestOptions: new QueryRequestOptions { MaxItemCount=5, PartitionKey = new PartitionKey("Base-hbcn") }))
+            {
+                students.Add(item);
+            }
+            return Ok(students);
+        }
+
+        [ProducesDefaultResponseType]
+        [HttpPost("video-list")]
+        public async Task<IActionResult> VideoList(JsonElement json)
+        {
+            List<OfficialVideo> videos = new List<OfficialVideo>();
+            var table = _azureStorage.TableServiceClient().GetTableClient("ShortUrl");
+
+            if (json.TryGetProperty("rowKey", out JsonElement _rowKey) && !string.IsNullOrWhiteSpace($"{_rowKey}"))
+            {
+                videos =    table.Query<OfficialVideo>($"{Constant.PartitionKey} {Constant.Equal} 'OfficialVideo' and {Constant.RowKey} {Constant.Equal} '{_rowKey}'").ToList();
+
+
+            }
+            else
+            {
+                videos =    table.Query<OfficialVideo>(filter: $"{Constant.PartitionKey} eq  'OfficialVideo'").ToList();
+
+            }
+            return Ok(new { videos });
+        }
+
+        [ProducesDefaultResponseType]
+        [RequestSizeLimit(102_400_000_00)] //最大10000m左右
+        [HttpPost("video-upload")]
+        public async Task<IActionResult> VideoUpload([FromForm] string name, [FromForm] string type, [FromForm] string? rowKey = null, [FromForm] IFormFile? videoFile = null)
+        {
+            OfficialVideo video = null;
+            string url = string.Empty;
+            var table = _azureStorage.TableServiceClient().GetTableClient("ShortUrl");
+            if (videoFile == null)
+            {
+                if (!string.IsNullOrWhiteSpace(rowKey))
+                {
+                    try
+                    {
+                        video=await table.GetEntityAsync<OfficialVideo>("OfficialVideo", rowKey);
+                    }
+                    catch { return BadRequest(); }
+                }
+                else
+                {
+                    return BadRequest();
+                }
+            }
+            else
+            {
+                if (!string.IsNullOrWhiteSpace(rowKey))
+                {
+                    try
+                    {
+                        video=await table.GetEntityAsync<OfficialVideo>("OfficialVideo", rowKey);
+                    }
+                    catch { }
+                }
+                if (video== null)
+                {
+                    video= new OfficialVideo { RowKey=$"{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}", PartitionKey="OfficialVideo" };
+                }
+                string fileExt = FileType.GetExtention(videoFile.FileName).ToLower();
+                if (fileExt.Equals("mp4", StringComparison.OrdinalIgnoreCase))
+                {
+                    var url_blob = await _azureStorage.GetBlobContainerClient("0-public").UploadFileByContainer(videoFile.OpenReadStream(), "official", $"{video.RowKey}.{fileExt}", false);
+                    url=url_blob;
+                }
+            }
+            video.name= name;
+            video.type= type;
+            video.url=string.IsNullOrWhiteSpace(url) ? video.url : url;
+            table.UpsertEntity<OfficialVideo>(video);
+            return Ok(new { video });
+        }
+    }
+    //[TableName(Name = "ShortUrl")]
+    public class OfficialVideo : HTableEntity
+    {
+        ///// <summary>
+        ///// OfficialVideo
+        ///// </summary>
+        //public string PartitionKey { get; set; }
+        ///// <summary>
+        ///// 视频id
+        ///// </summary>
+        //public string RowKey { get; set; }
+        /// <summary>
+        /// 名称
+        /// </summary>
+        public string? name { get; set; }
+        /// <summary>
+        /// 类型
+        /// </summary>
+        public string? type { get; set; }
+        /// <summary>
+        /// 地址
+        /// </summary>
+        public string? url { get; set; }
+    }
+    public class Student : CosmosEntity
+    {
+        public string mail { get; set; }
+        public string mobile { get; set; }
+        public string country { get; set; }
+        public string name { get; set; }
+        public string picture { get; set; }
+        public string schoolId { get; set; }
+        public string pw { get; set; }
+        public string salt { get; set; }
+        public int year { get; set; }
+        //座位号
+        public string no { get; set; }   //座位号
+        public string irs { get; set; }
+        //绑定班级Id
+        public string classId { get; set; }
+        //分组信息
+        public string groupId { get; set; }
+        public string groupName { get; set; }
+        public string periodId { get; set; }
+        /// <summary>
+        /// 性别 M( male,男) F (female 女)  N(secret 保密) 
+        /// </summary>
+        public string gender { get; set; }
+
+        //补充留级信息
+        //0在校,1毕业 
+        public int graduate { get; set; } = 0;
+
+        /// <summary>
+        /// 创建时间  十位 时间戳
+        /// </summary>
+        public long createTime { get; set; }
+
+        /// <summary>
+        /// 学生的专业id
+        /// </summary>
+        public string majorId { get; set; }
+        /// <summary>
+        /// 學生的OpenID (TW教育雲綁定ID)
+        /// </summary>
+        public string openId { get; set; }
+    }
+
+    /// <summary>
+    /// 教师
+    /// </summary>
+    public class Teacher : CosmosEntity
+    {
+        public Teacher()
+        {
+            pk = "Teacher";
+        }
+
+        /// <summary>
+        /// 系统权限信息
+        /// </summary>
+        public HashSet<string> permissions { get; set; } = new HashSet<string>();
+        /// <summary>
+        /// 组织信息
+        /// </summary>
+
+        //常用设备信息,及IP登录信息。
+    }
+}

+ 25 - 0
TEAMModelOS.Extension/HTEX.Complex/Dockerfile

@@ -0,0 +1,25 @@
+#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
+
+FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
+USER app
+WORKDIR /app
+EXPOSE 80
+EXPOSE 443
+
+FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
+ARG BUILD_CONFIGURATION=Release
+WORKDIR /src
+COPY ["TEAMModelOS.Extension/HTEX.Complex/HTEX.Complex.csproj", "TEAMModelOS.Extension/HTEX.Complex/"]
+RUN dotnet restore "./TEAMModelOS.Extension/HTEX.Complex/HTEX.Complex.csproj"
+COPY . .
+WORKDIR "/src/TEAMModelOS.Extension/HTEX.Complex"
+RUN dotnet build "./HTEX.Complex.csproj" -c $BUILD_CONFIGURATION -o /app/build
+
+FROM build AS publish
+ARG BUILD_CONFIGURATION=Release
+RUN dotnet publish "./HTEX.Complex.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "HTEX.Complex.dll"]

+ 20 - 0
TEAMModelOS.Extension/HTEX.Complex/HTEX.Complex.csproj

@@ -0,0 +1,20 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <Nullable>enable</Nullable>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <UserSecretsId>1cd8e994-7280-465a-bd0c-ed91a6d66717</UserSecretsId>
+    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
+    <DockerfileContext>..\..</DockerfileContext>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="Microsoft.Azure.SignalR.Management" Version="1.26.0" />
+    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
+	<PackageReference Include="Hangfire" Version="1.8.11" />
+	<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
+	<PackageReference Include="Hangfire.Redis.StackExchange" Version="1.9.3" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\TEAMModelOS.SDK\TEAMModelOS.SDK.csproj" />
+  </ItemGroup>
+</Project>

+ 6 - 0
TEAMModelOS.Extension/HTEX.Complex/HTEX.Complex.http

@@ -0,0 +1,6 @@
+@HTEX.Complex_HostAddress = http://localhost:5181
+
+GET {{HTEX.Complex_HostAddress}}/weatherforecast/
+Accept: application/json
+
+###

BIN
TEAMModelOS.Extension/HTEX.Complex/JsonFiles/ip2region.db


File diff suppressed because it is too large
+ 42708 - 0
TEAMModelOS.Extension/HTEX.Complex/JsonFiles/latlng.json


+ 126 - 0
TEAMModelOS.Extension/HTEX.Complex/Program.cs

@@ -0,0 +1,126 @@
+using Hangfire;
+using Hangfire.Redis.StackExchange;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.IdentityModel.Tokens;
+using System.IdentityModel.Tokens.Jwt;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK;
+using HTEX.Complex.Services;
+namespace HTEX.Complex
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            var builder = WebApplication.CreateBuilder(args);
+
+
+            // Add services to the container.
+
+            JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
+            builder.Services.AddAuthentication(options => options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme)
+                .AddJwtBearer(options => //AzureADJwtBearer
+                {
+                    //options.SaveToken = true; //驗證令牌由服務器生成才有效,不適用於服務重啟或分布式架構
+                    options.Authority ="https://login.chinacloudapi.cn/4807e9cf-87b8-4174-aa5b-e76497d7392b/v2.0";// builder.Configuration["Option:Authority"];
+                    options.Audience = "72643704-b2e7-4b26-b881-bd5865e7a7a5";//builder.Configuration["Option:Audience"];
+                    options.RequireHttpsMetadata = true;
+                    options.TokenValidationParameters = new TokenValidationParameters
+                    {
+                        RoleClaimType = "roles",
+                        //ValidAudiences = new string[] { builder.Configuration["Option:Audience"], $"api://{builder.Configuration["Option:Audience"]}" }
+                        ValidAudiences = new string[] { "72643704-b2e7-4b26-b881-bd5865e7a7a5", $"api://72643704-b2e7-4b26-b881-bd5865e7a7a5" }
+                    };
+                    options.Events = new JwtBearerEvents();
+                    //下列事件有需要紀錄則打開
+                    //options.Events.OnMessageReceived = async context => { await Task.FromResult(0); };
+                    //options.Events.OnForbidden = async context => { await Task.FromResult(0); };
+                    //options.Events.OnChallenge = async context => { await Task.FromResult(0); };
+                    //options.Events.OnAuthenticationFailed = async context => { await Task.FromResult(0); };
+                    options.Events.OnTokenValidated = async context =>
+                    {
+                        if (!context.Principal.Claims.Any(x => x.Type.Equals("http://schemas.microsoft.com/identity/claims/scope")) //ClaimConstants.Scope
+                        && !context.Principal.Claims.Any(y => y.Type.Equals("roles"))) //ClaimConstants.Roles //http://schemas.microsoft.com/ws/2008/06/identity/claims/role
+                        {
+                            //TODO 需處理額外授權非角色及範圍的訪問異常紀錄
+                            throw new UnauthorizedAccessException("Neither scope or roles claim was found in the bearer token.");
+                        }
+                        await Task.FromResult(0);
+                    };
+                });
+            builder.Services.AddControllers();
+#if DEBUG
+            builder.WebHost.UseUrls(new[] { "https://*:7298" });
+#endif
+            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+            builder.Services.AddEndpointsApiExplorer();
+            //builder.Services.AddSwaggerGen();
+            builder.Services.AddHttpClient();
+            string? StorageConnectionString = builder.Configuration.GetValue<string>("Azure:Storage:ConnectionString");
+            string? RedisConnectionString = builder.Configuration.GetValue<string>("Azure:Redis:ConnectionString");
+            string? CosmosConnectionString = builder.Configuration.GetValue<string>("Azure:Cosmos:ConnectionString");
+            //Storage
+            builder.Services.AddAzureStorage(StorageConnectionString, "Default");
+            //Redis
+            builder.Services.AddAzureRedis(RedisConnectionString, "Default");
+            //Cosmos
+            builder.Services.AddAzureCosmos(CosmosConnectionString, "Default");
+
+            //MQTT  服务端API 发送消息到MQTT客户端 https://www.cnblogs.com/weskynet/p/16441219.html
+            builder.Services.AddSignalR();
+            builder.Services.AddHttpContextAccessor();
+            builder.Services.AddHttpClient<DingDing>();
+            string path = $"{builder.Environment.ContentRootPath}/JsonFiles";
+            builder.Services.TryAddSingleton(new Region2LongitudeLatitudeTranslator(path));
+            builder.Services.AddIPSearcher(path);
+            builder.Services.AddCors(options =>
+            {
+                options.AddDefaultPolicy(
+                builder =>
+                {
+
+                    builder.AllowAnyOrigin()
+                            .AllowAnyHeader()
+                            .AllowAnyMethod();
+                });
+            });
+#if !DEBUG
+            builder.Services.AddHangfire(config => {
+                config.UseRedisStorage(builder.Configuration.GetValue<string>("Azure:Redis:ConnectionString"));
+            });
+            builder.Services.AddHangfireServer();
+#endif
+
+            builder.Services.AddControllersWithViews();
+
+            var app = builder.Build();
+
+            // Configure the HTTP request pipeline.
+            if (!app.Environment.IsDevelopment())
+            {
+                app.UseExceptionHandler("/Home/Error");
+                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+                app.UseHsts();
+            }
+
+            app.UseHttpsRedirection();
+            app.UseStaticFiles();
+
+            app.UseRouting();
+            app.UseCors(); //使用跨域設定
+            app.UseHttpsRedirection(); //開發中暫時關掉
+            app.UseAuthentication();
+            app.UseAuthorization();
+            //app.MapControllerRoute(
+            //    name: "default",
+            //    pattern: "{controller=Home}/{action=Index}/{id?}");
+            app.UseEndpoints(endpoints => {
+                endpoints.MapControllers();
+                endpoints.MapFallbackToFile("index.html");
+                endpoints.MapHub<SignalRScreenServerHub>("/signalr/screen").RequireCors("any");
+            });
+            app.Run();
+        }
+    }
+}

+ 52 - 0
TEAMModelOS.Extension/HTEX.Complex/Properties/launchSettings.json

@@ -0,0 +1,52 @@
+{
+  "profiles": {
+    "http": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "launchUrl": "weatherforecast",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      },
+      "dotnetRunMessages": true,
+      "applicationUrl": "http://localhost:5181"
+    },
+    "https": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "launchUrl": "weatherforecast",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      },
+      "dotnetRunMessages": true,
+      "applicationUrl": "https://localhost:7121;http://localhost:5181"
+    },
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": false,
+      "launchUrl": "weatherforecast",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "Container (Dockerfile)": {
+      "commandName": "Docker",
+      "launchBrowser": false,
+      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/weatherforecast",
+      "environmentVariables": {
+        "ASPNETCORE_HTTPS_PORTS": "8081",
+        "ASPNETCORE_HTTP_PORTS": "8080"
+      },
+      "publishAllPorts": true,
+      "useSSL": true
+    }
+  },
+  "$schema": "http://json.schemastore.org/launchsettings.json",
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:37012",
+      "sslPort": 44329
+    }
+  }
+}

+ 188 - 0
TEAMModelOS.Extension/HTEX.Complex/Services/SignalRScreenServerHub.cs

@@ -0,0 +1,188 @@
+using Grpc.Core;
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.Azure.Cosmos.Linq;
+using Microsoft.Extensions.Primitives;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK;
+using System.Web;
+using System.Text;
+
+using StackExchange.Redis;
+namespace HTEX.Complex.Services
+{
+    public class SignalRScreenServerHub : Hub<IClient>
+    {
+
+        private readonly ILogger<SignalRScreenServerHub> _logger;
+        private readonly AzureRedisFactory _azureRedis;
+        public SignalRScreenServerHub(AzureRedisFactory azureRedis, ILogger<SignalRScreenServerHub> logger)
+        {
+            _logger = logger;
+            _azureRedis = azureRedis;
+        }
+
+        /// <summary>
+        /// 客户连接成功时触发
+        /// </summary>
+        /// <returns></returns>
+        public override async Task OnConnectedAsync()
+        {
+            var connid = Context.ConnectionId;
+            var httpContext = Context.GetHttpContext();
+            if (httpContext != null)
+            {
+                //wss://www.winteach.cn/signalr/notify?grant_type=wechat_qrcode&scene=0a75aca57536490ba00fe62e27bb8f6c&id=U2MNiCFNPPuVcw2gUI_gRA
+                //wss://www.winteach.cn/signalr/notify?grant_type=bookjs_api&clientid={clientid}&id=客户端自动生成的
+                httpContext.Request.Query.TryGetValue("grant_type", out StringValues grant_type);
+                httpContext.Request.Query.TryGetValue("clientid", out StringValues clientid);
+                httpContext.Request.Query.TryGetValue("device", out StringValues _device);
+
+                await Groups.AddToGroupAsync(connid, grant_type!);
+                if (!clientid.Equals(StringValues.Empty) && !grant_type.Equals(StringValues.Empty)) {
+
+                    ///连接配置,并且使用钉钉 通知。
+                    ///
+                    var client = new SignalRClient
+                    {
+                        connid = connid,
+                        grant_type = grant_type,
+                        clientid= clientid
+                    };
+                    await _azureRedis.GetRedisClient(8).HashSetAsync($"SignalRClient:connects", connid, client.ToJsonString());
+                    ClientDevice device = HttpUtility.UrlDecode(_device, Encoding.Unicode).ToObject<ClientDevice>();
+                    switch (true) 
+                    {
+                        case bool when grant_type.Equals(ScreenConstant.grant_type):
+                            ScreenClient screenClient ;
+                            var value = await _azureRedis.GetRedisClient(8).HashGetAsync($"ScreenApi:clients", client.clientid);
+                            if (value!=default  && value.HasValue)
+                            {
+                                screenClient = value.ToString().ToObject<ScreenClient>();
+                                
+                                // 这里不强制设置free ,因为如果是重连,可能正在执行任务,需要等待执行完成
+                                //screenClient.status="free";
+
+                                //先检查状态是否是在忙碌,在时间戳范围里,如果不在时间戳范围,强制free。
+                                if (!screenClient.status!.Equals(ScreenConstant.free) && screenClient.last_time  + screenClient.timeout+ screenClient.delay + ScreenConstant.time_excess < DateTimeOffset.UtcNow.ToUnixTimeMilliseconds())
+                                {
+                                    screenClient.status = ScreenConstant.free;
+                                }
+                            }
+                            else 
+                            {
+                                screenClient = new ScreenClient
+                                {
+                                    status = ScreenConstant.free,
+                                };
+                            }
+                            screenClient.connid=connid;
+                            screenClient.grant_type = grant_type;
+                            screenClient.clientid = clientid;
+                            screenClient.os = device.os;
+                            screenClient.port = device.port;
+                            screenClient.name = device.name;
+                            screenClient.region = device.region;
+                            screenClient.remote = device.remote;
+                            screenClient.networks = device.networks;
+                            screenClient.screenUrl = device.screenUrl;
+                            screenClient.delay = device.delay;
+                            screenClient.timeout = device.timeout;
+                            screenClient.last_time= DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+                            //连接成功,发送消息给客户端。
+                            await SendConnection(connid, new ConnectionMessageContent
+                            {
+                                connid=connid,
+                                clientid = clientid,
+                                status = screenClient.status,
+                                grant_type = grant_type,
+                                message_type= MessageType.conn_success,
+                                content = $"连接成功"
+                            });
+                            _logger.LogInformation($"客户端连接成功=>{screenClient.name},{clientid}:\n{screenClient.ToJsonString()}");
+                            if (screenClient.status!.Equals(ScreenConstant.free)) {
+                                _logger.LogInformation($"客户端当前空闲=>{screenClient.name},{clientid},分发任务......");
+                                //连接成功,马上分发任务。
+                                //从尾部弹出元素,队列先进先出
+                                var queueValue = await _azureRedis.GetRedisClient(8).ListRightPopAsync("PDFGen:Queue");
+                                if (queueValue!=default && queueValue.HasValue)
+                                {
+                                    PDFGenQueue genQueue = queueValue.ToString().ToObject<PDFGenQueue>();
+                                    await SendMessage(connid, new ScreenProcessMessageContent
+                                    {
+                                        clientid = clientid,
+                                        status = ScreenConstant.busy,
+                                        grant_type = grant_type,
+                                        content =$"{queueValue.ToString()}",//从Redis中获取任务信息
+                                    });
+                                    screenClient.status =  ScreenConstant.busy;
+                                    screenClient.last_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+                                }
+                                else {
+                                    _logger.LogInformation($"客户端当前空闲=>{screenClient.name},{clientid},暂无任务可领取的任务......");
+                                  
+                                }
+                            }
+                            await _azureRedis.GetRedisClient(8).HashSetAsync($"ScreenApi:clients", client.clientid, screenClient.ToJsonString());
+                            break;
+                    }
+                }
+                else
+                {
+                    await SendConnection(connid, new ConnectionMessageContent
+                    {
+                        clientid = string.Empty,
+                        status =ScreenConstant.error,
+                        grant_type = grant_type,
+                        message_type= MessageType.conn_error,
+                        content = "客户端配置错误",
+                        connid = connid,
+                    });
+                }
+            }
+        }
+
+        public async override Task OnDisconnectedAsync(Exception? exception)
+        {
+            var connid = Context.ConnectionId;
+            var redisData = await _azureRedis.GetRedisClient(8).HashGetAsync($"SignalRClient:connects", connid);
+            _logger.LogInformation($"客户端断开连接=>{connid} ");
+            ///连接配置,并且使用钉钉 离线通知。
+            if (!redisData.IsNullOrEmpty)
+            {
+                var client = redisData.ToString().ToObject<SignalRClient>();
+                await _azureRedis.GetRedisClient(8).HashDeleteAsync($"SignalRClient:connects", connid);
+                if (client != null)
+                {
+                    await Groups.RemoveFromGroupAsync(connid, client.grant_type!);
+                    var value =  await _azureRedis.GetRedisClient(8).HashGetAsync($"ScreenApi:clients", client.clientid);
+                    if (value!=default  && value.HasValue) 
+                    {
+                        ScreenClient screenClient = value.ToString().ToObject<ScreenClient>() ;
+                        _logger.LogInformation($"客户端断开连接=>{connid},{screenClient.name},{screenClient.clientid} ");
+                        long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+                        // 判断是否过期
+                        if (screenClient.status!.Equals(ScreenConstant.busy )  &&    screenClient.last_time+screenClient.timeout+screenClient.delay+ ScreenConstant.time_excess <=now)
+                        {
+                            screenClient.status=ScreenConstant.down;
+                            screenClient.connid= string.Empty;
+                            await _azureRedis.GetRedisClient(8).HashSetAsync($"ScreenApi:clients", client.clientid, screenClient.ToJsonString());
+                        }
+                    }
+                }
+            }
+        }
+        public async Task SendConnection(string connectionId, MessageBody msg)
+        {
+            await Clients.Client(connectionId).ReceiveConnection(msg);
+        }
+        public async Task SendMessage(string connectionId,  MessageBody msg)
+        {
+            await Clients.Client(connectionId).ReceiveMessage(msg);
+        }
+        public async Task SendDisConnection(string connectionId, MessageBody msg)
+        {
+            await Clients.Client(connectionId).ReceiveDisConnection(msg);
+        }
+    }
+}

+ 23 - 0
TEAMModelOS.Extension/HTEX.Complex/appsettings.Development.json

@@ -0,0 +1,23 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"
+    }
+  },
+  "AllowedHosts": "*",
+  "Azure": {
+    "Storage": {
+      "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodeltest;AccountKey=O2W2vadCqexDxWO+px+QK7y1sHwsYj8f/WwKLdOdG5RwHgW/Dupz9dDUb4c1gi6ojzQaRpFUeAAmOu4N9E+37A==;EndpointSuffix=core.chinacloudapi.cn"
+    },
+    "ServiceBus": {
+      "ConnectionString": "Endpoint=sb://coreservicebuscn.servicebus.chinacloudapi.cn/;SharedAccessKeyName=TEAMModelOS;SharedAccessKey=xO8HcvXXuuEkuFI0KlV5uXs8o6vyuVqTR+ASbPGMhHo="
+    },
+    "Redis": {
+      "ConnectionString": "52.130.252.100:6379,password=habook,ssl=false,abortConnect=False,writeBuffer=10240"
+    },
+    "Cosmos": {
+      "ConnectionString": "AccountEndpoint=https://cdhabookdep-free.documents.azure.cn:443/;AccountKey=JTUVk92Gjsx17L0xqxn0X4wX2thDPMKiw4daeTyV1HzPb6JmBeHdtFY1MF1jdctW1ofgzqkDMFOtcqS46by31A==;"
+    }
+  }
+}

+ 23 - 0
TEAMModelOS.Extension/HTEX.Complex/appsettings.json

@@ -0,0 +1,23 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"
+    }
+  },
+  "AllowedHosts": "*",
+  "Azure": {
+    "Storage": {
+      "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelos;AccountKey=Dl04mfZ9hE9cdPVO1UtqTUQYN/kz/dD/p1nGvSq4tUu/4WhiKcNRVdY9tbe8620nPXo/RaXxs+1F9sVrWRo0bg==;EndpointSuffix=core.chinacloudapi.cn",
+    },
+    "ServiceBus": {
+      "ConnectionString": "Endpoint=sb://coreservicebuscn.servicebus.chinacloudapi.cn/;SharedAccessKeyName=TEAMModelOS;SharedAccessKey=xO8HcvXXuuEkuFI0KlV5uXs8o6vyuVqTR+ASbPGMhHo=",
+    },
+    "Redis": {
+      "ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False",
+    },
+    "Cosmos": {
+      "ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;",
+    }
+  }
+}

TEAMModelOS.HTEXLib/COMM/Globals.cs → TEAMModelOS.Extension/HTEX.Lib/COMM/Globals.cs


TEAMModelOS.HTEXLib/COMM/Helpers/CollectionHelper.cs → TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/CollectionHelper.cs


TEAMModelOS.HTEXLib/COMM/Helpers/ContentTypeDict.cs → TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/ContentTypeDict.cs


TEAMModelOS.HTEXLib/COMM/Helpers/CustomXmlResolver.cs → TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/CustomXmlResolver.cs


TEAMModelOS.HTEXLib/COMM/Helpers/HtmlHelper.cs → TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/HtmlHelper.cs


TEAMModelOS.HTEXLib/COMM/Helpers/StringHelper.cs → TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/StringHelper.cs


TEAMModelOS.HTEXLib/COMM/Helpers/WMFConverter/Gdi/BrushDIBColorsEnum.cs → TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/WMFConverter/Gdi/BrushDIBColorsEnum.cs


TEAMModelOS.HTEXLib/COMM/Helpers/WMFConverter/Gdi/BrushEnum.cs → TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/WMFConverter/Gdi/BrushEnum.cs


TEAMModelOS.HTEXLib/COMM/Helpers/WMFConverter/Gdi/BrushHSEnum.cs → TEAMModelOS.Extension/HTEX.Lib/COMM/Helpers/WMFConverter/Gdi/BrushHSEnum.cs


+ 0 - 0
TEAMModelOS.HTEXLib/COMM/Helpers/WMFConverter/Gdi/FontCharsetEnum.cs


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