ItemController.cs 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  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;
  8. using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
  9. using TEAMModelOS.SDK.DI;
  10. using System.Text.Json;
  11. using TEAMModelOS.SDK.Helper.Common.StringHelper;
  12. using TEAMModelOS.SDK.Models;
  13. using Microsoft.AspNetCore.Http;
  14. using TEAMModelOS.SDK.Extension;
  15. using Azure.Cosmos;
  16. using Microsoft.AspNetCore.Authentication;
  17. using System.Text;
  18. using TEAMModelOS.SDK.DI.AzureCosmos.Inner;
  19. using Microsoft.Extensions.Options;
  20. using Azure.Messaging.ServiceBus;
  21. using Microsoft.Extensions.Configuration;
  22. using TEAMModelOS.Services.Common;
  23. namespace TEAMModelOS.Controllers
  24. {
  25. [ProducesResponseType(StatusCodes.Status200OK)]
  26. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  27. //[Authorize(Roles = "IES5")]
  28. [Route("item")]
  29. //[Route("api/[controller]")]
  30. [ApiController]
  31. public class ItemController : ControllerBase
  32. {
  33. private readonly SnowflakeId _snowflakeId;
  34. private readonly AzureCosmosFactory _azureCosmos;
  35. private readonly DingDing _dingDing;
  36. private readonly Option _option;
  37. private readonly AzureStorageFactory _azureStorage;
  38. private readonly AzureServiceBusFactory _serviceBus;
  39. public IConfiguration _configuration { get; set; }
  40. public ItemController(AzureCosmosFactory azureCosmos, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option, AzureStorageFactory azureStorage, 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. }
  50. [ProducesDefaultResponseType]
  51. [HttpPost("cond-count")]
  52. public async Task<IActionResult> CondCount(JsonElement request) {
  53. try
  54. {
  55. var client = _azureCosmos.GetCosmosClient();
  56. if (!request.TryGetProperty("periodId", out JsonElement periodId)) return BadRequest();
  57. if (!request.TryGetProperty("schoolCode", out JsonElement schoolCode)) return BadRequest();
  58. ItemCond itemCond = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<ItemCond>($"{periodId}", new PartitionKey($"ItemCond-{schoolCode}"));
  59. return Ok(new { itemCond });
  60. } catch (Exception ex) {
  61. await _dingDing.SendBotMsg($"OS,{_option.Location},item/cond-count()\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
  62. return BadRequest();
  63. }
  64. }
  65. [ProducesDefaultResponseType]
  66. [HttpPost("upsert")]
  67. public async Task<IActionResult> Upsert(JsonElement request)
  68. {
  69. /* if (string.IsNullOrEmpty(request.id))
  70. {
  71. request.id = _snowflakeId.NextId() + "";
  72. request.code = typeof(ItemInfo).Name + "-" + request.code;
  73. };
  74. request.createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  75. return Ok(await _azureCosmos.SaveOrUpdate(request));*/
  76. var client = _azureCosmos.GetCosmosClient();
  77. if (!request.TryGetProperty("itemInfo", out JsonElement item)) return BadRequest();
  78. if (!request.TryGetProperty("option", out JsonElement option)) return BadRequest();
  79. try
  80. {
  81. ItemInfo itemInfo;
  82. itemInfo = item.ToObject<ItemInfo>();
  83. itemInfo.size = await _azureStorage.GetBlobContainerClient(itemInfo.code).GetBlobsSize($"item/{itemInfo.id}");
  84. var messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "update", root = $"item/{itemInfo.id}", name = $"{itemInfo.code}" }.ToJsonString());
  85. messageBlob.ApplicationProperties.Add("name", "BlobRoot");
  86. var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
  87. await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageBlob);
  88. if (option.ToString().Equals("insert"))
  89. {
  90. itemInfo.createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  91. //DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  92. if (!itemInfo.code.Contains("Item"))
  93. {
  94. itemInfo.code = "Item-" + itemInfo.code;
  95. // itemInfo = await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync(itemInfo, itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  96. }
  97. var response = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  98. if (response.Status == 200)
  99. {
  100. return Ok();
  101. }
  102. else
  103. {
  104. if (itemInfo.scope.Equals("private"))
  105. {
  106. itemInfo = await client.GetContainer("TEAMModelOS", "Teacher").CreateItemAsync(itemInfo, new PartitionKey($"{itemInfo.code}"));
  107. }
  108. else
  109. {
  110. // itemInfo.periodId
  111. itemInfo = await client.GetContainer("TEAMModelOS", "School").CreateItemAsync(itemInfo, new PartitionKey($"{itemInfo.code}"));
  112. ItemCond itemCond = null;
  113. try {
  114. itemCond = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<ItemCond>(itemInfo.periodId, new PartitionKey($"ItemCond-{itemInfo.code.Replace("Item-", "")}"));
  115. } catch (Exception ex) {
  116. itemCond = new ItemCond() { id = itemInfo.periodId, code = $"ItemCond-hbcn", pk = "ItemCond", ttl = -1, conds = new Dictionary<string, List<CondCount>>() };
  117. };
  118. ItemService.CountItemCond(itemInfo, null, itemCond);
  119. await client.GetContainer("TEAMModelOS", "School").UpsertItemAsync<ItemCond>(itemCond, new PartitionKey(itemCond.code));
  120. }
  121. }
  122. }
  123. else
  124. {
  125. itemInfo.createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  126. if (itemInfo.scope.Equals("private"))
  127. {
  128. if (!itemInfo.code.Contains("Item"))
  129. {
  130. itemInfo.code = "Item-" + itemInfo.code;
  131. }
  132. itemInfo = await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync(itemInfo, itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  133. }
  134. else
  135. {
  136. if (!itemInfo.code.Contains("Item"))
  137. {
  138. itemInfo.code = "Item-" + itemInfo.code;
  139. }
  140. ItemInfo olditemInfo = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<ItemInfo>( itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  141. itemInfo = await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync(itemInfo, itemInfo.id, new PartitionKey($"{itemInfo.code}"));
  142. //更新题目数量
  143. ItemCond itemCond = null;
  144. try
  145. {
  146. itemCond = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<ItemCond>(itemInfo.periodId, new PartitionKey($"ItemCond-{itemInfo.code.Replace("Item-", "")}"));
  147. }
  148. catch (Exception ex)
  149. {
  150. itemCond = new ItemCond() { id = itemInfo.periodId, code = $"ItemCond-hbcn", pk = "ItemCond", ttl = -1, conds = new Dictionary<string, List<CondCount>>() };
  151. };
  152. ItemService.CountItemCond(itemInfo, olditemInfo, itemCond);
  153. await client.GetContainer("TEAMModelOS", "School").UpsertItemAsync<ItemCond>(itemCond, new PartitionKey(itemCond.code));
  154. }
  155. }
  156. return Ok(new { itemInfo });
  157. }
  158. catch (Exception ex)
  159. {
  160. await _dingDing.SendBotMsg($"OS,{_option.Location},item/upsert()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  161. return BadRequest();
  162. }
  163. }
  164. /// <summary>
  165. //获取题目摘要信息
  166. /// </summary>
  167. /// <param name="request"></param>
  168. /// <returns></returns>
  169. [ProducesDefaultResponseType]
  170. //[AuthToken(Roles = "teacher")]
  171. [HttpPost("find-summary")]
  172. public async Task<IActionResult> FindSummary(JsonElement requert)
  173. {
  174. try
  175. {
  176. var client = _azureCosmos.GetCosmosClient();
  177. StringBuilder sql = new StringBuilder();
  178. sql.Append("select c.id, c.question,c.useCount,c.level,c.field,c.knowledge,c.type,c.option,c.createTime from c ");
  179. if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
  180. /* if (!requert.TryGetProperty("@CURRPAGE", out JsonElement page)) return BadRequest();
  181. if (!requert.TryGetProperty("@PAGESIZE", out JsonElement size)) return BadRequest();*/
  182. if (!requert.TryGetProperty("@DESC", out JsonElement desc)) return BadRequest();
  183. if (!requert.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
  184. List<object> summary = new List<object>();
  185. Dictionary<string, object> dict = new Dictionary<string, object>();
  186. /* dict.Add("@CURRPAGE", page.GetInt32());
  187. dict.Add("@PAGESIZE", size.GetInt32());*/
  188. dict.Add("@DESC", desc.ToString());
  189. if (requert.TryGetProperty("periodId", out JsonElement periodId))
  190. {
  191. dict.Add("periodId", periodId);
  192. }
  193. if (requert.TryGetProperty("subjectId", out JsonElement subjectId))
  194. {
  195. dict.Add("subjectId", subjectId);
  196. }
  197. if (requert.TryGetProperty("level", out JsonElement level))
  198. {
  199. dict.Add("level", level);
  200. }
  201. if (requert.TryGetProperty("type", out JsonElement type))
  202. {
  203. dict.Add("type", type);
  204. }
  205. if (requert.TryGetProperty("field", out JsonElement field))
  206. {
  207. dict.Add("field", field);
  208. }
  209. AzureCosmosQuery cosmosDbQuery = SQLHelper.GetSQL(dict, sql);
  210. //List<object> items = new List<object>();
  211. if (scope.ToString().Equals("private"))
  212. {
  213. await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{code}") }))
  214. {
  215. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  216. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  217. {
  218. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  219. {
  220. summary.Add(obj.ToObject<object>());
  221. }
  222. }
  223. }
  224. }
  225. if (scope.ToString().Equals("school"))
  226. {
  227. await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{code}") }))
  228. {
  229. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  230. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  231. {
  232. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  233. {
  234. summary.Add(obj.ToObject<object>());
  235. }
  236. }
  237. }
  238. }
  239. return Ok(new { summary });
  240. }
  241. catch (Exception ex)
  242. {
  243. await _dingDing.SendBotMsg($"OS,{_option.Location},item/FindSummary()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  244. return BadRequest();
  245. }
  246. }
  247. /// <summary>
  248. /// 删除
  249. /// </summary>
  250. /// <param name="request"></param>
  251. /// <returns></returns>
  252. [ProducesDefaultResponseType]
  253. //[AuthToken(Roles = "teacher")]
  254. [HttpPost("delete")]
  255. public async Task<IActionResult> Delete(JsonElement request)
  256. {
  257. try
  258. {
  259. if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
  260. if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
  261. if (!request.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
  262. var client = _azureCosmos.GetCosmosClient();
  263. //删除blob 相关资料
  264. await _azureStorage.GetBlobServiceClient().DelectBlobs(code.ToString().Replace("Item-",""), $"item/{id}");
  265. //通知删除信息
  266. var messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "delete", root = $"item/{id}", name = code.ToString().Replace("Item-", "") }.ToJsonString());
  267. messageBlob.ApplicationProperties.Add("name", "BlobRoot");
  268. var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
  269. await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageBlob);
  270. if (scope.ToString().Equals("school"))
  271. {
  272. ItemInfo itemInfo = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<ItemInfo>(id.ToString(), new PartitionKey($"{code}"));
  273. var response = await client.GetContainer("TEAMModelOS", "School").DeleteItemStreamAsync(id.ToString(), new PartitionKey($"{code}"));
  274. //更新题目数量
  275. ItemCond itemCond = null;
  276. try
  277. {
  278. itemCond = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<ItemCond>(itemInfo.periodId, new PartitionKey($"ItemCond-{itemInfo.code.Replace("Item-", "")}"));
  279. }
  280. catch (Exception ex)
  281. {
  282. itemCond = new ItemCond() { id = itemInfo.periodId, code = $"ItemCond-hbcn", pk = "ItemCond", ttl = -1, conds = new Dictionary<string, List<CondCount>>() };
  283. };
  284. ItemService.CountItemCond(null, itemInfo, itemCond);
  285. await client.GetContainer("TEAMModelOS", "School").UpsertItemAsync<ItemCond>(itemCond, new PartitionKey(itemCond.code));
  286. return Ok(new { code = response.Status });
  287. }
  288. else
  289. {
  290. var response = await client.GetContainer("TEAMModelOS", "Teacher").DeleteItemStreamAsync(id.ToString(), new PartitionKey($"{code}"));
  291. return Ok(new { code = response.Status });
  292. }
  293. }
  294. catch (Exception e)
  295. {
  296. await _dingDing.SendBotMsg($"OS,{_option.Location},item/delete()\n{e.Message},{e.StackTrace}", GroupNames.醍摩豆服務運維群組);
  297. return BadRequest();
  298. }
  299. /* ResponseBuilder builder = ResponseBuilder.custom();
  300. IdPk idPk = await _azureCosmos.DeleteAsync<ItemInfo>( request );
  301. return Ok(idPk);*/
  302. }
  303. /// <summary>
  304. /// 手动挑题
  305. /// </summary>
  306. /// <param name="request"></param>
  307. /// <returns></returns>
  308. [ProducesDefaultResponseType]
  309. //[AuthToken(Roles = "teacher")]
  310. [HttpPost("find")]
  311. public async Task<IActionResult> Find(JsonElement requert)
  312. {
  313. try
  314. {
  315. var client = _azureCosmos.GetCosmosClient();
  316. StringBuilder sql = new StringBuilder();
  317. 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 ");
  318. if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
  319. /* if (!requert.TryGetProperty("@CURRPAGE", out JsonElement page)) return BadRequest();
  320. if (!requert.TryGetProperty("@PAGESIZE", out JsonElement size)) return BadRequest();*/
  321. if (!requert.TryGetProperty("@DESC", out JsonElement desc)) return BadRequest();
  322. if (!requert.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
  323. Dictionary<string, object> dict = new Dictionary<string, object>();
  324. /*var emobj = requert.EnumerateObject();
  325. while (emobj.MoveNext())
  326. {
  327. dict[emobj.Current.Name] = emobj.Current.Value;
  328. }
  329. //处理code
  330. if (dict.TryGetValue("code", out object _))
  331. {
  332. dict.Remove("code");
  333. }*/
  334. /* dict.Add("@CURRPAGE", page.GetInt32());
  335. dict.Add("@PAGESIZE", size.GetInt32());*/
  336. dict.Add("@DESC", desc.ToString());
  337. if (requert.TryGetProperty("periodId", out JsonElement periodId))
  338. {
  339. dict.Add("periodId", periodId);
  340. }
  341. if (requert.TryGetProperty("subjectId", out JsonElement subjectId))
  342. {
  343. dict.Add("subjectId", subjectId);
  344. }
  345. if (requert.TryGetProperty("level", out JsonElement level))
  346. {
  347. dict.Add("level", level);
  348. }
  349. if (requert.TryGetProperty("type", out JsonElement type))
  350. {
  351. dict.Add("type", type);
  352. }
  353. if (requert.TryGetProperty("field", out JsonElement field))
  354. {
  355. dict.Add("field", field);
  356. }
  357. if (requert.TryGetProperty("gradeIds[*]", out JsonElement gradeIds))
  358. {
  359. dict.Add("gradeIds[*]", gradeIds);
  360. }
  361. if (requert.TryGetProperty("pid", out JsonElement pd))
  362. {
  363. if (pd.ValueKind != JsonValueKind.Null)
  364. {
  365. dict.Add("pid", pd.ToString());
  366. }
  367. else
  368. {
  369. dict.Add("pid", null);
  370. }
  371. }
  372. AzureCosmosQuery cosmosDbQuery = SQLHelper.GetSQL(dict, sql);
  373. List<object> items = new List<object>();
  374. if (scope.ToString().Equals("private"))
  375. {
  376. await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{code}") }))
  377. {
  378. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  379. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  380. {
  381. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  382. {
  383. items.Add(obj.ToObject<object>());
  384. }
  385. }
  386. }
  387. }
  388. if (scope.ToString().Equals("school"))
  389. {
  390. await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{code}") }))
  391. {
  392. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  393. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  394. {
  395. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  396. {
  397. items.Add(obj.ToObject<object>());
  398. }
  399. }
  400. }
  401. }
  402. //ResponseBuilder builder = ResponseBuilder.custom();
  403. /* List<ItemInfo> items = new List<ItemInfo>();
  404. if (StringHelper.getKeyCount(requert) > 0)
  405. {
  406. items = await _azureCosmos.FindByDict<ItemInfo>(requert);
  407. }*/
  408. return Ok(new { items });
  409. //return builder.Data(items).build();
  410. }
  411. catch (Exception e)
  412. {
  413. await _dingDing.SendBotMsg($"OS,{_option.Location},item/Find()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
  414. return BadRequest(e.StackTrace);
  415. }
  416. }
  417. /// <summary>
  418. /// 手动挑题
  419. /// </summary>
  420. /// <param name="request"></param>
  421. /// <returns></returns>
  422. [ProducesDefaultResponseType]
  423. //[AuthToken(Roles = "teacher")]
  424. [HttpPost("Find-cache-shell")]
  425. public async Task<IActionResult> FindCacheShell(JsonElement requert)
  426. {
  427. var client = _azureCosmos.GetCosmosClient();
  428. if (!requert.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
  429. if (!requert.TryGetProperty("ids", out JsonElement id)) return BadRequest();
  430. //List<string> ids = new List<string>();
  431. string info = "";
  432. for (int i = 0; i < id.GetArrayLength(); i++)
  433. {
  434. //ids.Add(id[i].ToJsonString());
  435. info += id[i].ToJsonString() + ",";
  436. }
  437. List<object> items = new List<object>();
  438. var query = $"select c.id, c.question,c.useCount,c.level,c.field,c.knowledge,c.type,c.option,c.createTime from c where c.id in ({info[0..^1]})";
  439. await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{school_code}") }))
  440. {
  441. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  442. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  443. {
  444. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  445. {
  446. items.Add(obj.ToObject<object>());
  447. }
  448. }
  449. }
  450. return Ok(new { items });
  451. }
  452. /// <summary>
  453. /// 自动组题
  454. /// </summary>
  455. /// <param name="request"></param>
  456. /// <returns></returns>
  457. [HttpPost("Automatic")]
  458. public async Task<IActionResult> Automatic(List<Compose> request)
  459. {
  460. try
  461. {
  462. //ResponseBuilder builder = ResponseBuilder.custom();
  463. List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
  464. var client = _azureCosmos.GetCosmosClient();
  465. for (int i = 0; i < request.Count; i++)
  466. {
  467. ///处理知识点均分问题
  468. int avg = 0;
  469. Dictionary<string, int> point = new Dictionary<string, int>();
  470. if (request[i].points.IsNotEmpty())
  471. {
  472. avg = (int)Math.Ceiling(request[i].count * 1.0 / request[i].points.Count);
  473. foreach (string p in request[i].points)
  474. {
  475. point.TryAdd(p, avg);
  476. }
  477. }
  478. List<ItemInfo> retnInfos = new List<ItemInfo>();
  479. List<ItemInfo> itemInfos = new List<ItemInfo>();
  480. List<TempItem> tempItems = new List<TempItem>();
  481. if (request[i].quInfos.IsNotEmpty())
  482. {
  483. List<string> types = new List<string>();
  484. List<int> levels = new List<int>();
  485. foreach (QuInfo quInfo in request[i].quInfos)
  486. {
  487. StringBuilder sql = new StringBuilder();
  488. 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 ");
  489. // 自定义
  490. if (quInfo.custom.IsNotEmpty() && quInfo.policy.Equals("custom"))
  491. {
  492. foreach (Custom custom in quInfo.custom)
  493. {
  494. for (int j = 0; j < custom.count; j++)
  495. {
  496. tempItems.Add(new TempItem { level = custom.level, type = quInfo.type });
  497. }
  498. Dictionary<string, object> dict = new Dictionary<string, object>();
  499. if (!string.IsNullOrEmpty(request[i].code))
  500. {
  501. dict.Add("code", request[i].code);
  502. }
  503. if (!string.IsNullOrEmpty(request[i].period))
  504. {
  505. dict.Add("periodId", request[i].period);
  506. }
  507. if (request[i].points.IsNotEmpty())
  508. {
  509. dict.Add("knowledge[*]", request[i].points.ToArray());
  510. }
  511. //dict.Add("lite", false);
  512. dict.Add("pid", null);
  513. ///
  514. dict.Add("type", quInfo.type);
  515. dict.Add("level", custom.level);
  516. List<ItemInfo> items = new List<ItemInfo>();
  517. AzureCosmosQuery cosmosDbQuery = SQLHelper.GetSQL(dict, sql);
  518. if (request[i].scope.Equals("school"))
  519. {
  520. await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{request[i].code}") }))
  521. {
  522. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  523. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  524. {
  525. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  526. {
  527. items.Add(obj.ToObject<ItemInfo>());
  528. }
  529. }
  530. }
  531. }
  532. else
  533. {
  534. await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{request[i].code}") }))
  535. {
  536. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  537. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  538. {
  539. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  540. {
  541. items.Add(obj.ToObject<ItemInfo>());
  542. }
  543. }
  544. }
  545. }
  546. //List<ItemInfo> items = await _azureCosmos.FindByDict<ItemInfo>(dict);
  547. //id去重
  548. items = items.Where((x, i) => items.FindIndex(z => z.id == x.id) == i).ToList();
  549. ////均分知识点题目
  550. itemInfos.AddRange(items);
  551. }
  552. }
  553. else
  554. {
  555. Dictionary<string, object> dict = new Dictionary<string, object>();
  556. if (!string.IsNullOrEmpty(request[i].code))
  557. {
  558. dict.Add("code", request[i].code);
  559. }
  560. if (!string.IsNullOrEmpty(request[i].period))
  561. {
  562. dict.Add("periodId", request[i].period);
  563. }
  564. if (request[i].points.IsNotEmpty())
  565. {
  566. dict.Add("knowledge[*]", request[i].points.ToArray());
  567. }
  568. if (!string.IsNullOrEmpty(request[i].subject))
  569. {
  570. dict.Add("subjectId", request[i].subject);
  571. }
  572. //dict.Add("lite", false);
  573. dict.Add("pid", null);
  574. dict.Add("type", quInfo.type);
  575. List<ItemInfo> items = new List<ItemInfo>();
  576. AzureCosmosQuery cosmosDbQuery = SQLHelper.GetSQL(dict, sql);
  577. if (request[i].scope.Equals("school"))
  578. {
  579. await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{request[i].code}") }))
  580. {
  581. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  582. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  583. {
  584. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  585. {
  586. items.Add(obj.ToObject<ItemInfo>());
  587. }
  588. }
  589. }
  590. }
  591. else
  592. {
  593. await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{request[i].code}") }))
  594. {
  595. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  596. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  597. {
  598. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  599. {
  600. items.Add(obj.ToObject<ItemInfo>());
  601. }
  602. }
  603. }
  604. }
  605. //List<ItemInfo> items = await _azureCosmos.FindByDict<ItemInfo>(dict);
  606. //id去重
  607. items = items.Where((x, i) => items.FindIndex(z => z.id == x.id) == i).ToList();
  608. itemInfos.AddRange(items);
  609. //均分
  610. if (quInfo.policy.Equals("average"))
  611. {
  612. //按等级去重 获取所有等级
  613. List<int> lvls = items.Where((x, i) => items.FindIndex(z => z.level == x.level) == i).Select(x => x.level).ToList();
  614. foreach (int k in lvls)
  615. {
  616. int count = quInfo.count / lvls.Count;
  617. for (int j = 0; j < count; j++)
  618. {
  619. tempItems.Add(new TempItem { level = k, type = quInfo.type });
  620. }
  621. }
  622. // 余数 取模 随机处理
  623. if (lvls.Count != 0)
  624. {
  625. int mod = quInfo.count % lvls.Count;
  626. for (int m = 0; m < mod; m++)
  627. {
  628. int lv = lvls.OrderBy(x => Guid.NewGuid()).Take(1).FirstOrDefault();
  629. tempItems.Add(new TempItem { level = lv, type = quInfo.type });
  630. lvls.Remove(lv);
  631. }
  632. }
  633. }
  634. //随机
  635. if (quInfo.policy.Equals("random"))
  636. {
  637. List<int> lvls = items.Where((x, i) => items.FindIndex(z => z.level == x.level) == i).Select(x => x.level).ToList();
  638. for (int n = 0; n < quInfo.count; n++)
  639. {
  640. int lv = lvls.OrderBy(x => Guid.NewGuid()).FirstOrDefault();
  641. tempItems.Add(new TempItem { level = lv, type = quInfo.type, policy = "random" });
  642. }
  643. }
  644. }
  645. }
  646. }
  647. itemInfos = itemInfos.OrderBy(x => Guid.NewGuid()).ToList();
  648. tempItems = tempItems.OrderBy(x => Guid.NewGuid()).ToList();
  649. foreach (TempItem temp in tempItems)
  650. {
  651. ItemInfo itemInfo = new ItemInfo();
  652. if (temp.policy != null && temp.policy.Equals("random"))
  653. {
  654. itemInfo = itemInfos.Where(x => x.type == temp.type).OrderBy(x => Guid.NewGuid()).FirstOrDefault();
  655. }
  656. else
  657. {
  658. itemInfo = itemInfos.Where(x => x.level == temp.level && x.type == temp.type).OrderBy(x => Guid.NewGuid()).FirstOrDefault();
  659. }
  660. if (itemInfo != null)
  661. {
  662. retnInfos.Add(itemInfo);
  663. itemInfos.Remove(itemInfo);
  664. }
  665. }
  666. List<ItemInfo> restItem = new List<ItemInfo>();
  667. //处理综合题问题
  668. foreach (var item in retnInfos)
  669. {
  670. if (!string.IsNullOrWhiteSpace(item.pid))
  671. {
  672. if (item.scope == "school")
  673. {
  674. var iteme = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<ItemInfo>(item.id, new PartitionKey(item.code));
  675. if (iteme != null)
  676. {
  677. restItem.Add(iteme.Value);
  678. }
  679. }
  680. else if (item.scope == "private")
  681. {
  682. var iteme = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<ItemInfo>(item.id, new PartitionKey(item.code));
  683. if (iteme != null)
  684. {
  685. restItem.Add(iteme.Value);
  686. }
  687. }
  688. }
  689. else
  690. {
  691. restItem.Add(item);
  692. }
  693. }
  694. List<List<ItemInfo>> listInfo = new List<List<ItemInfo>>();
  695. //处理综合题id重复
  696. restItem = restItem.Where((x, i) => restItem.FindIndex(z => z.id == x.id) == i).ToList();
  697. foreach (IGrouping<string, ItemInfo> group in restItem.GroupBy(c => c.type))
  698. {
  699. Dictionary<string, object> dictInfo = new Dictionary<string, object>();
  700. listInfo.Add(group.ToList());
  701. }
  702. foreach (List<ItemInfo> infos in listInfo)
  703. {
  704. List<Dictionary<string, object>> dict = new List<Dictionary<string, object>>();
  705. foreach (IGrouping<int, ItemInfo> group in infos.GroupBy(c => c.level))
  706. {
  707. Dictionary<string, object> dictInfo = new Dictionary<string, object>();
  708. dictInfo.Add("level", group.Key);
  709. dictInfo.Add("count", group.Count());
  710. dict.Add(dictInfo);
  711. }
  712. Dictionary<string, object> typeDict = new Dictionary<string, object>();
  713. typeDict.Add("info", dict);
  714. typeDict.Add("item", infos);
  715. typeDict.Add("count", infos.Count);
  716. typeDict.Add("type", infos.FirstOrDefault().type);
  717. list.Add(typeDict);
  718. }
  719. }
  720. //return builder.Data(list).build();
  721. return Ok(list);
  722. }
  723. catch (Exception e)
  724. {
  725. await _dingDing.SendBotMsg($"OS,{_option.Location},item/Automatic()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
  726. return BadRequest();
  727. }
  728. }
  729. }
  730. public class TempItem
  731. {
  732. public string type { get; set; }
  733. public int level { get; set; }
  734. public ItemInfo itemInfo { get; set; }
  735. public string policy { get; set; }
  736. }
  737. public class Compose
  738. {
  739. /// <summary>
  740. /// 科目
  741. /// </summary>
  742. public string subject { get; set; }
  743. /// <summary>
  744. /// 来源,个人题库,校本题库
  745. /// </summary>
  746. public string code { get; set; }
  747. /// <summary>
  748. /// 适用学段,小学,初中,高中
  749. /// </summary>
  750. public string period { get; set; }
  751. /// <summary>
  752. /// 关联知识点
  753. /// </summary>
  754. public List<string> points { get; set; }
  755. /// <summary>
  756. /// 题目组合
  757. /// </summary>
  758. public List<QuInfo> quInfos { get; set; }
  759. /// <summary>
  760. /// 题目总数
  761. /// </summary>
  762. public int count { get; set; }
  763. public string scope { get; set; }
  764. }
  765. public class QuInfo
  766. {
  767. /// <summary>
  768. /// 题目类型,单选,多选,判断,填空,问答,综合 Single单选,Multiple多选,Judge判断,Complete填空,Subjective问答,Compose综合
  769. /// </summary>
  770. public string type { get; set; }
  771. /// <summary>
  772. /// 随机 random 平均的 average ,自定义 custom
  773. /// </summary>
  774. public string policy { get; set; }
  775. /// <summary>
  776. /// 自定义题目类型
  777. /// </summary>
  778. public List<Custom> custom { get; set; }
  779. /// <summary>
  780. /// 总题
  781. /// </summary>
  782. public int count { get; set; }
  783. }
  784. public class Custom
  785. {
  786. /// <summary>
  787. /// 难易程度
  788. /// </summary>
  789. public int level { get; set; }
  790. /// <summary>
  791. /// 数量
  792. /// </summary>
  793. public int count { get; set; }
  794. }
  795. }