ItemController.cs 71 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326
  1. using Microsoft.AspNetCore.Mvc;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Threading.Tasks;
  6. using TEAMModelOS.Models;
  7. using TEAMModelOS.SDK.DI;
  8. using System.Text.Json;
  9. using TEAMModelOS.SDK.Models;
  10. using Microsoft.AspNetCore.Http;
  11. using TEAMModelOS.SDK.Extension;
  12. using Azure.Cosmos;
  13. using System.Text;
  14. using TEAMModelOS.SDK.DI.AzureCosmos.Inner;
  15. using Microsoft.Extensions.Options;
  16. using Azure.Messaging.ServiceBus;
  17. using Microsoft.Extensions.Configuration;
  18. using HTEXLib.COMM.Helpers;
  19. using StackExchange.Redis;
  20. using Microsoft.AspNetCore.Authorization;
  21. using TEAMModelOS.SDK.Services;
  22. using System.Text.RegularExpressions;
  23. namespace TEAMModelOS.Controllers
  24. {
  25. [ProducesResponseType(StatusCodes.Status200OK)]
  26. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  27. [Route("item")]
  28. [ApiController]
  29. public class ItemController : ControllerBase
  30. {
  31. private readonly SnowflakeId _snowflakeId;
  32. private readonly AzureCosmosFactory _azureCosmos;
  33. private readonly DingDing _dingDing;
  34. private readonly Option _option;
  35. private readonly AzureStorageFactory _azureStorage;
  36. private readonly AzureServiceBusFactory _serviceBus;
  37. private readonly AzureRedisFactory _azureRedis;
  38. public IConfiguration _configuration { get; set; }
  39. public ItemController(AzureCosmosFactory azureCosmos, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option, AzureStorageFactory azureStorage,
  40. AzureRedisFactory azureRedis,AzureServiceBusFactory serviceBus, IConfiguration configuration)
  41. {
  42. _azureCosmos = azureCosmos;
  43. _snowflakeId = snowflakeId;
  44. _dingDing = dingDing;
  45. _option = option?.Value;
  46. _azureStorage = azureStorage;
  47. _serviceBus = serviceBus;
  48. _configuration = configuration;
  49. _azureRedis = azureRedis;
  50. }
  51. /// <summary>
  52. /// 参数{"periodId":"学段id","schoolCode":"学校编码"} 其中periodId 不填则是全部学段的。
  53. /// </summary>
  54. /// <param name="request"></param>
  55. /// <returns></returns>
  56. [ProducesDefaultResponseType]
  57. [HttpPost("cond-count")]
  58. [Authorize(Roles = "IES")]
  59. public async Task<IActionResult> CondCount(JsonElement request) {
  60. try
  61. {
  62. var client = _azureCosmos.GetCosmosClient();
  63. request.TryGetProperty("periodId", out JsonElement periodId);
  64. request.TryGetProperty("schoolCode", out JsonElement schoolCode);
  65. request.TryGetProperty("tmdid", out JsonElement tmdid);
  66. if (!string.IsNullOrEmpty($"{periodId}") && !string.IsNullOrEmpty($"{schoolCode}"))
  67. {
  68. var value = await _azureRedis.GetRedisClient(8).HashGetAsync($"ItemCond:{schoolCode}", $"{periodId}");
  69. ItemCond itemCond = null;
  70. if (value != default && !value.IsNullOrEmpty)
  71. {
  72. itemCond = value.ToString().ToObject<ItemCond>();
  73. }
  74. else {
  75. List<ItemInfo> items = new List<ItemInfo>();
  76. var queryslt = $"SELECT c.gradeIds,c.subjectId,c.periodId,c.type,c.level,c.field ,c.scope FROM c where c.periodId='{periodId}' and c.pid= null ";
  77. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ItemInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{schoolCode}") }))
  78. {
  79. items.Add(item);
  80. }
  81. itemCond = new ItemCond()
  82. {
  83. id = $"{periodId}",
  84. code = $"ItemCond-{schoolCode}",
  85. pk = "ItemCond",
  86. ttl = -1,
  87. count = items.Count,
  88. grades = new List<GradeCount>(),
  89. subjects = new List<SubjectItemCount>()
  90. };
  91. items.ForEach(z =>
  92. {
  93. if (!string.IsNullOrEmpty(z.type))
  94. {
  95. ItemService.CountItemCond(z, null, itemCond);
  96. }
  97. });
  98. await _azureRedis.GetRedisClient(8).HashSetAsync($"ItemCond:{schoolCode}", $"{periodId}", itemCond.ToJsonString());
  99. }
  100. return Ok(new { itemConds = new List<ItemCond>() { itemCond } });
  101. }
  102. else if (!string.IsNullOrEmpty($"{schoolCode}"))
  103. {
  104. List<ItemCond> itemConds = new List<ItemCond>();
  105. School school =await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{schoolCode}", new PartitionKey("Base"));
  106. List<string> nocachePeriods = new List<string>();
  107. foreach (var period in school.period) {
  108. var value = await _azureRedis.GetRedisClient(8).HashGetAsync($"ItemCond:{schoolCode}", $"{period.id}");
  109. ItemCond itemCond = null;
  110. if (value != default && !value.IsNullOrEmpty)
  111. {
  112. itemCond = value.ToString().ToObject<ItemCond>();
  113. itemConds.Add(itemCond);
  114. }
  115. else {
  116. nocachePeriods.Add(period.id);
  117. }
  118. }
  119. string nocachePeriodsql = "";
  120. if (nocachePeriods.IsNotEmpty())
  121. {
  122. string sql = string.Join(',', nocachePeriods.Select(x => $"'{x}'"));
  123. nocachePeriodsql = $" and c.periodId in ({sql})";
  124. List<ItemInfo> items = new List<ItemInfo>();
  125. var queryslt = $"SELECT c.gradeIds,c.subjectId,c.periodId,c.type,c.level,c.field,c.scope FROM c where c.pid= null {nocachePeriodsql}";
  126. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ItemInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{schoolCode}") }))
  127. {
  128. items.Add(item);
  129. }
  130. var list = items.GroupBy(x => x.periodId).Select(y => new { key = y.Key, list = y.ToList() }).ToList();
  131. foreach (var z in list)
  132. {
  133. ItemCond cond = new ItemCond() { id = z.key, code = $"ItemCond-{school.id}", pk = "ItemCond", ttl = -1, count = z.list.Count, grades = new List<GradeCount>(), subjects = new List<SubjectItemCount>() };
  134. z.list.ForEach(y =>
  135. {
  136. if (!string.IsNullOrEmpty(y.type))
  137. {
  138. ItemService.CountItemCond(y, null, cond);
  139. }
  140. });
  141. await _azureRedis.GetRedisClient(8).HashSetAsync($"ItemCond:{schoolCode}", $"{z.key}", cond.ToJsonString());
  142. itemConds.Add(cond);
  143. }
  144. if (school != null)
  145. {
  146. foreach (var period in school.period)
  147. {
  148. var cond = itemConds.Find(x => x.id.Equals(period.id));
  149. if (cond == null)
  150. {
  151. ItemCond condn = new ItemCond() { id = period.id, code = $"ItemCond-{school.id}", pk = "ItemCond", ttl = -1, count = 0, grades = new List<GradeCount>(), subjects = new List<SubjectItemCount>() };
  152. itemConds.Add(condn);
  153. }
  154. }
  155. }
  156. }
  157. return Ok(new { itemConds = itemConds });
  158. }
  159. else if (!string.IsNullOrEmpty($"{tmdid}"))
  160. {
  161. var value = await _azureRedis.GetRedisClient(8).HashGetAsync($"ItemCond:ItemCond", $"{tmdid}");
  162. ItemCond itemCond = null;
  163. if (value != default && !value.IsNullOrEmpty)
  164. {
  165. itemCond = value.ToString().ToObject<ItemCond>();
  166. }
  167. else {
  168. List<ItemInfo> items = new List<ItemInfo>();
  169. var queryslt = $"SELECT c.gradeIds,c.subjectId,c.periodId,c.type,c.level,c.field ,c.scope FROM c where c.pid= null ";
  170. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<ItemInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{tmdid}") }))
  171. {
  172. items.Add(item);
  173. }
  174. itemCond = new ItemCond() { id = $"{tmdid}", code = $"ItemCond", pk = "ItemCond", ttl = -1, count = items.Count };
  175. items.ForEach(z =>
  176. {
  177. if (!string.IsNullOrEmpty(z.type)) {
  178. ItemService.CountItemCond(z, null, itemCond);
  179. }
  180. });
  181. await _azureRedis.GetRedisClient(8).HashSetAsync($"ItemCond:ItemCond", $"{tmdid}", itemCond.ToJsonString());
  182. }
  183. return Ok(new { itemConds = new List<ItemCond>() { itemCond } });
  184. }
  185. else
  186. {
  187. return Ok(new { itemConds = new List<ItemCond>() { } });
  188. }
  189. }
  190. catch (CosmosException ex)
  191. {
  192. return Ok(new { itemConds = new List<ItemCond>() { } });
  193. }
  194. catch (Exception ex)
  195. {
  196. return Ok(new { itemConds = new List<ItemCond>() { } });
  197. }
  198. }
  199. [ProducesDefaultResponseType]
  200. [HttpPost("upsert-all")]
  201. [Authorize(Roles = "IES")]
  202. public async Task<IActionResult> UpsertAll(JsonElement request)
  203. {
  204. var ItemCondQueue = _configuration.GetValue<string>("Azure:ServiceBus:ItemCondQueue");
  205. var client = _azureCosmos.GetCosmosClient();
  206. List<ItemInfo> itemInfos = null;
  207. if (!request.TryGetProperty("itemInfos", out JsonElement items)) return BadRequest();
  208. if (!request.TryGetProperty("option", out JsonElement option)) return BadRequest();
  209. try
  210. {
  211. Dictionary<string, ItemCondDto> dict = new Dictionary<string, ItemCondDto>();
  212. itemInfos = items.ToObject<List<ItemInfo>>();
  213. foreach (var itemInfo in itemInfos) {
  214. itemInfo.ttl = -1;
  215. itemInfo.size = await _azureStorage.GetBlobContainerClient(itemInfo.code).GetBlobsSize($"item/{itemInfo.id}");
  216. var messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "update", root = $"item/{itemInfo.id}", name = $"{itemInfo.code}" }.ToJsonString());
  217. messageBlob.ApplicationProperties.Add("name", "BlobRoot");
  218. var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
  219. await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageBlob);
  220. if (option.ToString().Equals("insert"))
  221. {
  222. itemInfo.createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  223. if (!itemInfo.code.Contains("Item"))
  224. {
  225. itemInfo.code = "Item-" + itemInfo.code;
  226. }
  227. var response = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  228. if (response.Status == 200)
  229. {
  230. return Ok();
  231. }
  232. else
  233. {
  234. if (itemInfo.scope.Equals("private"))
  235. {
  236. if (string.IsNullOrEmpty(itemInfo.pid))
  237. {
  238. if (!dict.ContainsKey($"{itemInfo.code.Replace("Item-", "")}"))
  239. {
  240. dict.Add($"{itemInfo.code.Replace("Item-", "")}", new ItemCondDto { key = $"{itemInfo.code.Replace("Item-", "")}",filed= $"{itemInfo.code.Replace("Item-", "")}", scope= "private" });
  241. }
  242. }
  243. await client.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync(itemInfo, new PartitionKey($"{itemInfo.code}"));
  244. }
  245. else
  246. {
  247. if (string.IsNullOrEmpty(itemInfo.pid))
  248. {
  249. if (!dict.ContainsKey($"{itemInfo.code.Replace("Item-", "")}-{itemInfo.periodId}"))
  250. {
  251. dict.Add($"{itemInfo.code.Replace("Item-", "")}-{itemInfo.periodId}", new ItemCondDto { key = $"{itemInfo.code.Replace("Item-", "")}",filed=$"{itemInfo.periodId}", scope = "school" });
  252. }
  253. }
  254. await client.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync(itemInfo, new PartitionKey($"{itemInfo.code}"));
  255. }
  256. }
  257. }
  258. else
  259. {
  260. itemInfo.createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  261. if (itemInfo.scope.Equals("private"))
  262. {
  263. if (!itemInfo.code.Contains("Item"))
  264. {
  265. itemInfo.code = "Item-" + itemInfo.code;
  266. }
  267. if (string.IsNullOrEmpty(itemInfo.pid))
  268. {
  269. if (!dict.ContainsKey($"{itemInfo.code.Replace("Item-", "")}"))
  270. {
  271. dict.Add($"{itemInfo.code.Replace("Item-", "")}", new ItemCondDto { key = $"{itemInfo.code.Replace("Item-", "")}", filed = $"{itemInfo.code.Replace("Item-", "")}", scope = "private" });
  272. }
  273. ItemInfo olditemInfo = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<ItemInfo>(itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  274. if (!dict.ContainsKey($"{olditemInfo.code.Replace("Item-", "")}"))
  275. {
  276. dict.Add($"{olditemInfo.code.Replace("Item-", "")}", new ItemCondDto { key = $"{olditemInfo.code.Replace("Item-", "")}", filed = $"{olditemInfo.code.Replace("Item-", "")}", scope = "private" });
  277. }
  278. }
  279. await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync(itemInfo, itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  280. }
  281. else
  282. {
  283. if (!itemInfo.code.Contains("Item"))
  284. {
  285. itemInfo.code = "Item-" + itemInfo.code;
  286. }
  287. if (string.IsNullOrEmpty(itemInfo.pid))
  288. {
  289. if (!dict.ContainsKey($"{itemInfo.code.Replace("Item-", "")}-{itemInfo.periodId}"))
  290. {
  291. dict.Add($"{itemInfo.code.Replace("Item-", "")}-{itemInfo.periodId}", new ItemCondDto { key = $"{itemInfo.code.Replace("Item-", "")}", filed = $"{itemInfo.periodId}", scope = "school" });
  292. }
  293. ItemInfo olditemInfo = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<ItemInfo>(itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  294. if (!dict.ContainsKey($"{olditemInfo.code.Replace("Item-", "")}-{olditemInfo.periodId}"))
  295. {
  296. dict.Add($"{olditemInfo.code.Replace("Item-", "")}-{olditemInfo.periodId}", new ItemCondDto { key = $"{olditemInfo.code.Replace("Item-", "")}", filed = $"{olditemInfo.periodId}", scope = "school" });
  297. }
  298. }
  299. await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(itemInfo, itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  300. }
  301. }
  302. }
  303. var itemCondDtos= dict.Select(x => x.Value).ToList();
  304. var str = itemCondDtos.ToJsonString();
  305. var messageBlobItemCond = new ServiceBusMessage(str);
  306. await _serviceBus.GetServiceBusClient().SendMessageAsync(ItemCondQueue, messageBlobItemCond);
  307. return Ok(new { itemInfos });
  308. }
  309. catch (Exception ex)
  310. {
  311. await _dingDing.SendBotMsg($"OS,{_option.Location},item/upsert()\n{ex.Message}{ex.StackTrace}\n{request}", GroupNames.醍摩豆服務運維群組);
  312. return BadRequest();
  313. }
  314. }
  315. [ProducesDefaultResponseType]
  316. [HttpPost("upsert")]
  317. [Authorize(Roles = "IES")]
  318. public async Task<IActionResult> Upsert(JsonElement request)
  319. {
  320. var client = _azureCosmos.GetCosmosClient();
  321. if (!request.TryGetProperty("itemInfo", out JsonElement item)) return BadRequest();
  322. if (!request.TryGetProperty("option", out JsonElement option)) return BadRequest();
  323. try
  324. {
  325. Dictionary<string, ItemCondDto> dict = new Dictionary<string, ItemCondDto>();
  326. var ItemCondQueue = _configuration.GetValue<string>("Azure:ServiceBus:ItemCondQueue");
  327. ItemInfo itemInfo;
  328. itemInfo = item.ToObject<ItemInfo>();
  329. itemInfo.size = await _azureStorage.GetBlobContainerClient(itemInfo.code).GetBlobsSize($"item/{itemInfo.id}");
  330. var messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "update", root = $"item/{itemInfo.id}", name = $"{itemInfo.code}" }.ToJsonString());
  331. messageBlob.ApplicationProperties.Add("name", "BlobRoot");
  332. var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
  333. await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageBlob);
  334. if (option.ToString().Equals("insert"))
  335. {
  336. itemInfo.createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  337. if (!itemInfo.code.Contains("Item"))
  338. {
  339. itemInfo.code = "Item-" + itemInfo.code;
  340. }
  341. var response = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  342. if (response.Status == 200)
  343. {
  344. return Ok(new { code=409,msg="题目已经存在"});
  345. }
  346. else
  347. {
  348. if (itemInfo.scope.Equals("private"))
  349. {
  350. if (string.IsNullOrEmpty(itemInfo.pid))
  351. {
  352. if (!dict.ContainsKey($"{itemInfo.code.Replace("Item-", "")}"))
  353. {
  354. dict.Add($"{itemInfo.code.Replace("Item-", "")}", new ItemCondDto { key = $"{itemInfo.code.Replace("Item-", "")}", filed = $"{itemInfo.code.Replace("Item-", "")}", scope = "private" });
  355. }
  356. }
  357. itemInfo = await client.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync(itemInfo, new PartitionKey($"{itemInfo.code}"));
  358. }
  359. else
  360. {
  361. if (string.IsNullOrEmpty(itemInfo.pid))
  362. {
  363. if (!dict.ContainsKey($"{itemInfo.code.Replace("Item-", "")}-{itemInfo.periodId}"))
  364. {
  365. dict.Add($"{itemInfo.code.Replace("Item-", "")}-{itemInfo.periodId}", new ItemCondDto { key = $"{itemInfo.code.Replace("Item-", "")}", filed = $"{itemInfo.periodId}", scope = "school" });
  366. }
  367. }
  368. itemInfo = await client.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync(itemInfo, new PartitionKey($"{itemInfo.code}"));
  369. }
  370. }
  371. }
  372. else
  373. {
  374. itemInfo.createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  375. if (itemInfo.scope.Equals("private"))
  376. {
  377. if (!itemInfo.code.Contains("Item"))
  378. {
  379. itemInfo.code = "Item-" + itemInfo.code;
  380. }
  381. if (string.IsNullOrEmpty(itemInfo.pid))
  382. {
  383. if (!dict.ContainsKey($"{itemInfo.code.Replace("Item-", "")}"))
  384. {
  385. dict.Add($"{itemInfo.code.Replace("Item-", "")}", new ItemCondDto { key = $"{itemInfo.code.Replace("Item-", "")}", filed = $"{itemInfo.code.Replace("Item-", "")}", scope = "private" });
  386. }
  387. ItemInfo olditemInfo = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<ItemInfo>(itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  388. if (!dict.ContainsKey($"{olditemInfo.code.Replace("Item-", "")}"))
  389. {
  390. dict.Add($"{olditemInfo.code.Replace("Item-", "")}", new ItemCondDto { key = $"{olditemInfo.code.Replace("Item-", "")}", filed = $"{olditemInfo.code.Replace("Item-", "")}", scope = "private" });
  391. }
  392. }
  393. itemInfo = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync(itemInfo, itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  394. }
  395. else
  396. {
  397. if (!itemInfo.code.Contains("Item"))
  398. {
  399. itemInfo.code = "Item-" + itemInfo.code;
  400. }
  401. if (string.IsNullOrEmpty(itemInfo.pid))
  402. {
  403. if (!dict.ContainsKey($"{itemInfo.code.Replace("Item-", "")}-{itemInfo.periodId}"))
  404. {
  405. dict.Add($"{itemInfo.code.Replace("Item-", "")}-{itemInfo.periodId}", new ItemCondDto { key = $"{itemInfo.code.Replace("Item-", "")}", filed = $"{itemInfo.periodId}", scope = "school" });
  406. }
  407. ItemInfo olditemInfo = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<ItemInfo>(itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  408. if (!dict.ContainsKey($"{olditemInfo.code.Replace("Item-", "")}-{olditemInfo.periodId}"))
  409. {
  410. dict.Add($"{olditemInfo.code.Replace("Item-", "")}-{olditemInfo.periodId}", new ItemCondDto { key = $"{olditemInfo.code.Replace("Item-", "")}", filed = $"{olditemInfo.periodId}", scope = "school" });
  411. }
  412. }
  413. itemInfo = await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(itemInfo, itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  414. }
  415. }
  416. var itemCondDtos = dict.Select(x => x.Value).ToList();
  417. var str = itemCondDtos.ToJsonString();
  418. var messageBlobItemCond = new ServiceBusMessage(str);
  419. await _serviceBus.GetServiceBusClient().SendMessageAsync(ItemCondQueue, messageBlobItemCond);
  420. return Ok(new { itemInfo });
  421. }
  422. catch (Exception ex)
  423. {
  424. await _dingDing.SendBotMsg($"OS,{_option.Location},item/upsert()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  425. return BadRequest();
  426. }
  427. }
  428. /// <summary>
  429. //获取题目摘要信息
  430. /// </summary>
  431. /// <param name="request"></param>
  432. /// <returns></returns>
  433. [ProducesDefaultResponseType]
  434. //[AuthToken(Roles = "teacher")]
  435. [HttpPost("find-summary")]
  436. [Authorize(Roles = "IES")]
  437. public async Task<IActionResult> FindSummary(JsonElement request)
  438. {
  439. try
  440. {
  441. var client = _azureCosmos.GetCosmosClient();
  442. StringBuilder sql = new StringBuilder();
  443. sql.Append("select c.id, c.question,c.useCount,c.level,c.field,c.knowledge,c.type,c.option,c.createTime from c ");
  444. if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
  445. /* if (!request.TryGetProperty("@CURRPAGE", out JsonElement page)) return BadRequest();
  446. if (!request.TryGetProperty("@PAGESIZE", out JsonElement size)) return BadRequest();*/
  447. if (!request.TryGetProperty("@DESC", out JsonElement desc)) return BadRequest();
  448. if (!request.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
  449. List<object> summary = new List<object>();
  450. Dictionary<string, object> dict = new Dictionary<string, object>();
  451. /* dict.Add("@CURRPAGE", page.GetInt32());
  452. dict.Add("@PAGESIZE", size.GetInt32());*/
  453. dict.Add("@DESC", desc.ToString());
  454. if (request.TryGetProperty("periodId", out JsonElement periodId))
  455. {
  456. dict.Add("periodId", periodId);
  457. }
  458. if (request.TryGetProperty("subjectId", out JsonElement subjectId))
  459. {
  460. dict.Add("subjectId", subjectId);
  461. }
  462. if (request.TryGetProperty("level", out JsonElement level))
  463. {
  464. dict.Add("level", level);
  465. }
  466. if (request.TryGetProperty("type", out JsonElement type))
  467. {
  468. dict.Add("type", type);
  469. }
  470. if (request.TryGetProperty("field", out JsonElement field))
  471. {
  472. dict.Add("field", field);
  473. }
  474. AzureCosmosQuery cosmosDbQuery = SQLHelper.GetSQL(dict, sql);
  475. //List<object> items = new List<object>();
  476. if (scope.ToString().Equals("private"))
  477. {
  478. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{code}") }))
  479. {
  480. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  481. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  482. {
  483. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  484. {
  485. summary.Add(obj.ToObject<object>());
  486. }
  487. }
  488. }
  489. }
  490. if (scope.ToString().Equals("school"))
  491. {
  492. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{code}") }))
  493. {
  494. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  495. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  496. {
  497. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  498. {
  499. summary.Add(obj.ToObject<object>());
  500. }
  501. }
  502. }
  503. }
  504. return Ok(new { summary });
  505. }
  506. catch (Exception ex)
  507. {
  508. await _dingDing.SendBotMsg($"OS,{_option.Location},item/FindSummary()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  509. return BadRequest();
  510. }
  511. }
  512. /// <summary>
  513. /// 删除
  514. /// </summary>
  515. /// <param name="request"></param>
  516. /// <returns></returns>
  517. [ProducesDefaultResponseType]
  518. //[AuthToken(Roles = "teacher")]
  519. [HttpPost("delete")]
  520. [Authorize(Roles = "IES")]
  521. public async Task<IActionResult> Delete(JsonElement request)
  522. {
  523. try
  524. {
  525. Dictionary<string, ItemCondDto> dict = new Dictionary<string, ItemCondDto>();
  526. var ItemCondQueue = _configuration.GetValue<string>("Azure:ServiceBus:ItemCondQueue");
  527. if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
  528. if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
  529. if (!request.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
  530. var client = _azureCosmos.GetCosmosClient();
  531. //删除blob 相关资料
  532. await _azureStorage.GetBlobServiceClient().DeleteBlobs(_dingDing, code.ToString().Replace("Item-",""),new List<string> { $"item/{id}" });
  533. //通知删除信息
  534. var messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "delete", root = $"item/{id}", name = code.ToString().Replace("Item-", "") }.ToJsonString());
  535. messageBlob.ApplicationProperties.Add("name", "BlobRoot");
  536. var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
  537. await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageBlob);
  538. if (scope.ToString().Equals("school"))
  539. {
  540. ItemInfo olditemInfo = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<ItemInfo>($"{id}", new PartitionKey($"{code}"));
  541. if (!dict.ContainsKey($"{olditemInfo.code.Replace("Item-", "")}-{olditemInfo.periodId}"))
  542. {
  543. dict.Add($"{olditemInfo.code.Replace("Item-", "")}-{olditemInfo.periodId}", new ItemCondDto { key = $"{olditemInfo.code.Replace("Item-", "")}", filed = $"{olditemInfo.periodId}", scope = "school" });
  544. }
  545. var itemCondDtos = dict.Select(x => x.Value).ToList();
  546. var str = itemCondDtos.ToJsonString();
  547. var messageBlobItemCond = new ServiceBusMessage(str);
  548. await _serviceBus.GetServiceBusClient().SendMessageAsync(ItemCondQueue, messageBlobItemCond);
  549. var response = await client.GetContainer(Constant.TEAMModelOS, "School").DeleteItemStreamAsync(id.ToString(), new PartitionKey($"{code}"));
  550. return Ok(new { code = response.Status });
  551. }
  552. else
  553. {
  554. ItemInfo olditemInfo = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<ItemInfo>($"{id}", new PartitionKey($"{code}"));
  555. if (!dict.ContainsKey($"{olditemInfo.code.Replace("Item-", "")}"))
  556. {
  557. dict.Add($"{olditemInfo.code.Replace("Item-", "")}", new ItemCondDto { key = $"{olditemInfo.code.Replace("Item-", "")}", filed = $"{olditemInfo.code.Replace("Item-", "")}", scope = "private" });
  558. }
  559. var itemCondDtos = dict.Select(x => x.Value).ToList();
  560. var str = itemCondDtos.ToJsonString();
  561. var messageBlobItemCond = new ServiceBusMessage(str);
  562. await _serviceBus.GetServiceBusClient().SendMessageAsync(ItemCondQueue, messageBlobItemCond);
  563. var response = await client.GetContainer(Constant.TEAMModelOS, "Teacher").DeleteItemStreamAsync(id.ToString(), new PartitionKey($"{code}"));
  564. return Ok(new { code = response.Status });
  565. }
  566. }
  567. catch (Exception e)
  568. {
  569. await _dingDing.SendBotMsg($"OS,{_option.Location},item/delete()\n{e.Message},{e.StackTrace}", GroupNames.醍摩豆服務運維群組);
  570. return BadRequest();
  571. }
  572. /* ResponseBuilder builder = ResponseBuilder.custom();
  573. IdPk idPk = await _azureCosmos.DeleteAsync<ItemInfo>( request );
  574. return Ok(idPk);*/
  575. }
  576. /// <summary>
  577. /// 关键字搜索
  578. /// </summary>
  579. /// <param name="request"></param>
  580. /// <returns></returns>
  581. [ProducesDefaultResponseType]
  582. //[AuthToken(Roles = "teacher")]
  583. [HttpPost("research")]
  584. [Authorize(Roles = "IES")]
  585. public async Task<IActionResult> Research(JsonElement request) {
  586. var client = _azureCosmos.GetCosmosClient();
  587. StringBuilder sql = new StringBuilder();
  588. sql.Append("select distinct c.id,c.code,c.repairResource, c.periodId,c.question,c.useCount,c.level,c.field,c.knowledge,c.type,c.option,c.createTime," +
  589. "c.answer,c.explain,c.children,c.score,c.gradeIds,c.subjectId,c.blob,c.scope from c where 1=1 and c.pid=null ");
  590. if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
  591. if (!request.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
  592. if (!request.TryGetProperty("researchKey", out JsonElement researchKey)) return BadRequest();
  593. request.TryGetProperty("orOpt", out JsonElement _orOpt);
  594. string _researchKey = Regex.Replace($"{researchKey}", "[ \\[ \\] \\^ \\-|()【】/' {}_*×――(^)$%~!@#$…&%¥—+=<>《》!!???::•`·、。,;,.;\"‘’“”-]", " ");
  595. var keys = Regex.Split(_researchKey, "\\s+", RegexOptions.IgnoreCase).Where(y=>!string.IsNullOrWhiteSpace(y));
  596. if (keys.Count() ==0) {
  597. return BadRequest();
  598. }
  599. else if (keys.Count() == 1)
  600. {
  601. sql.Append($" and contains(c.question,'{keys.First()}')");
  602. }
  603. else {
  604. string join = " and ";
  605. if (_orOpt.ValueKind.Equals(JsonValueKind.True)) {
  606. join = " or ";
  607. }
  608. sql.Append($" and ( {string.Join(join, keys.Select(x => $" contains(c.question,'{x}') "))})");
  609. }
  610. request.TryGetProperty("type", out JsonElement type);
  611. if (!string.IsNullOrWhiteSpace($"{type}")) {
  612. sql.Append($" and c.type='{type}' ");
  613. }
  614. request.TryGetProperty("level", out JsonElement level);
  615. if (!string.IsNullOrWhiteSpace($"{level}"))
  616. {
  617. sql.Append($" and c.level={level} ");
  618. }
  619. request.TryGetProperty("field", out JsonElement field);
  620. if (!string.IsNullOrWhiteSpace($"{field}"))
  621. {
  622. sql.Append($" and c.level={field} ");
  623. }
  624. request.TryGetProperty("continuationToken", out JsonElement _continuationToken);
  625. string continuationToken = null;
  626. if (!string.IsNullOrWhiteSpace($"{_continuationToken}"))
  627. {
  628. continuationToken = $"{_continuationToken}";
  629. }
  630. int pageCount = 10;
  631. if (request.TryGetProperty("pageCount", out JsonElement _pageCount))
  632. {
  633. int.TryParse($"{_pageCount}", out int pcount);
  634. if (pcount > 0)
  635. {
  636. pageCount = pcount;
  637. }
  638. }
  639. List<object> items = new List<object>();
  640. if (scope.ToString().Equals("private"))
  641. {
  642. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIterator(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{code}") }))
  643. {
  644. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  645. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  646. {
  647. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  648. {
  649. items.Add(obj.ToObject<object>());
  650. }
  651. //continuationToken=item.GetContinuationToken();
  652. //break;
  653. }
  654. }
  655. }
  656. if (scope.ToString().Equals("school"))
  657. {
  658. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{code}") }))
  659. {
  660. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  661. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  662. {
  663. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  664. {
  665. items.Add(obj.ToObject<object>());
  666. }
  667. //continuationToken = item.GetContinuationToken();
  668. //break;
  669. }
  670. }
  671. }
  672. //需要处理 图片中的 base64
  673. return Ok(new { items , continuationToken });
  674. }
  675. /// <summary>
  676. /// 根据条件随机挑选一个题目
  677. /// </summary>
  678. /// <param name="request"></param>
  679. /// <returns></returns>
  680. [ProducesDefaultResponseType]
  681. //[AuthToken(Roles = "teacher")]
  682. [HttpPost("find-random-one")]
  683. [Authorize(Roles = "IES")]
  684. public async Task<IActionResult> FindRandomOne(JsonElement request)
  685. {
  686. try
  687. {
  688. ItemInfo itemInfo = null;
  689. var client = _azureCosmos.GetCosmosClient();
  690. string sql = $"select value(c.id) from c joingradeIds joinknowledge where 1=1";
  691. if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
  692. if (!request.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
  693. Dictionary<string, object> dict = new Dictionary<string, object>();
  694. if (request.TryGetProperty("periodId", out JsonElement periodId))
  695. {
  696. sql=$"{sql} and c.periodId='{periodId}'" ;
  697. }
  698. if (request.TryGetProperty("subjectId", out JsonElement subjectId))
  699. {
  700. sql = $"{sql} and c.subjectId='{subjectId}'";
  701. }
  702. if (request.TryGetProperty("level", out JsonElement level))
  703. {
  704. sql = $"{sql} and c.level={level}";
  705. }
  706. if (request.TryGetProperty("type", out JsonElement type))
  707. {
  708. sql = $"{sql} and c.type='{type}'";
  709. }
  710. if (request.TryGetProperty("field", out JsonElement field))
  711. {
  712. sql = $"{sql} and c.field={field}";
  713. }
  714. if (request.TryGetProperty("gradeIds", out JsonElement _gradeIds) && _gradeIds.ValueKind.Equals(JsonValueKind.Array))
  715. {
  716. List<string> gradeIds = _gradeIds.ToObject<List<string>>();
  717. if (gradeIds.IsNotEmpty()) {
  718. sql = $"{sql} and g in ({string.Join(",", gradeIds.Select(x => $"'{x}'"))})";
  719. sql= sql.Replace("joingradeIds", " join g in c.gradeIds");
  720. }
  721. }
  722. if (request.TryGetProperty("knowledge", out JsonElement _knowledge) && _knowledge.ValueKind.Equals(JsonValueKind.Array))
  723. {
  724. List<string> knowledge = _knowledge.ToObject<List<string>>();
  725. if (knowledge.IsNotEmpty())
  726. {
  727. sql = $"{sql} and k in ({string.Join(",", knowledge.Select(x => $"'{x}'"))})";
  728. sql= sql.Replace("joinknowledge", " join k in c.knowledge");
  729. }
  730. }
  731. if (request.TryGetProperty("pid", out JsonElement pd))
  732. {
  733. if (pd.ValueKind != JsonValueKind.Null)
  734. {
  735. sql = $"{sql} and c.pid='{pd}'";
  736. }
  737. else
  738. {
  739. sql = $"{sql} and c.pid= null ";
  740. }
  741. }
  742. List<string> notinIds = null;
  743. if (request.TryGetProperty("notinIds", out JsonElement _notinIds) && _notinIds.ValueKind.Equals(JsonValueKind.Array))
  744. {
  745. notinIds = _notinIds.ToObject<List<string>>();
  746. if (notinIds.IsNotEmpty())
  747. {
  748. sql = $"{sql} and c.id not in ({string.Join(",", notinIds.Select(x => $"'{x}'"))})";
  749. }
  750. }
  751. string sqlstr = sql.ToString().Replace("joingradeIds", " ").Replace("joinknowledge"," " );
  752. if (sqlstr.EndsWith("1=1") || !sqlstr.Contains("and"))
  753. {
  754. return Ok(new { itemInfo = itemInfo });
  755. }
  756. if (scope.ToString().Equals("private"))
  757. {
  758. List<string> items = new List<string>();
  759. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<string>(queryText: sqlstr, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{code}") }))
  760. {
  761. items.Add(item);
  762. }
  763. if (notinIds.IsNotEmpty()) {
  764. items = items.Except(notinIds).ToList();
  765. }
  766. string id= items.OrderBy(x => Guid.NewGuid().ToString()).Take(1).FirstOrDefault();
  767. if (!string.IsNullOrWhiteSpace(id)) {
  768. try {
  769. itemInfo = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<ItemInfo>(id, new PartitionKey($"Item-{code}"));
  770. } catch (Exception ex) {
  771. itemInfo = null;
  772. }
  773. }
  774. }
  775. if (scope.ToString().Equals("school"))
  776. {
  777. List<string> items = new List<string>();
  778. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<string>(queryText: sqlstr, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{code}") }))
  779. {
  780. items.Add(item);
  781. }
  782. if (notinIds.IsNotEmpty())
  783. {
  784. items = items.Except(notinIds).ToList();
  785. }
  786. string id = items.OrderBy(x => Guid.NewGuid().ToString()).Take(1).FirstOrDefault();
  787. if (!string.IsNullOrWhiteSpace(id))
  788. {
  789. try
  790. {
  791. itemInfo = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<ItemInfo>(id, new PartitionKey($"Item-{code}"));
  792. }
  793. catch (Exception ex)
  794. {
  795. itemInfo = null;
  796. }
  797. }
  798. }
  799. return Ok(new { itemInfo= itemInfo });
  800. }
  801. catch (Exception e)
  802. {
  803. await _dingDing.SendBotMsg($"OS,{_option.Location},item/Find()\n{e.Message}\n{e.StackTrace}", GroupNames.醍摩豆服務運維群組);
  804. return BadRequest();
  805. }
  806. }
  807. /// <summary>
  808. /// 手动挑题
  809. /// </summary>
  810. /// <param name="request"></param>
  811. /// <returns></returns>
  812. [ProducesDefaultResponseType]
  813. //[AuthToken(Roles = "teacher")]
  814. [HttpPost("find")]
  815. [Authorize(Roles = "IES")]
  816. public async Task<IActionResult> Find(JsonElement request)
  817. {
  818. try
  819. {
  820. var client = _azureCosmos.GetCosmosClient();
  821. StringBuilder sql = new StringBuilder();
  822. sql.Append("select c.id,c.code,c.repairResource, c.periodId,c.question,c.useCount,c.level,c.field,c.knowledge,c.type,c.option,c.createTime,c.answer,c.explain,c.children,c.score,c.gradeIds,c.subjectId,c.blob,c.scope from c ");
  823. if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
  824. /* if (!request.TryGetProperty("@CURRPAGE", out JsonElement page)) return BadRequest();
  825. if (!request.TryGetProperty("@PAGESIZE", out JsonElement size)) return BadRequest();*/
  826. if (!request.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
  827. Dictionary<string, object> dict = new Dictionary<string, object>();
  828. /*var emobj = request.EnumerateObject();
  829. while (emobj.MoveNext())
  830. {
  831. dict[emobj.Current.Name] = emobj.Current.Value;
  832. }
  833. //处理code
  834. if (dict.TryGetValue("code", out object _))
  835. {
  836. dict.Remove("code");
  837. }*/
  838. /* dict.Add("@CURRPAGE", page.GetInt32());
  839. dict.Add("@PAGESIZE", size.GetInt32());*/
  840. if (request.TryGetProperty("@DESC", out JsonElement desc)) {
  841. dict.Add("@DESC", desc.ToString());
  842. }
  843. if (request.TryGetProperty("@ASC", out JsonElement asc))
  844. {
  845. dict.Add("@ASC", asc.ToString());
  846. }
  847. if (request.TryGetProperty("periodId", out JsonElement periodId))
  848. {
  849. dict.Add("periodId", periodId);
  850. }
  851. if (request.TryGetProperty("subjectId", out JsonElement subjectId))
  852. {
  853. dict.Add("subjectId", subjectId);
  854. }
  855. if (request.TryGetProperty("level", out JsonElement level))
  856. {
  857. dict.Add("level", level);
  858. }
  859. if (request.TryGetProperty("type", out JsonElement type))
  860. {
  861. dict.Add("type", type);
  862. }
  863. if (request.TryGetProperty("field", out JsonElement field))
  864. {
  865. dict.Add("field", field);
  866. }
  867. if (request.TryGetProperty("gradeIds[*]", out JsonElement gradeIds))
  868. {
  869. dict.Add("gradeIds[*]", gradeIds);
  870. }
  871. if (request.TryGetProperty("knowledge[*]", out JsonElement knowledge))
  872. {
  873. dict.Add("knowledge[*]", knowledge);
  874. }
  875. if (request.TryGetProperty("pid", out JsonElement pd))
  876. {
  877. if (pd.ValueKind != JsonValueKind.Null)
  878. {
  879. dict.Add("pid", pd.ToString());
  880. }
  881. else
  882. {
  883. dict.Add("pid", null);
  884. }
  885. }
  886. AzureCosmosQuery cosmosDbQuery = SQLHelper.GetSQL(dict, sql);
  887. List<object> items = new List<object>();
  888. if (scope.ToString().Equals("private"))
  889. {
  890. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{code}") }))
  891. {
  892. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  893. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  894. {
  895. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  896. {
  897. items.Add(obj.ToObject<object>());
  898. }
  899. }
  900. }
  901. }
  902. if (scope.ToString().Equals("school"))
  903. {
  904. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{code}") }))
  905. {
  906. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  907. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  908. {
  909. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  910. {
  911. items.Add(obj.ToObject<object>());
  912. }
  913. }
  914. }
  915. }
  916. //ResponseBuilder builder = ResponseBuilder.custom();
  917. /* List<ItemInfo> items = new List<ItemInfo>();
  918. if (StringHelper.getKeyCount(request) > 0)
  919. {
  920. items = await _azureCosmos.FindByDict<ItemInfo>(request);
  921. }*/
  922. return Ok(new { items });
  923. //return builder.Data(items).build();
  924. }
  925. catch (Exception e)
  926. {
  927. await _dingDing.SendBotMsg($"OS,{_option.Location},item/Find()\n{e.Message}\n{e.StackTrace}", GroupNames.醍摩豆服務運維群組);
  928. return BadRequest();
  929. }
  930. }
  931. /// <summary>
  932. /// 自动组题
  933. /// </summary>
  934. /// <param name="request"></param>
  935. /// <returns></returns>
  936. [HttpPost("automatic")]
  937. [Authorize(Roles = "IES")]
  938. public async Task<IActionResult> Automatic(List<Compose> request)
  939. {
  940. try
  941. {
  942. //ResponseBuilder builder = ResponseBuilder.custom();
  943. List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
  944. var client = _azureCosmos.GetCosmosClient();
  945. for (int i = 0; i < request.Count; i++)
  946. {
  947. ///处理知识点均分问题
  948. int avg = 0;
  949. Dictionary<string, int> point = new Dictionary<string, int>();
  950. if (request[i].points.IsNotEmpty())
  951. {
  952. avg = (int)Math.Ceiling(request[i].count * 1.0 / request[i].points.Count);
  953. foreach (string p in request[i].points)
  954. {
  955. point.TryAdd(p, avg);
  956. }
  957. }
  958. List<ItemInfo> retnInfos = new List<ItemInfo>();
  959. List<ItemInfo> itemInfos = new List<ItemInfo>();
  960. List<TempItem> tempItems = new List<TempItem>();
  961. if (request[i].quInfos.IsNotEmpty())
  962. {
  963. List<string> types = new List<string>();
  964. List<int> levels = new List<int>();
  965. foreach (QuInfo quInfo in request[i].quInfos)
  966. {
  967. StringBuilder sql = new StringBuilder();
  968. sql.Append("select c.id,c.code,c.repairResource, c.periodId,c.question,c.useCount,c.level,c.field,c.knowledge,c.type,c.option,c.createTime,c.answer,c.explain,c.children,c.score,c.gradeIds,c.subjectId,c.blob,c.scope from c ");
  969. // 自定义
  970. if (quInfo.custom.IsNotEmpty() && quInfo.policy.Equals("custom"))
  971. {
  972. foreach (Custom custom in quInfo.custom)
  973. {
  974. for (int j = 0; j < custom.count; j++)
  975. {
  976. tempItems.Add(new TempItem { level = custom.level, type = quInfo.type });
  977. }
  978. Dictionary<string, object> dict = new Dictionary<string, object>();
  979. if (!string.IsNullOrEmpty(request[i].code))
  980. {
  981. dict.Add("code", request[i].code);
  982. }
  983. if (!string.IsNullOrEmpty(request[i].period))
  984. {
  985. dict.Add("periodId", request[i].period);
  986. }
  987. if (request[i].points.IsNotEmpty())
  988. {
  989. dict.Add("knowledge[*]", request[i].points.ToArray());
  990. }
  991. //dict.Add("lite", false);
  992. dict.Add("pid", null);
  993. ///
  994. dict.Add("type", quInfo.type);
  995. dict.Add("level", custom.level);
  996. List<ItemInfo> items = new List<ItemInfo>();
  997. AzureCosmosQuery cosmosDbQuery = SQLHelper.GetSQL(dict, sql);
  998. if (request[i].scope.Equals("school"))
  999. {
  1000. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{request[i].code}") }))
  1001. {
  1002. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  1003. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  1004. {
  1005. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  1006. {
  1007. items.Add(obj.ToObject<ItemInfo>());
  1008. }
  1009. }
  1010. }
  1011. }
  1012. else
  1013. {
  1014. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{request[i].code}") }))
  1015. {
  1016. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  1017. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  1018. {
  1019. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  1020. {
  1021. items.Add(obj.ToObject<ItemInfo>());
  1022. }
  1023. }
  1024. }
  1025. }
  1026. //List<ItemInfo> items = await _azureCosmos.FindByDict<ItemInfo>(dict);
  1027. //id去重
  1028. items = items.Where((x, i) => items.FindIndex(z => z.id == x.id) == i).ToList();
  1029. ////均分知识点题目
  1030. itemInfos.AddRange(items);
  1031. }
  1032. }
  1033. else
  1034. {
  1035. Dictionary<string, object> dict = new Dictionary<string, object>();
  1036. if (!string.IsNullOrEmpty(request[i].code))
  1037. {
  1038. dict.Add("code", request[i].code);
  1039. }
  1040. if (!string.IsNullOrEmpty(request[i].period))
  1041. {
  1042. dict.Add("periodId", request[i].period);
  1043. }
  1044. if (request[i].points.IsNotEmpty())
  1045. {
  1046. dict.Add("knowledge[*]", request[i].points.ToArray());
  1047. }
  1048. if (!string.IsNullOrEmpty(request[i].subject))
  1049. {
  1050. dict.Add("subjectId", request[i].subject);
  1051. }
  1052. //dict.Add("lite", false);
  1053. dict.Add("pid", null);
  1054. dict.Add("type", quInfo.type);
  1055. List<ItemInfo> items = new List<ItemInfo>();
  1056. AzureCosmosQuery cosmosDbQuery = SQLHelper.GetSQL(dict, sql);
  1057. if (request[i].scope.Equals("school"))
  1058. {
  1059. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{request[i].code}") }))
  1060. {
  1061. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  1062. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  1063. {
  1064. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  1065. {
  1066. items.Add(obj.ToObject<ItemInfo>());
  1067. }
  1068. }
  1069. }
  1070. }
  1071. else
  1072. {
  1073. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{request[i].code}") }))
  1074. {
  1075. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  1076. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  1077. {
  1078. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  1079. {
  1080. items.Add(obj.ToObject<ItemInfo>());
  1081. }
  1082. }
  1083. }
  1084. }
  1085. //List<ItemInfo> items = await _azureCosmos.FindByDict<ItemInfo>(dict);
  1086. //id去重
  1087. Console.WriteLine(items.Count);
  1088. items = items.Where((x, i) => items.FindIndex(z => z.id == x.id) == i).ToList();
  1089. itemInfos.AddRange(items);
  1090. //均分
  1091. if (quInfo.policy.Equals("average"))
  1092. {
  1093. //按等级去重 获取所有等级
  1094. List<int> lvls = items.Where((x, i) => items.FindIndex(z => z.level == x.level) == i).Select(x => x.level).ToList();
  1095. foreach (int k in lvls)
  1096. {
  1097. int count = quInfo.count / lvls.Count;
  1098. for (int j = 0; j < count; j++)
  1099. {
  1100. tempItems.Add(new TempItem { level = k, type = quInfo.type });
  1101. }
  1102. }
  1103. // 余数 取模 随机处理
  1104. if (lvls.Count != 0)
  1105. {
  1106. int mod = quInfo.count % lvls.Count;
  1107. for (int m = 0; m < mod; m++)
  1108. {
  1109. int lv = lvls.OrderBy(x => Guid.NewGuid()).Take(1).FirstOrDefault();
  1110. tempItems.Add(new TempItem { level = lv, type = quInfo.type });
  1111. lvls.Remove(lv);
  1112. }
  1113. }
  1114. }
  1115. //随机
  1116. if (quInfo.policy.Equals("random"))
  1117. {
  1118. List<int> lvls = items.Where((x, i) => items.FindIndex(z => z.level == x.level) == i).Select(x => x.level).ToList();
  1119. for (int n = 0; n < quInfo.count; n++)
  1120. {
  1121. int lv = lvls.OrderBy(x => Guid.NewGuid()).FirstOrDefault();
  1122. tempItems.Add(new TempItem { level = lv, type = quInfo.type, policy = "random" });
  1123. }
  1124. }
  1125. }
  1126. }
  1127. }
  1128. itemInfos = itemInfos.OrderBy(x => Guid.NewGuid()).ToList();
  1129. tempItems = tempItems.OrderBy(x => Guid.NewGuid()).ToList();
  1130. foreach (TempItem temp in tempItems)
  1131. {
  1132. ItemInfo itemInfo = new ItemInfo();
  1133. if (temp.policy != null && temp.policy.Equals("random"))
  1134. {
  1135. itemInfo = itemInfos.Where(x => x.type == temp.type).OrderBy(x => Guid.NewGuid()).FirstOrDefault();
  1136. }
  1137. else
  1138. {
  1139. itemInfo = itemInfos.Where(x => x.level == temp.level && x.type == temp.type).OrderBy(x => Guid.NewGuid()).FirstOrDefault();
  1140. }
  1141. if (itemInfo != null)
  1142. {
  1143. retnInfos.Add(itemInfo);
  1144. itemInfos.Remove(itemInfo);
  1145. }
  1146. }
  1147. List<ItemInfo> restItem = new List<ItemInfo>();
  1148. //处理综合题问题
  1149. foreach (var item in retnInfos)
  1150. {
  1151. if (!string.IsNullOrWhiteSpace(item.pid))
  1152. {
  1153. if (item.scope .Equals("school"))
  1154. {
  1155. var iteme = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<ItemInfo>(item.id, new PartitionKey(item.code));
  1156. if (iteme != null)
  1157. {
  1158. restItem.Add(iteme.Value);
  1159. }
  1160. }
  1161. else if (item.scope .Equals("private"))
  1162. {
  1163. var iteme = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<ItemInfo>(item.id, new PartitionKey(item.code));
  1164. if (iteme != null)
  1165. {
  1166. restItem.Add(iteme.Value);
  1167. }
  1168. }
  1169. }
  1170. else
  1171. {
  1172. restItem.Add(item);
  1173. }
  1174. }
  1175. List<List<ItemInfo>> listInfo = new List<List<ItemInfo>>();
  1176. //处理综合题id重复
  1177. restItem = restItem.Where((x, i) => restItem.FindIndex(z => z.id == x.id) == i).ToList();
  1178. foreach (IGrouping<string, ItemInfo> group in restItem.GroupBy(c => c.type))
  1179. {
  1180. Dictionary<string, object> dictInfo = new Dictionary<string, object>();
  1181. listInfo.Add(group.ToList());
  1182. }
  1183. foreach (List<ItemInfo> infos in listInfo)
  1184. {
  1185. List<Dictionary<string, object>> dict = new List<Dictionary<string, object>>();
  1186. foreach (IGrouping<int, ItemInfo> group in infos.GroupBy(c => c.level))
  1187. {
  1188. Dictionary<string, object> dictInfo = new Dictionary<string, object>();
  1189. dictInfo.Add("level", group.Key);
  1190. dictInfo.Add("count", group.Count());
  1191. dict.Add(dictInfo);
  1192. }
  1193. Dictionary<string, object> typeDict = new Dictionary<string, object>();
  1194. typeDict.Add("info", dict);
  1195. typeDict.Add("item", infos);
  1196. typeDict.Add("count", infos.Count);
  1197. typeDict.Add("type", infos.FirstOrDefault().type);
  1198. list.Add(typeDict);
  1199. }
  1200. }
  1201. //return builder.Data(list).build();
  1202. return Ok(list);
  1203. }
  1204. catch (Exception e)
  1205. {
  1206. await _dingDing.SendBotMsg($"OS,{_option.Location},item/Automatic()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
  1207. return BadRequest();
  1208. }
  1209. }
  1210. }
  1211. public class TempItem
  1212. {
  1213. public string type { get; set; }
  1214. public int level { get; set; }
  1215. public ItemInfo itemInfo { get; set; }
  1216. public string policy { get; set; }
  1217. }
  1218. public class Compose
  1219. {
  1220. /// <summary>
  1221. /// 科目
  1222. /// </summary>
  1223. public string subject { get; set; }
  1224. /// <summary>
  1225. /// 来源,个人题库,校本题库
  1226. /// </summary>
  1227. public string code { get; set; }
  1228. /// <summary>
  1229. /// 适用学段,小学,初中,高中
  1230. /// </summary>
  1231. public string period { get; set; }
  1232. /// <summary>
  1233. /// 关联知识点
  1234. /// </summary>
  1235. public List<string> points { get; set; }
  1236. /// <summary>
  1237. /// 题目组合
  1238. /// </summary>
  1239. public List<QuInfo> quInfos { get; set; }
  1240. /// <summary>
  1241. /// 题目总数
  1242. /// </summary>
  1243. public int count { get; set; }
  1244. public string scope { get; set; }
  1245. }
  1246. public class QuInfo
  1247. {
  1248. /// <summary>
  1249. /// 题目类型,单选,多选,判断,填空,问答,综合 Single单选,Multiple多选,Judge判断,Complete填空,Subjective问答,Compose综合
  1250. /// </summary>
  1251. public string type { get; set; }
  1252. /// <summary>
  1253. /// 随机 random 平均的 average ,自定义 custom
  1254. /// </summary>
  1255. public string policy { get; set; }
  1256. /// <summary>
  1257. /// 自定义题目类型
  1258. /// </summary>
  1259. public List<Custom> custom { get; set; }
  1260. /// <summary>
  1261. /// 总题
  1262. /// </summary>
  1263. public int count { get; set; }
  1264. }
  1265. public class Custom
  1266. {
  1267. /// <summary>
  1268. /// 难易程度
  1269. /// </summary>
  1270. public int level { get; set; }
  1271. /// <summary>
  1272. /// 数量
  1273. /// </summary>
  1274. public int count { get; set; }
  1275. }
  1276. }