IESHttpTrigger.cs 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028
  1. using Azure.Cosmos;
  2. using Azure.Storage.Blobs.Models;
  3. using Azure.Storage.Sas;
  4. using HTEXLib.COMM.Helpers;
  5. using HTEXLib.Models;
  6. using Microsoft.Azure.Cosmos.Table;
  7. using Microsoft.Azure.Functions.Worker;
  8. using Microsoft.Azure.Functions.Worker.Http;
  9. using OpenXmlPowerTools;
  10. using StackExchange.Redis;
  11. using System;
  12. using System.Collections.Generic;
  13. using System.Dynamic;
  14. using System.IO;
  15. using System.Linq;
  16. using System.Net;
  17. using System.Net.Http;
  18. using System.Net.Http.Json;
  19. using System.Reflection;
  20. using System.Security.Policy;
  21. using System.Text;
  22. using System.Text.Json;
  23. using System.Threading;
  24. using System.Threading.Tasks;
  25. using System.Web;
  26. using TEAMModelOS.SDK;
  27. using TEAMModelOS.SDK.DI;
  28. using TEAMModelOS.SDK.Extension;
  29. using TEAMModelOS.SDK.Models;
  30. using TEAMModelOS.SDK.Models.Table;
  31. using static TEAMModelOS.SDK.Models.Teacher;
  32. using PuppeteerSharp;
  33. using Path = System.IO.Path;
  34. using DocumentFormat.OpenXml.Bibliography;
  35. namespace TEAMModelOS.FunctionV4.HttpTrigger
  36. {
  37. public class IESHttpTrigger
  38. {
  39. private readonly AzureCosmosFactory _azureCosmos;
  40. private readonly DingDing _dingDing;
  41. private readonly AzureStorageFactory _azureStorage;
  42. private readonly AzureRedisFactory _azureRedis;
  43. private readonly HttpClient _httpClient;
  44. public IESHttpTrigger(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage
  45. , AzureRedisFactory azureRedis, HttpClient httpClient)
  46. {
  47. _azureCosmos = azureCosmos;
  48. _dingDing = dingDing;
  49. _azureStorage = azureStorage;
  50. _azureRedis = azureRedis;
  51. _httpClient = httpClient;
  52. }
  53. /// <summary>
  54. /// 网页截图参数
  55. /// </summary>
  56. public class ScreenshotDto
  57. {
  58. public int width { get; set; } = 1920;
  59. public int height { get; set; } = 1080;
  60. public string? url { get; set; }
  61. public List<string> urls { get; set; } = new List<string>();
  62. public int delay { get; set; }
  63. }
  64. /// <summary>
  65. /// C#使用Puppeteer http://t.zoukankan.com/zhaotianff-p-13528507.html
  66. /// 文档https://learnku.com/docs/puppeteer/3.1.0/class-request/8559
  67. /// https://www.w3cschool.cn/puppeteer/puppeteer-gp1737se.html
  68. /// </summary>
  69. /// <param name="screenshot"></param>
  70. /// <returns></returns>
  71. [Function("screenshot-png")]
  72. public async Task<HttpResponseData> ScreenshotPng([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequestData req )
  73. {
  74. string data = await new StreamReader(req.Body).ReadToEndAsync();
  75. var json = JsonDocument.Parse(data).RootElement;
  76. ScreenshotDto screenshot = json.Deserialize<ScreenshotDto>();
  77. var response = req.CreateResponse(HttpStatusCode.OK);
  78. // 进入容器的命令 docker exec -it f9e27d175498 /bin/bash
  79. //依赖包 https://blog.csdn.net/weixin_45447477/article/details/115188938
  80. //sudo apt-get install libgdk-pixbuf2.0-0 libgdk-pixbuf-xlib-2.0-0 libdbusmenu-gtk3-4 libdbusmenu-glib4 libindicator3-7 ca-certificates fonts-liberation libappindicator3-1 libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils -y
  81. //解决ubuntu18上使用puppeteer https://blog.csdn.net/qq_42414062/article/details/114539378
  82. //https://www.hardkoded.com/blog/running-puppeteer-sharp-azure-functions 使用。
  83. //string url = "https://teammodelos.blob.core.chinacloudapi.cn/0-public/pie-borderRadius.html";
  84. try
  85. {
  86. var bfOptions = new BrowserFetcherOptions();
  87. if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  88. {
  89. string dir = "/app";
  90. if (!Directory.Exists(dir))
  91. {
  92. Directory.CreateDirectory(dir);
  93. }
  94. bfOptions.Path = dir;
  95. }
  96. var bf = new BrowserFetcher(bfOptions);
  97. var revisionInfo = bf.DownloadAsync(BrowserFetcher.DefaultChromiumRevision).Result;
  98. string BrowserExecutablePath = revisionInfo.ExecutablePath;
  99. var browser = await Puppeteer.LaunchAsync(new LaunchOptions
  100. {
  101. ExecutablePath = BrowserExecutablePath,
  102. Headless = true,
  103. Args = new string[] { "--no-sandbox", "--disable-setuid-sandbox" }
  104. });
  105. var page = await browser.NewPageAsync();
  106. bool fullPage = true;
  107. await page.SetViewportAsync(new ViewPortOptions
  108. {
  109. Width = screenshot.width,
  110. Height = screenshot.height
  111. }); ;
  112. fullPage = false;
  113. await page.GoToAsync(System.Web.HttpUtility.UrlDecode(screenshot.url));
  114. Thread.Sleep(screenshot.delay);
  115. string base64 = await page.ScreenshotBase64Async(new ScreenshotOptions { FullPage = fullPage, BurstMode = true });
  116. //关闭浏览器
  117. await browser.CloseAsync();
  118. await browser.DisposeAsync();
  119. await response.WriteAsJsonAsync(new { url = base64, type = "data:image/png;base64," });
  120. return response;
  121. }
  122. catch (Exception ex)
  123. {
  124. await response.WriteAsJsonAsync(new { msg = ex.Message, stack = ex.StackTrace });
  125. return response;
  126. }
  127. }
  128. /// <summary>
  129. /// </summary>
  130. /// <param name="req"></param>
  131. /// <param name="log"></param>
  132. /// <returns></returns>
  133. [Function("system-info-function")]
  134. public async Task<HttpResponseData> SystemInfo([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequestData req)
  135. {
  136. var response = req.CreateResponse(HttpStatusCode.OK);
  137. Type attr = this.GetType();
  138. string currentDirectory = Path.GetDirectoryName(attr.Assembly.Location);
  139. Assembly assembly = Assembly.LoadFrom($"{currentDirectory}\\TEAMModelOS.FunctionV4.dll");
  140. var description = assembly.GetCustomAttribute<AssemblyDescriptionAttribute>().Description;
  141. //var v1 = Assembly.GetEntryAssembly().GetName().Version;
  142. //var v2 = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>().Version;
  143. // var description = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyDescriptionAttribute>().Description;
  144. var version = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>().Version;
  145. long nowtime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  146. //Console.WriteLine($"Assembly.GetEntryAssembly().GetName().Version: " +
  147. // $"{Assembly.GetEntryAssembly().GetName().Version}");5.2107.12.1
  148. //Console.WriteLine($"Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>().Version:" +
  149. // $"{Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>().Version}");5.2107.12.1
  150. //Console.WriteLine($"Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion:" +
  151. // $"{Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion}");5.2107.12
  152. await response.WriteAsJsonAsync(new { version, description, nowtime });
  153. return response;
  154. }
  155. /// <summary>
  156. /// 区级艺术评价变更,异步同步已开启数据同步的学校。
  157. /// </summary>
  158. /// <param name="req"></param>
  159. /// <param name="log"></param>
  160. /// <returns></returns>
  161. [Function("area-artsetting-change")]
  162. public async Task<HttpResponseData> AreaArtSettingChange([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequestData req) {
  163. var response = req.CreateResponse(HttpStatusCode.OK);
  164. try {
  165. string data = await new StreamReader(req.Body).ReadToEndAsync();
  166. var json = JsonDocument.Parse(data).RootElement;
  167. json.TryGetProperty("areaId", out JsonElement _areaId);
  168. string schoolSQL = $"select value c from c where c.areaId='{_areaId}'";
  169. List<School> schools = new List<School>();
  170. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
  171. .GetItemQueryIterator<School>(queryText: schoolSQL, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Base") }))
  172. {
  173. schools.Add(item);
  174. }
  175. ArtSetting artSetting = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).ReadItemAsync<ArtSetting>($"{_areaId}", new PartitionKey("ArtSetting"));
  176. foreach (var school in schools)
  177. {
  178. List<Period> periods = new List<Period>();
  179. var hastype_period = school.period.Where(p => p.type.IsNotEmpty());
  180. if (hastype_period.Any())
  181. {
  182. periods.AddRange(hastype_period);
  183. }
  184. var nottype_period = school.period.Where(p => p.type.IsEmpty());
  185. if (nottype_period.Any())
  186. {
  187. foreach (var period in nottype_period)
  188. {
  189. if (period.name.Contains("小学"))
  190. {
  191. period.type.Add("primary");
  192. }
  193. if (period.name.Contains("初中"))
  194. {
  195. period.type.Add("junior");
  196. }
  197. if (period.name.Contains("高中"))
  198. {
  199. period.type.Add("senior");
  200. }
  201. if (period.type.IsEmpty() && school.period.Count == 1)
  202. {
  203. if (school.name.Contains("小学"))
  204. {
  205. period.type.Add("primary");
  206. }
  207. if (school.name.Contains("初中"))
  208. {
  209. period.type.Add("junior");
  210. }
  211. if (school.name.Contains("高中"))
  212. {
  213. period.type.Add("senior");
  214. }
  215. }
  216. if (period.type.IsNotEmpty())
  217. {
  218. periods.Add(period);
  219. }
  220. }
  221. }
  222. foreach (var period in periods)
  223. {
  224. var dimension = artSetting.dimensions.FindAll(x => x.type.Intersect(period.type).Any());
  225. var bindIds = period.subjects.Where(s => !string.IsNullOrWhiteSpace(s.bindId)).Select(x => x.bindId);
  226. //该学段未同步学科的。
  227. var unBindIds = dimension.Where(z => !string.IsNullOrWhiteSpace(z.subjectBind)).Select(x => x.subjectBind).ToHashSet().Except(bindIds);
  228. if (unBindIds.Any())
  229. {
  230. //尝试寻找同名学科且没有设置bindId的
  231. foreach (var unBindId in unBindIds)
  232. {
  233. var subjects = artSetting.dimensions.FindAll(d => !string.IsNullOrWhiteSpace(d.subjectBind) && !string.IsNullOrWhiteSpace(d.subject) && d.subjectBind.Equals(unBindId))?.Select(m => m.subject);
  234. if (subjects != null)
  235. {
  236. foreach (var subject in subjects)
  237. {
  238. //获取同名学科,且没绑定的
  239. var sub = period.subjects.FindAll(sub => sub.name.Contains(subject) && string.IsNullOrWhiteSpace(sub.bindId));
  240. if (sub.IsNotEmpty())
  241. {
  242. sub[0].bindId = unBindId;
  243. }
  244. else
  245. {
  246. period.subjects.Add(new Subject { id = Guid.NewGuid().ToString(), name = subject, bindId = unBindId, type = 1 });
  247. }
  248. break;
  249. }
  250. }
  251. }
  252. }
  253. var period_subjects = period.subjects.Where(s => !string.IsNullOrWhiteSpace(s.bindId));
  254. foreach (var subject in period_subjects)
  255. {
  256. var dim = dimension.Where(x => x.subjectBind.Equals(subject.bindId));
  257. if (dim.Any())
  258. {
  259. Knowledge old = null;
  260. string sql = $"select value(c) from c where c.periodId = '{period.id}'";
  261. string pk = $"Knowledge-{school.id}-{subject.id}";
  262. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").
  263. GetItemQueryIterator<Knowledge>(queryText: sql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey(pk) }))
  264. {
  265. old = item;
  266. break;
  267. }
  268. //同步知识块。
  269. if (old != null)
  270. {
  271. bool change = false;
  272. //如果之前的是1 来源于区级,后面因区级删除,应该还原为0。
  273. var oldBlocks = old.blocks.Select(x => x.name).ToHashSet();
  274. var dimBlocks = dim.SelectMany(d => d.blocks);
  275. //增加的
  276. var addBlocks = dimBlocks.Except(oldBlocks);
  277. //减少的
  278. var cutBlocks = oldBlocks.Except(dimBlocks);
  279. foreach (var add in addBlocks)
  280. {
  281. old.blocks.Add(new Block { name = add, source = 1 });
  282. change = true;
  283. }
  284. //减少的还原为0
  285. if (cutBlocks.Any())
  286. {
  287. old.blocks.ForEach(ob => {
  288. if (cutBlocks.Contains(ob.name))
  289. {
  290. ob.source = 0;
  291. change = true;
  292. }
  293. });
  294. }
  295. if (change)
  296. {
  297. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(old, old.id, new PartitionKey(old.code));
  298. }
  299. var count = new { pcount = old.points != null ? old.points.Count : 0, bcount = old.blocks != null ? old.blocks.Count : 0 };
  300. //处理知识点,知识块计数问题
  301. await _azureRedis.GetRedisClient(8).HashSetAsync($"Knowledge:Count:{old.owner}-{old.subjectId}", old.periodId, count.ToJsonString());
  302. }
  303. else
  304. {
  305. var blocks = dim.SelectMany(x => x.blocks).Select(bs => new Block { name = bs, source = -1 });
  306. if (blocks.Any())
  307. {
  308. var _new = new Knowledge
  309. {
  310. id = Guid.NewGuid().ToString(),
  311. pk = "Knowledge",
  312. code = pk,
  313. owner = school.id,
  314. periodId = period.id,
  315. subjectId = subject.id,
  316. blocks = blocks.ToList()
  317. };
  318. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(_new, new PartitionKey(_new.code));
  319. var count = new { pcount = _new.points != null ? _new.points.Count : 0, bcount = _new.blocks != null ? _new.blocks.Count : 0 };
  320. //处理知识点,知识块计数问题
  321. await _azureRedis.GetRedisClient(8).HashSetAsync($"Knowledge:Count:{_new.owner}-{_new.subjectId}", _new.periodId, count.ToJsonString());
  322. }
  323. }
  324. }
  325. }
  326. }
  327. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(school, school.id, new PartitionKey(school.code));
  328. }
  329. return response;
  330. } catch (Exception ex) {
  331. await _dingDing.SendBotMsg($"area-artsetting-change,{ex.Message}\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
  332. }
  333. return response;
  334. }
  335. /// <summary>
  336. /// 行政班,学生毕业状态变更。
  337. /// </summary>
  338. /// <param name="req"></param>
  339. /// <param name="log"></param>
  340. /// <returns></returns>
  341. [Function("graduate-change")]
  342. public async Task<HttpResponseData> GraduateChange([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequestData req) {
  343. var response = req.CreateResponse(HttpStatusCode.OK);
  344. dynamic jsondata =new ExpandoObject() ;
  345. try {
  346. string data = await new StreamReader(req.Body).ReadToEndAsync();
  347. var json = JsonDocument.Parse(data).RootElement;
  348. jsondata = json;
  349. //await _dingDing.SendBotMsg( "毕业状态变更:"+json.ToJsonString(), GroupNames.成都开发測試群組);
  350. string schoolId = null;
  351. if (json.TryGetProperty("schoolId", out JsonElement _schoolId))
  352. {
  353. schoolId = $"{_schoolId}";
  354. }
  355. if (string.IsNullOrEmpty(schoolId))
  356. {
  357. return response;
  358. }
  359. //计算毕业的
  360. if (json.TryGetProperty("graduate_classes", out JsonElement _graduate_classes))
  361. {
  362. List<Class> graduate_classes = _graduate_classes.ToObject<List<Class>>();
  363. if (graduate_classes.IsNotEmpty())
  364. {
  365. var ids = graduate_classes.Where(x => !string.IsNullOrWhiteSpace(x.id)).Select(x => $"'{x.id}'");
  366. List<Student> students = new List<Student>();
  367. string sql = $"select value c from c where (c.graduate = 0 or IS_DEFINED(c.graduate) = false) and c.classId in ({string.Join(",", ids)})";
  368. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student)
  369. .GetItemQueryIterator<Student>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Base-{schoolId}") }))
  370. {
  371. item.graduate = 1;
  372. students.Add(item);
  373. }
  374. foreach (var item in students)
  375. {
  376. item.graduate = 1;
  377. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).ReplaceItemAsync<Student>(item, item.id, new PartitionKey($"Base-{schoolId}"));
  378. }
  379. foreach (var item in graduate_classes)
  380. {
  381. item.graduate = 1;
  382. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync<Class>(item, item.id, new PartitionKey($"Class-{schoolId}"));
  383. }
  384. }
  385. }
  386. //未毕业的
  387. if (json.TryGetProperty("cancel_graduate_classes", out JsonElement _cancel_graduate_classes))
  388. {
  389. List<Class> cancel_graduate_classes = _cancel_graduate_classes.ToObject<List<Class>>();
  390. if (cancel_graduate_classes.IsNotEmpty())
  391. {
  392. var ids = cancel_graduate_classes.Where(x => !string.IsNullOrWhiteSpace(x.id)).Select(x => $"'{x.id}'");
  393. List<Student> students = new List<Student>();
  394. string sql = $"select value c from c where c.graduate =1 and c.classId in ({string.Join(",", ids)})";
  395. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student)
  396. .GetItemQueryIterator<Student>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Base-{schoolId}") }))
  397. {
  398. item.graduate = 0;
  399. students.Add(item);
  400. }
  401. foreach (var item in students)
  402. {
  403. item.graduate = 0;
  404. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).ReplaceItemAsync<Student>(item, item.id, new PartitionKey($"Base-{schoolId}"));
  405. }
  406. foreach (var item in cancel_graduate_classes)
  407. {
  408. item.graduate = 0;
  409. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync<Class>(item, item.id, new PartitionKey($"Class-{schoolId}"));
  410. }
  411. }
  412. }
  413. } catch (Exception ex) {
  414. await _dingDing.SendBotMsg($"graduate-change,{ex.Message}\n{ex.StackTrace}\n{jsondata.ToJsonString()}",GroupNames.醍摩豆服務運維群組);
  415. }
  416. return response;
  417. }
  418. /// <summary>
  419. /// 数据推送接口
  420. /// </summary>
  421. /// <param name="req"></param>
  422. /// <param name="log"></param>
  423. /// <returns></returns>
  424. [Function("lesson-tag-change")]
  425. public async Task<HttpResponseData> LessonTagChange([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequestData req) {
  426. var response = req.CreateResponse(HttpStatusCode.OK);
  427. string data = await new StreamReader(req.Body).ReadToEndAsync();
  428. var json = JsonDocument.Parse(data).RootElement;
  429. List<TagOldNew> old_new = null;
  430. string school = null;
  431. if (json.TryGetProperty("school", out JsonElement _school))
  432. {
  433. school = _school.GetString();
  434. }
  435. if (json.TryGetProperty("old_new", out JsonElement _old_new))
  436. {
  437. old_new = _old_new.ToObject<List<TagOldNew>>();
  438. }
  439. if (old_new.IsNotEmpty() && !string.IsNullOrWhiteSpace(school))
  440. {
  441. foreach (var on in old_new)
  442. {
  443. List<LessonRecord> lessonRecords = new List<LessonRecord>();
  444. string sql = $"select value(c) from c where array_contains(c.category,'{on._old}') ";
  445. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<LessonRecord>
  446. (queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonRecord-{_school}") }))
  447. {
  448. lessonRecords.Add(item);
  449. }
  450. lessonRecords.ForEach(item =>
  451. {
  452. //修改标签
  453. if (!string.IsNullOrWhiteSpace(on._new))
  454. {
  455. for (int i = 0; i < item.category.Count; i++)
  456. {
  457. if (item.category[i].Equals(on._old))
  458. {
  459. item.category[i] = on._new;
  460. }
  461. }
  462. }
  463. else
  464. {
  465. //表示删除标签
  466. item.category.RemoveAll(x => x.Equals(on._old));
  467. }
  468. });
  469. foreach (var item in lessonRecords)
  470. {
  471. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(item, item.id, new PartitionKey(item.code));
  472. }
  473. }
  474. }
  475. await response.WriteAsJsonAsync(new { data = json });
  476. return response;
  477. }
  478. /// <summary>
  479. /// 数据推送接口
  480. /// </summary>
  481. /// <param name="req"></param>
  482. /// <param name="log"></param>
  483. /// <returns></returns>
  484. [Function("knowledge-change")]
  485. public async Task<HttpResponseData> KnowledgeChange([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequestData req)
  486. {
  487. var response = req.CreateResponse(HttpStatusCode.OK);
  488. string data = await new StreamReader(req.Body).ReadToEndAsync();
  489. var json = JsonDocument.Parse(data).RootElement;
  490. List<TagOldNew> old_new = null;
  491. string school = null;
  492. if (json.TryGetProperty("school", out JsonElement _school))
  493. {
  494. school = _school.GetString();
  495. }
  496. if (json.TryGetProperty("old_new", out JsonElement _old_new))
  497. {
  498. old_new = _old_new.ToObject<List<TagOldNew>>();
  499. }
  500. if (old_new.IsNotEmpty() && !string.IsNullOrWhiteSpace(school))
  501. {
  502. foreach (var on in old_new)
  503. {
  504. List<ItemInfo> items = new List<ItemInfo>();
  505. string sql = $"select value(c) from c where array_contains(c.knowledge,'{on._old}') ";
  506. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ItemInfo>
  507. (queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{_school}") }))
  508. {
  509. items.Add(item);
  510. }
  511. items.ForEach(item =>
  512. {
  513. //修改知识点
  514. if (!string.IsNullOrEmpty(on._new))
  515. {
  516. for (int i = 0; i < item.knowledge.Count; i++)
  517. {
  518. if (item.knowledge[i].Equals(on._old))
  519. {
  520. item.knowledge[i] = on._new;
  521. }
  522. }
  523. }
  524. else
  525. {
  526. //表示删除知识点
  527. item.knowledge.RemoveAll(x => x.Equals(on._old));
  528. }
  529. });
  530. foreach (var item in items)
  531. {
  532. ItemBlob itemBlob = null;
  533. try
  534. {
  535. BlobDownloadInfo blobDownloadResult = await _azureStorage.GetBlobContainerClient($"{school}").GetBlobClient($"/item/{item.id}/{item.id}.json").DownloadAsync();
  536. if (blobDownloadResult != null)
  537. {
  538. var blob = JsonDocument.Parse(blobDownloadResult.Content);
  539. itemBlob = blob.RootElement.ToObject<ItemBlob>();
  540. itemBlob.exercise.knowledge = item.knowledge;
  541. await _azureStorage.GetBlobContainerClient($"{school}").UploadFileByContainer(itemBlob.ToJsonString(), "item", $"{item.id}/{item.id}.json", true);
  542. }
  543. }
  544. catch (Exception ex)
  545. {
  546. itemBlob = null;
  547. }
  548. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(item, item.id, new PartitionKey(item.code));
  549. }
  550. }
  551. }
  552. await response.WriteAsJsonAsync(new { data = json });
  553. return response;
  554. }
  555. /// <summary>
  556. /// 在线人数记录
  557. /// </summary>
  558. /// <param name="msg"></param>
  559. /// <returns></returns>
  560. [Function("online-record")]
  561. public async Task<HttpResponseData> OnlineRecord([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequestData req)
  562. {
  563. var response = req.CreateResponse(HttpStatusCode.OK);
  564. string data = await new StreamReader(req.Body).ReadToEndAsync();
  565. var json = JsonDocument.Parse(data).RootElement;
  566. try
  567. {
  568. string school = null;
  569. string scope = null;
  570. string id = null;
  571. string ip = null;
  572. int expire = 1;
  573. if (json.TryGetProperty("school", out JsonElement _school))
  574. school = _school.GetString();
  575. if (json.TryGetProperty("scope", out JsonElement _scope))
  576. scope = _scope.GetString();
  577. if (json.TryGetProperty("id", out JsonElement _id))
  578. id = _id.GetString();
  579. if (json.TryGetProperty("ip", out JsonElement _ip))
  580. ip = _ip.GetString();
  581. if (json.TryGetProperty("expire", out JsonElement _expire))
  582. expire = _expire.GetInt32();
  583. var table = _azureStorage.GetCloudTableClient().GetTableReference("IESLogin");
  584. var cosmosClient = _azureCosmos.GetCosmosClient();
  585. DateTimeOffset dateTime = DateTimeOffset.UtcNow;
  586. var dateHour = dateTime.ToString("yyyyMMddHH"); //获取当天的小时
  587. var dateDay = dateTime.ToString("yyyyMMdd"); //获取当天的日期
  588. var dateMonth = dateTime.ToString("yyyyMM");//获取当月的日期
  589. var currentHour = dateTime.Hour; //当前小时
  590. var currentDay = dateTime.Day; //当前天
  591. long Expire = dateTime.AddHours(expire).ToUnixTimeMilliseconds(); //token到期时间
  592. long now = dateTime.ToUnixTimeMilliseconds(); //当前时间戳
  593. DateTime hour = DateTime.UtcNow.AddHours(25); //25小时到期
  594. DateTime month = DateTime.UtcNow.AddDays(32); //一个月到期
  595. var delTbHour = dateTime.AddHours(-168).ToString("yyyyMMddHH"); //168小时前
  596. var delTbDay = dateTime.AddDays(-180).ToString("yyyyMMdd"); //180天前
  597. switch (scope)
  598. {
  599. case "teacher":
  600. try
  601. {
  602. Teacher teacher = await cosmosClient.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<Teacher>(id, new PartitionKey("Base"));
  603. teacher.loginInfos = new List<LoginInfo>() { new LoginInfo { expire = Expire, ip = ip, time = now } };
  604. await cosmosClient.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Teacher>(teacher, teacher.id, new PartitionKey("Base"));
  605. }
  606. catch { }
  607. break;
  608. case "student":
  609. try
  610. {
  611. Student student = await cosmosClient.GetContainer("TEAMModelOS", Constant.Student).ReadItemAsync<Student>(id, new PartitionKey($"Base-{school}"));
  612. student.loginInfos = new List<LoginInfo>() { new LoginInfo { expire = Expire, ip = ip, time = now } };
  613. await cosmosClient.GetContainer("TEAMModelOS", Constant.Student).ReplaceItemAsync<Student>(student, student.id, new PartitionKey($"Base-{school}"));
  614. }
  615. catch { }
  616. break;
  617. case "tmduser":
  618. try
  619. {
  620. TmdUser tmdUser = await cosmosClient.GetContainer("TEAMModelOS", Constant.Student).ReadItemAsync<TmdUser>(id, new PartitionKey("Base"));
  621. tmdUser.loginInfos = new List<LoginInfo>() { new LoginInfo { expire = Expire, ip = ip, time = now } };
  622. await cosmosClient.GetContainer("TEAMModelOS", Constant.Student).ReplaceItemAsync<TmdUser>(tmdUser, tmdUser.id, new PartitionKey("Base"));
  623. }
  624. catch { }
  625. break;
  626. }
  627. //天
  628. SortedSetEntry[] dayCnt = null;
  629. //月
  630. SortedSetEntry[] monthCnt = null;
  631. try
  632. {
  633. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Login:IES:{scope}:{dateDay}", $"{currentHour}", 1);//一天24小时 小时为单位
  634. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Login:IES:{scope}:{dateMonth}", $"{currentDay}", 1); //一天的累计 天为单位
  635. var resDay = await _azureRedis.GetRedisClient(8).KeyTimeToLiveAsync($"Login:IES:{scope}:{dateDay}");
  636. if (resDay == null)
  637. await _azureRedis.GetRedisClient(8).KeyExpireAsync($"Login:IES:{scope}:{dateDay}", hour); //设置到期时间
  638. var rspMonth = await _azureRedis.GetRedisClient(8).KeyTimeToLiveAsync($"Login:IES:{scope}:{dateMonth}");
  639. if (rspMonth == null)
  640. await _azureRedis.GetRedisClient(8).KeyExpireAsync($"Login:IES:{scope}:{dateMonth}", month); //设置到期时间
  641. //保存当前小时统计
  642. dayCnt = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Login:IES:{scope}:{dateDay}");
  643. //保存当前的统计数据
  644. monthCnt = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Login:IES:{scope}:{dateMonth}");
  645. }
  646. catch { }
  647. if (dayCnt != null && dayCnt.Length > 0)
  648. {
  649. List<HourLogin> hourLogins = new();
  650. foreach (var dCnt in dayCnt)
  651. {
  652. if (((int)dCnt.Element) == currentHour)
  653. {
  654. var tphourLogins = await table.QueryWhereString<HourLogin>($"PartitionKey eq 'HourLogin' and RowKey eq '{dateHour}'");
  655. if (tphourLogins.Count > 0)
  656. {
  657. foreach (var hourLogin in tphourLogins)
  658. {
  659. if (scope.Equals("teacher"))
  660. hourLogin.Teacher = (int)dCnt.Score;
  661. else if (scope.Equals("student"))
  662. hourLogin.Student = (int)dCnt.Score;
  663. else
  664. hourLogin.TmdUser = (int)dCnt.Score;
  665. hourLogins.Add(hourLogin);
  666. }
  667. }
  668. else
  669. {
  670. HourLogin hourLogin = new() { PartitionKey = $"HourLogin", RowKey = dateHour, Hour = currentHour };
  671. if (scope.Equals("teacher"))
  672. {
  673. hourLogin.Teacher = 1;
  674. hourLogin.Student = 0;
  675. hourLogin.TmdUser = 0;
  676. }
  677. else if (scope.Equals("student"))
  678. {
  679. hourLogin.Teacher = 0;
  680. hourLogin.Student = 1;
  681. hourLogin.TmdUser = 0;
  682. }
  683. else
  684. {
  685. hourLogin.Teacher = 0;
  686. hourLogin.Student = 0;
  687. hourLogin.TmdUser = 1;
  688. }
  689. hourLogins.Add(hourLogin);
  690. }
  691. }
  692. }
  693. await table.SaveOrUpdateAll(hourLogins); //保存和更新保存当前小时登录次数
  694. }
  695. if (monthCnt != null && monthCnt.Length > 0)
  696. {
  697. List<DayLogin> dayLogins = new();
  698. foreach (var mCnt in monthCnt)
  699. {
  700. if (((int)mCnt.Element) == currentDay)
  701. {
  702. //保存当天的峰值
  703. var tbDays = await table.QueryWhereString<DayLogin>($"PartitionKey eq 'DayLogin' and RowKey eq '{dateDay}'");
  704. if (tbDays.Count > 0)
  705. {
  706. foreach (var dayLogin in tbDays)
  707. {
  708. if (scope.Equals("teacher"))
  709. dayLogin.Teacher = (int)mCnt.Score;
  710. else if (scope.Equals("student"))
  711. dayLogin.Student = (int)mCnt.Score;
  712. else
  713. dayLogin.TmdUser = (int)mCnt.Score;
  714. dayLogins.Add(dayLogin);
  715. }
  716. }
  717. else
  718. {
  719. //保存当月每天的峰值
  720. DayLogin dayLogin = new() { PartitionKey = $"DayLogin", RowKey = dateDay, Day = currentDay };
  721. if (scope.Equals("teacher"))
  722. {
  723. dayLogin.Teacher = 1;
  724. dayLogin.Student = 0;
  725. dayLogin.TmdUser = 0;
  726. }
  727. else if (scope.Equals("student"))
  728. {
  729. dayLogin.Teacher = 0;
  730. dayLogin.Student = 1;
  731. dayLogin.TmdUser = 0;
  732. }
  733. else
  734. {
  735. dayLogin.Teacher = 0;
  736. dayLogin.Student = 0;
  737. dayLogin.TmdUser = 1;
  738. }
  739. dayLogins.Add(dayLogin);
  740. }
  741. }
  742. }
  743. await table.SaveOrUpdateAll(dayLogins);// 保存当月每天在线数据
  744. }
  745. string tbHourSql = $"PartitionKey eq 'HourLogin' and RowKey le '{delTbHour}'";
  746. string tbDaySql = $"PartitionKey eq 'DayLogin' and RowKey le '{delTbDay}'";
  747. try
  748. {
  749. await table.DeleteStringWhere<HourLogin>(rowKey: tbHourSql); //删除168小时前的数据
  750. await table.DeleteStringWhere<DayLogin>(rowKey: tbDaySql); //删除180天前的数据
  751. }
  752. catch { }
  753. if (!string.IsNullOrWhiteSpace(school))
  754. {
  755. //天
  756. SortedSetEntry[] scDayCnt = null;
  757. //月
  758. SortedSetEntry[] scMonthCnt = null;
  759. try
  760. {
  761. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Login:School:{school}:{scope}:{dateDay}", $"{currentHour}", 1);//当天当前小时在线人加1
  762. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Login:School:{school}:{scope}:{dateMonth}", $"{currentDay}", 1); //当天的在线加1
  763. var reScDay = await _azureRedis.GetRedisClient(8).KeyTimeToLiveAsync($"Login:School:{school}:{scope}:{dateDay}");
  764. if (reScDay == null)
  765. await _azureRedis.GetRedisClient(8).KeyExpireAsync($"Login:School:{school}:{scope}:{dateDay}", hour); //设置到期时间
  766. var reScMonth = await _azureRedis.GetRedisClient(8).KeyTimeToLiveAsync($"Login:School:{school}:{scope}:{dateMonth}");
  767. if (reScMonth == null)
  768. await _azureRedis.GetRedisClient(8).KeyExpireAsync($"Login:School:{school}:{scope}:{dateMonth}", month); //设置到期时间
  769. //保存学校当天每小时的
  770. scDayCnt = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Login:School:{school}:{scope}:{dateDay}");
  771. //学校天峰值
  772. scMonthCnt = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Login:School:{school}:{scope}:{dateMonth}");
  773. }
  774. catch { }
  775. if (scDayCnt != null && scDayCnt.Length > 0)
  776. {
  777. List<HourLoginSchool> hourLoginSchools = new();
  778. foreach (var scDCnt in scDayCnt)
  779. {
  780. if (((int)scDCnt.Element) == currentHour)
  781. {
  782. var tmpHour = await table.QueryWhereString<HourLoginSchool>($"PartitionKey eq 'HourLogin-{school}' and RowKey eq '{dateHour}'");
  783. if (tmpHour.Count > 0)
  784. {
  785. foreach (var hLoginSc in tmpHour)
  786. {
  787. if (scope.Equals("teacher"))
  788. hLoginSc.Teacher = (int)scDCnt.Score;
  789. else if (scope.Equals("student"))
  790. hLoginSc.Student = (int)scDCnt.Score;
  791. else
  792. hLoginSc.TmdUser = (int)scDCnt.Score;
  793. hourLoginSchools.Add(hLoginSc);
  794. }
  795. }
  796. else
  797. {
  798. //学校小时峰值
  799. HourLoginSchool hourLoginSc = new() { PartitionKey = $"HourLogin-{school}", RowKey = dateHour, Hour = currentHour, School = school };
  800. if (scope.Equals("teacher"))
  801. {
  802. hourLoginSc.Teacher = 1;
  803. hourLoginSc.Student = 0;
  804. hourLoginSc.TmdUser = 0;
  805. }
  806. else if (scope.Equals("student"))
  807. {
  808. hourLoginSc.Teacher = 0;
  809. hourLoginSc.Student = 1;
  810. hourLoginSc.TmdUser = 0;
  811. }
  812. else
  813. {
  814. hourLoginSc.Teacher = 0;
  815. hourLoginSc.Student = 0;
  816. hourLoginSc.TmdUser = 1;
  817. }
  818. hourLoginSchools.Add(hourLoginSc);
  819. }
  820. }
  821. }
  822. await table.SaveOrUpdateAll(hourLoginSchools);
  823. }
  824. if (scMonthCnt != null && scMonthCnt.Length > 0)
  825. {
  826. List<DayLoginSchool> DayLoginSchools = new();
  827. foreach (var scMCnt in scMonthCnt)
  828. {
  829. if (((int)scMCnt.Element) == currentDay)
  830. {
  831. var tempDays = await table.QueryWhereString<DayLoginSchool>($"PartitionKey eq 'DayLogin-{school}' and RowKey eq '{dateDay}'");
  832. if (tempDays.Count > 0)
  833. {
  834. foreach (var dLoginSc in tempDays)
  835. {
  836. if (scope.Equals("teacher"))
  837. dLoginSc.Teacher = (int)scMCnt.Score;
  838. else if (scope.Equals("student"))
  839. dLoginSc.Student = (int)scMCnt.Score;
  840. else
  841. dLoginSc.TmdUser = (int)scMCnt.Score;
  842. DayLoginSchools.Add(dLoginSc);
  843. }
  844. }
  845. else
  846. {
  847. //学校天峰值
  848. DayLoginSchool dayLoginSc = new() { PartitionKey = $"DayLogin-{school}", RowKey = dateDay, Day = currentDay, School = school };
  849. if (scope.Equals("teacher"))
  850. {
  851. dayLoginSc.Teacher = 1;
  852. dayLoginSc.Student = 0;
  853. dayLoginSc.TmdUser = 0;
  854. }
  855. else if (scope.Equals("student"))
  856. {
  857. dayLoginSc.Teacher = 0;
  858. dayLoginSc.Student = 1;
  859. dayLoginSc.TmdUser = 0;
  860. }
  861. else
  862. {
  863. dayLoginSc.Teacher = 0;
  864. dayLoginSc.Student = 0;
  865. dayLoginSc.TmdUser = 1;
  866. }
  867. DayLoginSchools.Add(dayLoginSc);
  868. }
  869. }
  870. }
  871. await table.SaveOrUpdateAll(DayLoginSchools);//保存学校当月在线数据
  872. }
  873. string tbScHourSql = $"PartitionKey eq 'HourLogin-{school}' and RowKey le '{delTbHour}'";
  874. List<HourLogin> scHourLog = await table.QueryWhereString<HourLogin>(tbScHourSql);
  875. if (scHourLog.Count > 0)
  876. try
  877. {
  878. //await table.DeleteStringWhere<HourLogin>(tbScHourSql); //删除学校168小时前的数据
  879. await table.DeleteAll(scHourLog);
  880. }
  881. catch { }
  882. string tbScDaySql = $"PartitionKey eq 'DayLogin-{school}' and RowKey le '{delTbDay}'";
  883. List<DayLogin> scDayLog = await table.QueryWhereString<DayLogin>(tbScDaySql);
  884. if (scDayLog.Count > 0)
  885. try
  886. {
  887. //await table.DeleteStringWhere<DayLogin>(tbScDaySql); //删除学校180天前的数据
  888. await table.DeleteAll(scDayLog);
  889. }
  890. catch { }
  891. }
  892. await response.WriteAsJsonAsync(new { data = json });
  893. return response;
  894. }
  895. catch (Exception ex)
  896. {
  897. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-online-record 人数记录异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
  898. await response.WriteAsJsonAsync(new { data = json });
  899. return response;
  900. }
  901. }
  902. /// <summary>
  903. /// 艺术评测报告生成
  904. /// </summary>
  905. /// <param name="msg"></param>
  906. /// <returns></returns>
  907. [Function("gen-art-pdf")]
  908. public async Task<HttpResponseData> GenArtPDF([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequestData req) {
  909. var response = req.CreateResponse(HttpStatusCode.OK);
  910. string data = await new StreamReader(req.Body).ReadToEndAsync();
  911. var json = JsonDocument.Parse(data).RootElement;
  912. json.TryGetProperty("studentPdfs", out JsonElement _studentPdfs);
  913. json.TryGetProperty("schoolCode", out JsonElement _schoolCode);
  914. List<ArtStudentPdf> studentPdfs = _studentPdfs.Deserialize<List<ArtStudentPdf>>();
  915. List<Task<string>> uploads = new List<Task<string>>();
  916. studentPdfs.ForEach(x => {
  917. x.blob = $"art/{x.artId}/report/{x.studentId}.json";
  918. uploads.Add(_azureStorage.GetBlobContainerClient($"{_schoolCode}").UploadFileByContainer(x.ToJsonString(), "art", $"{x.artId}/report/{x.studentId}.json", true));
  919. });
  920. var uploadJsonUrls= await Task.WhenAll(uploads);
  921. var list =uploadJsonUrls.ToList();
  922. List<string> urls = new List<string>();
  923. (string uri, string sas) = _azureStorage.GetBlobContainerSAS($"{_schoolCode}",Azure.Storage.Sas.BlobContainerSasPermissions.Read);
  924. studentPdfs.ForEach(x => {
  925. string atrUrl = "https://teammodelos.blob.core.chinacloudapi.cn/0-public/art-report-template/report.html";
  926. var s = _azureStorage.GetBlobSAS($"{_schoolCode}", x.blob, BlobSasPermissions.Read);
  927. s = $"{HttpUtility.UrlEncode($"{s}", Encoding.UTF8)}";
  928. string url = $"{atrUrl}?url={s}&pdfpath={x.artId}/report/{x.studentId}";
  929. urls.Add(url);
  930. //var a = list.Find(l => l.Contains(x.studentId));
  931. //if (a != null) {
  932. // a = $"{HttpUtility.UrlEncode($"{a}?{sas}", Encoding.UTF8)}";
  933. // string url = $"{atrUrl}?url={a}&pdfpath={x.artId}/report/{x.studentId}";
  934. // urls.Add(url);
  935. //}
  936. });
  937. string env = "release";
  938. if (Environment.GetEnvironmentVariable("Option:Location").Contains("Test",StringComparison.CurrentCultureIgnoreCase)||
  939. Environment.GetEnvironmentVariable("Option:Location").Contains("Dep", StringComparison.CurrentCultureIgnoreCase)) {
  940. env = "develop";
  941. }
  942. var screenshot = new ScreenshotDto
  943. {
  944. width = 1080,
  945. height = 1920,
  946. urls = urls,
  947. fileNameKey = "pdfpath",
  948. cnt = $"{_schoolCode}",
  949. root = "art",
  950. pagesize = 5,
  951. env = env
  952. };
  953. var st= screenshot.ToJsonString();
  954. var httpResponse= await _httpClient.PostAsJsonAsync("http://cdhabook.teammodel.cn:8805/screen/screenshot-pdf",
  955. screenshot
  956. );
  957. List<string> resUrls = new List<string>();
  958. if (httpResponse.StatusCode == HttpStatusCode.OK) {
  959. JsonElement json_res = await httpResponse.Content.ReadFromJsonAsync<JsonElement>();
  960. resUrls= json_res.GetProperty("urls").Deserialize<List<string>>();
  961. }
  962. await response.WriteAsJsonAsync(new { data =new { count= studentPdfs.Count , resUrls } });
  963. return response;
  964. }
  965. public class ScreenshotDto
  966. {
  967. public int width { get; set; } = 1920;
  968. public int height { get; set; } = 1080;
  969. public string? url { get; set; }
  970. /// <summary>
  971. /// 批量地址
  972. /// </summary>
  973. public List<string> urls { get; set; } = new List<string>();
  974. /// <summary>
  975. /// 提取参数的唯一id作为文件名
  976. /// </summary>
  977. public string? fileNameKey { get; set; }
  978. /// <summary>
  979. /// 存在哪个容器里
  980. /// </summary>
  981. public string? cnt { get; set; }
  982. public int delay { get; set; }
  983. public int pagesize { get; set; } = 5;
  984. public string? root { get; set; }
  985. public string? env { get; set; } = "release";
  986. }
  987. }
  988. }