TestController.cs 174 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356
  1. using Azure;
  2. using Azure.Cosmos;
  3. using Azure.Storage.Blobs.Models;
  4. using DinkToPdf;
  5. using DinkToPdf.Contracts;
  6. using HTEXLib.COMM.Helpers;
  7. using Microsoft.AspNetCore.Hosting;
  8. using Microsoft.AspNetCore.Http;
  9. using Microsoft.AspNetCore.Mvc;
  10. using Microsoft.Extensions.Configuration;
  11. using Microsoft.Extensions.Options;
  12. using System;
  13. using System.Collections.Concurrent;
  14. using System.Collections.Generic;
  15. using System.IO;
  16. using System.Linq;
  17. using System.Net;
  18. using System.Net.Http;
  19. using System.Net.Http.Json;
  20. using System.Text;
  21. using System.Text.Json;
  22. using System.Threading.Tasks;
  23. using TEAMModelOS.Controllers.Third.LePei;
  24. using TEAMModelOS.Filter;
  25. using TEAMModelOS.Models;
  26. using TEAMModelOS.SDK;
  27. using TEAMModelOS.SDK.DI;
  28. using TEAMModelOS.SDK.DI.Mail;
  29. using TEAMModelOS.SDK.Extension;
  30. using TEAMModelOS.SDK.Models;
  31. using TEAMModelOS.SDK.Models.Cosmos.Common;
  32. using TEAMModelOS.SDK.Models.Service;
  33. using TEAMModelOS.SDK.Services;
  34. using static TEAMModelOS.SDK.Models.Teacher;
  35. using static TEAMModelOS.SDK.SchoolService;
  36. namespace TEAMModelOS.Controllers
  37. {
  38. [Route("test")]
  39. [ApiController]
  40. public class TestController : ControllerBase
  41. {
  42. private readonly IHttpClientFactory _httpClient;
  43. public IWebHostEnvironment _environment { get; set; }
  44. private readonly AzureStorageFactory _azureStorage;
  45. private readonly AzureRedisFactory _azureRedis;
  46. private readonly AzureCosmosFactory _azureCosmos;
  47. private readonly DingDing _dingDing;
  48. private readonly AzureServiceBusFactory _serviceBus;
  49. private readonly CoreAPIHttpService _coreAPIHttpService;
  50. private readonly Option _option;
  51. private readonly IPSearcher _searcher;
  52. public IConfiguration _configuration { get; set; }
  53. private readonly IConverter _converter;
  54. private readonly HttpTrigger _httpTrigger;
  55. private readonly AzureServiceBusFactory _azureService;
  56. private readonly SnowflakeId _snowflakeId;
  57. private readonly MailFactory _mailFactory;
  58. public TestController(MailFactory mailFactory,HttpTrigger httpTrigger, IConverter converter, IPSearcher searcher, IOptionsSnapshot<Option> option, CoreAPIHttpService coreAPIHttpService, IHttpClientFactory httpClient, IWebHostEnvironment environment, AzureCosmosFactory azureCosmos, AzureRedisFactory azureRedis, AzureStorageFactory azureStorage, IConfiguration configuration, AzureServiceBusFactory serviceBus, DingDing dingDing, AzureServiceBusFactory azureService, SnowflakeId snowflakeId)
  59. {
  60. _converter = converter;
  61. _azureCosmos = azureCosmos;
  62. _azureRedis = azureRedis;
  63. _azureStorage = azureStorage;
  64. _dingDing = dingDing;
  65. _serviceBus = serviceBus; _configuration = configuration;
  66. _environment = environment;
  67. _httpClient = httpClient;
  68. _option = option.Value;
  69. _coreAPIHttpService = coreAPIHttpService;
  70. _searcher = searcher;
  71. _httpTrigger = httpTrigger;
  72. _azureService=azureService;
  73. _snowflakeId=snowflakeId;
  74. _mailFactory = mailFactory;
  75. }
  76. //
  77. /// <summary>
  78. /// 移除已经废弃的StuCourse 数据
  79. /// </summary>
  80. /// <param name="file"></param>
  81. /// <param name="periodId"></param>
  82. /// <returns></returns>
  83. [HttpPost("test-accumulate")]
  84. [RequestSizeLimit(102_400_000_00)] //最大10000m左右
  85. public async Task<IActionResult> RemoveStuCourse(JsonElement json)
  86. {
  87. json.TryGetProperty("am", out JsonElement _am);
  88. json.TryGetProperty("pm", out JsonElement _pm);
  89. int am = 0;
  90. int pm = 0;
  91. _am.TryGetInt32(out am);
  92. _pm.TryGetInt32(out pm);
  93. var url = _configuration.GetValue<string>("HaBookAuth:CoreAPI");
  94. var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
  95. var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
  96. string location = "";
  97. if (_option.Location.Contains("China"))
  98. {
  99. location = "China";
  100. }
  101. else if (_option.Location.Contains("Global"))
  102. {
  103. location = "Global";
  104. }
  105. var client = _httpClient.CreateClient();
  106. var token = CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, location).Result;
  107. if (client.DefaultRequestHeaders.Contains("Authorization"))
  108. {
  109. client.DefaultRequestHeaders.Remove("Authorization");
  110. client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.AccessToken}");
  111. }
  112. else
  113. {
  114. client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.AccessToken}");
  115. }
  116. List<CodeValue> notifys= await SystemService.AccumulateDaily(_configuration, _azureRedis,_azureCosmos, _coreAPIHttpService,_dingDing,client, _snowflakeId, url,am ,pm );
  117. return Ok(new { notifys });
  118. }
  119. /*
  120. [
  121. {
  122. "id": "99a4a33b-e21b-44ac-80a1-b31dc40496e0",
  123. "name": "蒲江县提升工程2.0研训平台"
  124. },
  125. {
  126. "id": "f35e0031-a53f-45e5-b307-1cd39446a2cf",
  127. "name": "金牛区直属学校提升工程2.0研训平台"
  128. },
  129. {
  130. "id": "2c1b01fe-3641-464f-8499-7be95a489b7c",
  131. "name": "峨边彝族自治县提升工程2.0研训平台"
  132. },
  133. {
  134. "id": "870a5a6b-1ab3-461a-bdeb-baec19780ddb",
  135. "name": "金牛区非直属学校提升工程2.0研训平台"
  136. },
  137. {
  138. "id": "dd15017a-f361-4346-852e-8eee71d027ad",
  139. "name": "峨眉山提升工程2.0研训平台"
  140. },
  141. {
  142. "id": "3b5a9b06-a9ec-4bac-b1dd-f73f5519f637",
  143. "name": "乐山市井研县提升工程2.0研训平台"
  144. },
  145. {
  146. "id": "1680c1c5-14e4-4bc2-b4cb-1749a537a01f",
  147. "name": "宜宾市筠连县提升工程2.0研训平台"
  148. },
  149. {
  150. "id": "e6fb5d40-bd85-7327-cea8-ea5c642836d2",
  151. "name": "广安市岳池县提升工程2.0研训平台"
  152. },
  153. {
  154. "id": "b14668be-d2f0-4923-8bf6-a27d9cc9111d",
  155. "name": "犍为县提升工程2.0研训平台"
  156. },
  157. {
  158. "id": "f49a83de-6156-448a-93b1-f03d0da967d6",
  159. "name": "宜宾市屏山县提升工程2.0研训平台"
  160. },
  161. {
  162. "id": "4a37997a-12b1-4f21-876b-3d9ba940fe54",
  163. "name": "宜宾市屏山县提升工程2.0研训平台(非一线)"
  164. },
  165. {
  166. "id": "6104c377-f48f-4d4c-9b38-509f9ccb54db",
  167. "name": "武胜县提升工程2.0研训平台"
  168. }
  169. ]
  170. */
  171. /// <summary>
  172. /// 将区级下所以学校的研修数据封存
  173. /// </summary>
  174. /// <param name="data"></param>
  175. /// <returns></returns>
  176. [HttpPost("change-blob-to-archive")]
  177. [RequestSizeLimit(102_400_000_00)] //最大10000m左右
  178. public async Task<IActionResult> Change(JsonElement data)
  179. {
  180. IdName area = null;
  181. if (data.TryGetProperty("area", out JsonElement _area))
  182. {
  183. area= _area.ToObject<IdName>();
  184. }
  185. List<ScTeacher> teachers = new List<ScTeacher>();
  186. var table = _azureStorage.GetCloudTableClient().GetTableReference("ScYxpt");
  187. List<int> pids = new List<int>();
  188. if (data.TryGetProperty("pids", out JsonElement _pids))
  189. {
  190. pids=_pids.ToObject<List<int>>();
  191. }
  192. if (pids.IsNotEmpty()) {
  193. foreach (var p in pids)
  194. {
  195. List<ScTeacher> teachersTable= await table.FindListByDict<ScTeacher>(new Dictionary<string, object>() { { "PartitionKey", "ScTeacher" }, { "ProjectItemID", p } });
  196. if (teachersTable.IsNotEmpty()) {
  197. teachers.AddRange(teachersTable);
  198. }
  199. }
  200. }
  201. HashSet<string> ids = teachers.Where(v => !string.IsNullOrWhiteSpace(v.tmdid)).Select(z => z.tmdid).ToHashSet();
  202. List<SchoolEconomy> economies = new List<SchoolEconomy>(0);
  203. if (area!= null)
  204. {
  205. string sql = $"select value c from c where c.areaId ='{area.id}'";
  206. List<School> schools = new List<School>();
  207. var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<School>(sql, "Base");
  208. if (result.list.IsNotEmpty())
  209. {
  210. schools.AddRange(result.list);
  211. }
  212. foreach (var school in schools)
  213. {
  214. double? ScoresYxpt = await _azureRedis.GetRedisClient(8).SortedSetScoreAsync($"Blob:Catalog:{school.id}", "yxpt");
  215. double? ScoresTrain = await _azureRedis.GetRedisClient(8).SortedSetScoreAsync($"Blob:Catalog:{school.id}", "train");
  216. double total = ((ScoresYxpt.HasValue ? ScoresYxpt.Value : 0)+(ScoresTrain.HasValue ? ScoresTrain.Value : 0))*1.0 /1073741824; //GB
  217. List<string> yxpts = await _azureStorage.GetBlobContainerClient(school.id).List("yxpt");
  218. HashSet<string> archive = new HashSet<string>();
  219. if (yxpts.IsNotEmpty()) {
  220. foreach (var uri in yxpts)
  221. {
  222. if (ids!=null && ids.Count>0)
  223. {
  224. bool has = false;
  225. foreach (var id in ids)
  226. {
  227. if (uri.Contains(id))
  228. {
  229. has = true;
  230. break;
  231. }
  232. }
  233. if (!has)
  234. {
  235. archive.Add($"https://teammodeltest.blob.core.chinacloudapi.cn/{school.id}/{uri}");
  236. }
  237. }
  238. else
  239. {
  240. archive.Add($"https://teammodeltest.blob.core.chinacloudapi.cn/{school.id}/{uri}");
  241. }
  242. }
  243. }
  244. List<string> trains = await _azureStorage.GetBlobContainerClient(school.id).List("train");
  245. if (trains.IsNotEmpty())
  246. {
  247. foreach (var uri in trains)
  248. {
  249. if (ids!=null && ids.Count>0)
  250. {
  251. bool has = false;
  252. foreach (var id in ids)
  253. {
  254. if (uri.Contains(id))
  255. {
  256. has = true;
  257. break;
  258. }
  259. }
  260. if (!has)
  261. {
  262. archive.Add($"https://teammodeltest.blob.core.chinacloudapi.cn/{school.id}/{uri}");
  263. }
  264. }
  265. else
  266. {
  267. archive.Add($"https://teammodeltest.blob.core.chinacloudapi.cn/{school.id}/{uri}");
  268. }
  269. }
  270. }
  271. if (archive.Count==0)
  272. {
  273. economies.Add(new SchoolEconomy { schoolId= school.id, schoolName= school.name, areaId=area.id, areaName=area.name, total=0, count=(yxpts!=null ? yxpts.Count : 0)+(trains!=null ? trains.Count : 0), archive=archive.Count });
  274. }
  275. else
  276. {
  277. //var pages = archive.Page(100);
  278. //foreach (var page in pages) {
  279. // if (page.Count()==0) { continue; }
  280. // try
  281. // {
  282. // await _azureStorage.GetBlobServiceClient().GetBlobBatchClient().SetBlobsAccessTierAsync(blobUris: page.Select(z => new Uri(z)), accessTier: AccessTier.Archive);
  283. // }
  284. // catch (Exception ex1)
  285. // {
  286. // var p20s = page.Page(20);
  287. // foreach (var p20 in p20s)
  288. // {
  289. // if (p20.Count()==0) { continue; }
  290. // try
  291. // {
  292. // await _azureStorage.GetBlobServiceClient().GetBlobBatchClient().SetBlobsAccessTierAsync(blobUris: p20.Select(z => new Uri(z)), accessTier: AccessTier.Archive);
  293. // }
  294. // catch (Exception ex2)
  295. // {
  296. // var p1s = p20.Page(1);
  297. // foreach (var p1 in p1s) {
  298. // if (p1.Count()==0) { continue; }
  299. // try
  300. // {
  301. // string path = p1.First().Replace($"https://teammodeltest.blob.core.chinacloudapi.cn/{school.id}/", "");
  302. // await _azureStorage.GetBlobContainerClient(school.id).GetBlobClient(path).SetAccessTierAsync(AccessTier.Archive);
  303. // }
  304. // catch (Exception ex3)
  305. // {
  306. // await _dingDing.SendBotMsg($"错误的链接地址:{p1.ToJsonString()}", GroupNames.成都开发測試群組);
  307. // }
  308. // }
  309. // }
  310. // }
  311. // }
  312. //}
  313. economies.Add(new SchoolEconomy { schoolId= school.id, schoolName= school.name, areaId=area.id, areaName=area.name, total=total, count=(yxpts!=null ? yxpts.Count : 0)+(trains!=null ? trains.Count : 0), archive=archive.Count });
  314. }
  315. }
  316. AreaEconomy economy = new AreaEconomy {id = area.id ,name = area.name, pk="AreaEconomy",code="AreaEconomy", economies= economies, sum= economies.Select(z => z.total).Sum(), count= economies.Select(z => z.count).Sum(), teachers= ids.ToList() };
  317. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).UpsertItemAsync(economy, new PartitionKey("AreaEconomy"));
  318. return Ok(new { economy });
  319. }
  320. else { return Ok(); }
  321. }
  322. public class AreaEconomy : CosmosEntity
  323. {
  324. public AreaEconomy(){
  325. pk="AreaEconomy";
  326. code="AreaEconomy";
  327. }
  328. public List<int> pids = new List<int>();
  329. public string name { get; set; }
  330. public List<SchoolEconomy> economies { get; set; } = new List<SchoolEconomy>();
  331. public double sum { get; set; }
  332. public long count { get; set; }
  333. /// <summary>
  334. /// 未被封存的教师
  335. /// </summary>
  336. public List<string> teachers = new List<string>();
  337. }
  338. public class SchoolEconomy {
  339. public string schoolId { get; set; }
  340. public string schoolName { get; set; }
  341. public string areaId { get; set; }
  342. public string areaName { get; set; }
  343. public double total { get; set; }
  344. public long count { get; set; }
  345. public long archive { get; set; }
  346. }
  347. [ProducesDefaultResponseType]
  348. [HttpPost("test-ru")]
  349. public async Task<IActionResult> FixSemester(JsonElement json)
  350. {
  351. await _azureStorage.GetBlobContainerClient("hscjzx").GetBlobClient("yxpt/standard3/jyzx/1639448922/691a16ca-b45a-4426-8e2d-162484af5d1d/B2-曹-微课方案.pdf").SetAccessTierAsync(AccessTier.Archive);
  352. await _azureStorage.GetBlobContainerClient("jlstcz").GetBlobClient("yxpt/standard14/jyzx/1657242924/b5625069-b8b7-431b-ab2a-643d9e2f80be/14岁少年沉迷网络,妈妈苦口婆心不起作用,偷偷躲在角落痛哭! 480P(标清)_format_2 (1).mp4").SetAccessTierAsync(AccessTier.Archive);
  353. //string url1 = HttpUtility.UrlPathEncode("https://teammodeltest.blob.core.chinacloudapi.cn/hscjzx/yxpt/standard3/jyzx/1639448922/691a16ca-b45a-4426-8e2d-162484af5d1d/B2-曹-微课方案.pdf");
  354. //string url2 = HttpUtility.UrlPathEncode("https://teammodeltest.blob.core.chinacloudapi.cn/jlstcz/yxpt/standard14/jyzx/1657242924/b5625069-b8b7-431b-ab2a-643d9e2f80be/14岁少年沉迷网络,妈妈苦口婆心不起作用,偷偷躲在角落痛哭! 480P(标清)_format_2 (1).mp4");
  355. //await _azureStorage.GetBlobServiceClient().GetBlobBatchClient().SetBlobsAccessTierAsync(
  356. // blobUris: new Uri[] { new Uri(url1),
  357. // new Uri(url2) }, accessTier: AccessTier.Archive);
  358. double? Scores = await _azureRedis.GetRedisClient(8).SortedSetScoreAsync($"Blob:Catalog:ssjxx", "yxpt");
  359. //await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "insert", root = "yxpt", name = $"ssjxx" }, _serviceBus, _configuration, _azureRedis);
  360. //await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "insert", root = "train", name = $"ssjxx" }, _serviceBus, _configuration, _azureRedis);
  361. //await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "insert", root = "survey", name = $"ssjxx" }, _serviceBus, _configuration, _azureRedis);
  362. //await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "insert", root = "records", name = $"ssjxx" }, _serviceBus, _configuration, _azureRedis);
  363. //await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "insert", root = "homework", name = $"ssjxx" }, _serviceBus, _configuration, _azureRedis);
  364. //await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "insert", root = "exam", name = $"ssjxx" }, _serviceBus, _configuration, _azureRedis);
  365. string topicName= "dep-active-task";
  366. List< string> msgStrs = new List< string>();
  367. //var client = new ServiceBusAdministrationClient("Endpoint=sb://teammodelos.servicebus.chinacloudapi.cn/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Sy4h4EQ8zP+7w/lOLi1X3tGord/7ShFHimHs1vC50Dc=");
  368. //var subsPages = client.GetSubscriptionsAsync(topicName);
  369. //await foreach (var page in subsPages.AsPages()) {
  370. // var subs= page.Values;
  371. // foreach (var sub in subs) {
  372. // var receiver = _azureService.GetServiceBusClient().CreateReceiver( topicName, sub.SubscriptionName, new ServiceBusReceiverOptions
  373. // {
  374. // ReceiveMode = ServiceBusReceiveMode.PeekLock
  375. // });
  376. // var scheduledMessages = await receiver.PeekMessagesAsync(100);
  377. // foreach (var message in scheduledMessages)
  378. // {
  379. // Console.WriteLine($"Scheduled Message: {message.Body}");
  380. // Console.WriteLine($"Scheduled Enqueue Time: {message.ScheduledEnqueueTime}");
  381. // Console.WriteLine("--------------------");
  382. // }
  383. // await receiver.CloseAsync();
  384. // }
  385. //}
  386. return Ok(msgStrs);
  387. //await _azureStorage.GetBlobContainerClient("0-public").GetBlobClient("winteach.cn_nginx.zip").SetAccessTierAsync(AccessTier.Archive);
  388. //await _azureStorage.GetBlobServiceClient().GetBlobBatchClient().SetBlobsAccessTierAsync(
  389. // blobUris: new Uri[] { new Uri("https://teammodeltest.blob.core.chinacloudapi.cn/0-public/test.md"),
  390. // new Uri("https://teammodeltest.blob.core.chinacloudapi.cn/0-public/pay.html") },accessTier:AccessTier.Archive);
  391. //var cm = _azureRedis.GetConnectionMultiplexer();
  392. //var keys = cm.GetServer(cm.GetEndPoints()[0]).Keys(cm.GetDatabase(8).Database,"Blob:Catalog*");
  393. //List<string> ks = new List<string>();
  394. //foreach (var key in keys)
  395. //{
  396. // ks.Add(key.ToString());
  397. //}
  398. //var result4 = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<ExamInfo>($"select value c from c where c.pk='Exam'and c.owner='teacher'", null, pageSize: 200);
  399. //var result0 = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<ExamInfo>($"select value c from c where c.pk='Exam'and c.owner='teacher' and STARTSWITH(c.code,'Exam-')", null, pageSize: 200);
  400. //var result1 = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<ExamInfo>($"select value c from c where c.pk='Exam' and c.owner='teacher' and contains(c.code,'Exam-')", null, pageSize: 200);
  401. //var result2 = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<ExamInfo>($"select value c from c where c.pk='Exam' and c.owner='school' and contains(c.code,'Exam-hbc')", null, pageSize: 200);
  402. //var result3 = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<ExamInfo>($"select value c from c where c.pk='Exam' and c.owner='school' ", "Exam-hbcn", pageSize: 200);
  403. //return Ok(new { ru4 = result4.ru, count4 = result4.list.Count, ru0 = result0.ru, count0 = result0.list.Count(), ru1 = result1.ru, count1 = result1.list.Count(), ru2 = result2.ru, count2 = result2.list.Count(), ru3 = result3.ru, count3 = result3.list.Count() });
  404. }
  405. /// <summary>
  406. /// 测试五育画像数据推送
  407. /// </summary>
  408. /// <param name="json"></param>
  409. /// <returns></returns>
  410. [ProducesDefaultResponseType]
  411. [HttpPost("period")]
  412. public async Task<IActionResult> period(JsonElement json)
  413. {
  414. List<string> names = new List<string>();
  415. if (json.TryGetProperty("names", out JsonElement _names))
  416. {
  417. names= _names.ToObject<List<string>>();
  418. }
  419. List<Period> periods = new List<Period>();
  420. if (json.TryGetProperty("period", out JsonElement _period))
  421. {
  422. foreach (var name in names) {
  423. Period period = _period.ToObject<Period>();
  424. period.name= name;
  425. period.id= Guid.NewGuid().ToString();
  426. period.semesters.ForEach(z => z.id= Guid.NewGuid().ToString());
  427. period.analysis.type.ForEach(z => z.id= Guid.NewGuid().ToString());
  428. period.subjectCount=0;
  429. periods.Add(period);
  430. }
  431. }
  432. return Ok(periods);
  433. }
  434. /// <summary>
  435. /// 测试五育画像数据推送
  436. /// </summary>
  437. /// <param name="json"></param>
  438. /// <returns></returns>
  439. [ProducesDefaultResponseType]
  440. [HttpPost("import-table")]
  441. public async Task<IActionResult> ImportTable(JsonElement json)
  442. {
  443. List<LPSchool> schools = json.ToObject<List<LPSchool>>();
  444. var table = _azureStorage.GetCloudTableClient().GetTableReference("ScYxpt");
  445. await table.BatchInsertAsync (schools);
  446. return Ok(schools);
  447. }
  448. /// <summary>
  449. /// 测试五育画像数据推送
  450. /// </summary>
  451. /// <param name="json"></param>
  452. /// <returns></returns>
  453. [ProducesDefaultResponseType]
  454. [HttpPost("test-upsert-student-portrait")]
  455. public async Task<IActionResult> TestUpsertStudentPortrait(JsonElement json) {
  456. var data = await _httpTrigger.RequestHttpTrigger(json, _option.Location, "upsert-student-portrait");
  457. return Ok(data.json.ToObject<JsonElement>());
  458. }
  459. /// <summary>
  460. ///
  461. /// </summary>
  462. /// <param name="json"></param>
  463. /// <returns></returns>
  464. [ProducesDefaultResponseType]
  465. [HttpPost("transform-lessonrecord-overalleducation")]
  466. public async Task<IActionResult> TransformLessonrecordOveralleducation(JsonElement json) {
  467. //string msg = json.ToString();
  468. //var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
  469. //var messageChange = new ServiceBusMessage(msg);
  470. //messageChange.ApplicationProperties.Add("name", "LessonRecordEvent");
  471. //await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChange);
  472. string sql = "select value c from c where c.pk='StudentScoreRecord' and c.userType='student' and c.school<>null and c.school<>'' ";
  473. List<StudentScoreRecord> studentScores = new List<StudentScoreRecord>();
  474. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetItemQueryIterator<StudentScoreRecord>(sql)) {
  475. studentScores.Add(item);
  476. }
  477. var group = studentScores.GroupBy(z => z.school);
  478. string schoolSql = $"select value c from c where c.id in ({string.Join(",",group.Select(x=>$"'{x.Key}'"))})";
  479. var resultScool= await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<School>(schoolSql,"Base");
  480. foreach(var item in group)
  481. {
  482. var list = item.ToList();
  483. var stuids = list.Select(z => z.stuid);
  484. string studentSql = $"select value c from c where c.id in ({string.Join(",", stuids.Select(x => $"'{x}'"))})";
  485. var resultStuden = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<Student>(studentSql, $"Base-{item.Key}");
  486. foreach (var sturecord in list) {
  487. HashSet<OverallEducation> overallEducations = new HashSet<OverallEducation>();
  488. var studentBase = resultStuden.list.Find(x => x.id.Equals(sturecord.stuid, StringComparison.OrdinalIgnoreCase));
  489. var schoolBase = resultScool.list.Find(x => x.id.Equals(sturecord.school, StringComparison.OrdinalIgnoreCase));
  490. if (studentBase == null) {
  491. continue;
  492. }
  493. var period = schoolBase.period.Find(x => x.id.Equals($"{studentBase.periodId}"));
  494. foreach (var record in sturecord.lessonRecords) {
  495. if (record.time > 1000000000000) {
  496. (Semester currSemester, int studyYear, DateTimeOffset currSemesterDate, DateTimeOffset date, DateTimeOffset nextSemester) dataSemester = SchoolService.GetSemester(period, record.time);
  497. string oid = $"{dataSemester.studyYear}-{dataSemester.currSemester.id}-{sturecord.stuid}";
  498. string ocode = $"OverallEducation-{sturecord.school}";
  499. OverallEducation overallEducation = overallEducations.Where(o => o.id.Equals(oid, StringComparison.OrdinalIgnoreCase) && o.code.Equals(ocode, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
  500. if (overallEducation != null)
  501. {
  502. var hasrecord = overallEducation.lessonScore.Find(x => x.lessonId.Equals(record.lessonId));
  503. if (hasrecord != null)
  504. {
  505. hasrecord.gscore = record.gscore;
  506. hasrecord.pscore = record.pscore;
  507. hasrecord.tscore = record.tscore;
  508. hasrecord.tmdid = record.tmdid;
  509. hasrecord.school = record.school;
  510. hasrecord.scope = record.scope;
  511. hasrecord.lessonId = record.lessonId;
  512. hasrecord.courseId = record.courseId;
  513. hasrecord.periodId = record.periodId;
  514. hasrecord.subjectId = record.subjectId;
  515. hasrecord.time = record.time;
  516. }
  517. else
  518. {
  519. overallEducation.lessonScore.Add(
  520. new StudentLessonRecord
  521. {
  522. gscore = record.gscore,
  523. pscore = record.pscore,
  524. tscore = record.tscore,
  525. tmdid = record.tmdid,
  526. school = record.school,
  527. scope = record.scope,
  528. lessonId = record.lessonId,
  529. courseId = record.courseId,
  530. periodId = record.periodId,
  531. subjectId = record.subjectId,
  532. time = record.time
  533. }
  534. );
  535. }
  536. }
  537. else {
  538. Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).ReadItemStreamAsync(oid, new PartitionKey(ocode));
  539. if (response.Status != 200)
  540. {
  541. overallEducation = new OverallEducation
  542. {
  543. id = oid,
  544. code = $"OverallEducation-{sturecord.school}",
  545. pk = "OverallEducation",
  546. ttl = -1,
  547. name = studentBase.name,
  548. classId = studentBase?.classId,
  549. schoolCode = $"{sturecord.school}",
  550. semesterId = dataSemester.currSemester.id,
  551. year = dataSemester.studyYear,
  552. periodId = $"{period.id}",
  553. stuYear = studentBase.year,
  554. studentId = studentBase.id,
  555. lessonScore = new List<StudentLessonRecord>
  556. {
  557. new StudentLessonRecord
  558. {
  559. gscore = record.gscore,
  560. pscore = record.pscore,
  561. tscore = record.tscore,
  562. tmdid = record.tmdid,
  563. school = record.school,
  564. scope = record.scope,
  565. lessonId = record.lessonId,
  566. courseId = record.courseId,
  567. periodId = record.periodId,
  568. subjectId = record.subjectId,
  569. time= record.time
  570. }
  571. }
  572. };
  573. }
  574. else
  575. {
  576. overallEducation = JsonDocument.Parse(response.Content).RootElement.ToObject<OverallEducation>();
  577. var hasrecord = overallEducation.lessonScore.Find(x => x.lessonId.Equals(record.lessonId));
  578. if (hasrecord != null)
  579. {
  580. hasrecord.gscore = record.gscore;
  581. hasrecord.pscore = record.pscore;
  582. hasrecord.tscore = record.tscore;
  583. hasrecord.tmdid = record.tmdid;
  584. hasrecord.school = record.school;
  585. hasrecord.scope = record.scope;
  586. hasrecord.lessonId = record.lessonId;
  587. hasrecord.courseId = record.courseId;
  588. hasrecord.periodId = record.periodId;
  589. hasrecord.subjectId = record.subjectId;
  590. hasrecord.time = record.time;
  591. }
  592. else
  593. {
  594. overallEducation.lessonScore.Add(
  595. new StudentLessonRecord
  596. {
  597. gscore = record.gscore,
  598. pscore = record.pscore,
  599. tscore = record.tscore,
  600. tmdid = record.tmdid,
  601. school = record.school,
  602. scope = record.scope,
  603. lessonId = record.lessonId,
  604. courseId = record.courseId,
  605. periodId = record.periodId,
  606. subjectId = record.subjectId,
  607. time = record.time
  608. }
  609. );
  610. }
  611. }
  612. overallEducations.Add(overallEducation);
  613. }
  614. }
  615. }
  616. foreach (var overallEducation in overallEducations) {
  617. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).UpsertItemAsync(overallEducation, partitionKey: new PartitionKey(overallEducation.code));
  618. }
  619. }
  620. }
  621. return Ok();
  622. }
  623. /// <summary>
  624. ///
  625. /// </summary>
  626. /// <param name="json"></param>
  627. /// <returns></returns>
  628. [ProducesDefaultResponseType]
  629. [HttpPost("check-art-result")]
  630. public async Task<IActionResult> CheckArtResult(JsonElement json)
  631. {
  632. List<StudentArtResult> art_idNames = new List<StudentArtResult>();
  633. string sqlSchool = "select value c from c where c.areaId='7a51072f-b329-4e74-99e0-ba0407ba8926'";
  634. List<School> schools = new List<School>();
  635. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
  636. .GetItemQueryIterator<School>(sqlSchool, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base") }))
  637. {
  638. schools.Add(item);
  639. }
  640. string sql = @"SELECT value c FROM c where c.pk='ArtResult' and c.artId in('770fbaaa-a9e8-4d45-a322-3c6d6e50a8f7',
  641. '1e59bb5f-984f-406d-83a2-48ef1ce60a75',
  642. '33fc9276-60c1-4663-8c42-2e44a138a874',
  643. '4eada95b-a408-4a66-bd6c-c61c6057d505',
  644. 'f61b32c6-2f86-4ae6-ac25-1961df0f443a',
  645. '4d974b69-e104-45db-8047-b4cbc43ebc98',
  646. 'efb8f6ed-74b9-43b7-b8e5-c61d92441ed9',
  647. '070d8ce5-253c-404b-80b7-12cbc234ddae',
  648. 'fdd6c34b-44c2-42e9-9cd4-66c01b7103da',
  649. 'b1cf6fed-a4ea-4d06-b15d-3941fba973de',
  650. '67cd2be9-e307-4d35-8249-6d4e7380d15c',
  651. 'f0481d0e-ab74-4117-8600-a375a206e283',
  652. '7a809ab3-4081-4a23-8127-9a362f9af8ff',
  653. '673684e2-1dc3-48d9-a21f-207cc40a68ba',
  654. '35e4da67-0fb9-4683-9fac-9c9b1c197f24',
  655. '893b9871-8518-4f70-97e5-58ceb4c1b504',
  656. '0cd4ea92-4697-468a-a2fd-2f0e1cd53525',
  657. 'd9fec69f-2532-408b-bc25-98a33edf7200',
  658. '02b68eed-29f2-49c1-a91f-c1e35dd8ce64',
  659. 'edaf8c12-9b0b-4b31-baff-3e9b926b401a',
  660. '472bbdc9-c287-4b18-9502-7f34d15172a8',
  661. '41f67e3c-6c7f-46e9-bc39-ec8d6ae9a495',
  662. 'ffea1c6b-3fb7-40d4-921b-e1dc46d15410',
  663. '079fa190-fc18-46b9-bcb9-a4b6e2cd902d',
  664. 'a0e778e8-2590-431e-b761-4929fa143762',
  665. '374a571a-6d5c-4a8a-ab57-6e79b8b8ff0a',
  666. '1db3838e-d7cd-4c77-af70-d3854262d33e',
  667. '7b8a2f53-3b90-48f1-bd0b-bb5be843656a',
  668. 'e5c24756-1ea3-46cf-8f0f-357ec280e42c',
  669. '1b713f31-7e0b-4cb5-84f1-0342db618a6d',
  670. '1794bc46-d0fb-4ea9-8ff8-2f813affe495',
  671. 'b9d54179-7eaf-426b-a44f-9018e6c4ffa7',
  672. '3145e47a-21e5-4cdf-a992-72b9e47c7bad',
  673. 'bdaab0b2-f8d0-4c1b-821c-95b4a2371c42',
  674. 'd39f74df-dc65-44d4-8463-41af1a4b186d',
  675. '79e83de1-4e64-4ef3-b24e-fe4e877e683b',
  676. 'bf3aaff3-1a86-42c8-89d7-4b9d6147d37f',
  677. 'ad3742eb-9e46-43f8-9644-ecb498082810',
  678. '66a3d74b-3946-42c3-a2d2-0bc6704c86ec',
  679. 'ec75e499-f432-41d4-b6dd-5548358b657d',
  680. '70ef5724-f875-4e2e-bda8-58fd2457c2a7',
  681. '60c03852-8c97-4cb0-a232-e0734eaebe96',
  682. '4eefe05d-3df9-4f27-804b-53dd7bc5f4ab',
  683. 'b82ff879-5474-4b31-b3e6-3174361a4fd0',
  684. '09489fef-5490-4b5e-802b-74d1be2c5515',
  685. '1a7d8d51-f828-4f15-9859-33937b41b9e4',
  686. '9e591e75-538e-426d-862d-b043c13e822a',
  687. '71cd894a-e82d-49ff-a204-a64a2eb6f332',
  688. '70103a11-095b-4d01-b3ea-0ed2e388445f',
  689. 'b40d4952-396d-49f3-ba2d-6aeba1d940d9',
  690. '149a12ae-7c5d-444c-ac34-17af88cf653e',
  691. '8c1b2180-4a81-4f6b-989a-b971dbeae082',
  692. '079107f5-7bf5-4955-a39c-85dec9715e60',
  693. 'f9abe967-dbce-46d7-a60f-d9a2e6866ec6',
  694. 'b4684520-cf0c-473c-aa3a-ea5ba5d398d3',
  695. '0839abf0-07e7-4c0d-b818-54d451a6265a',
  696. '6abc82c7-928b-43bf-8c5d-f5a5d7c55a4d',
  697. '544577d3-c4b0-491f-a041-18cc07e711ca',
  698. '2efddd68-0bbc-4dba-a594-f7f8532f519d',
  699. '725f2665-1015-4563-9044-f4061accdf67',
  700. '739aa426-a359-4515-85ef-1efe605c0b73',
  701. '8dcde32c-3a77-4bf5-84a3-ec4d7a78413d',
  702. '4a396e8b-babb-47ee-b6ed-db2124d5c39d',
  703. '55f4594b-c13b-48b8-82f1-563751d48e9e',
  704. '3cc1bd57-bf4e-4933-ac6b-7cdb0e8e2dc1',
  705. '380511bf-2b15-4b90-b8c8-3464c2c6e18c',
  706. '12378c30-0c1d-4c84-8deb-5aaffaa2b45c',
  707. 'e247abc3-7083-4de5-a492-46e09e9bb341',
  708. 'ef826295-7a00-483d-945b-589c8fc0baf9',
  709. 'c1b056c5-0ebf-454a-bb56-3f6024e837d2',
  710. 'c513fe45-767c-4632-b6d3-9631c9bf8854',
  711. '9f7d087e-ba53-4167-9776-1e33a9a1cb61',
  712. 'b5f1a3f0-975f-441c-b6d0-3b8513b96d24',
  713. '92560ac8-a3a5-4aff-85e6-b7f72fc7e2fb',
  714. '898a7705-47f3-4f3b-a01e-1ec609ad4abf',
  715. '4c4349a0-ade4-4793-a435-15de7f3c299e',
  716. '473707f1-6f43-4611-adca-263604aa8e58',
  717. '88ee65ec-ec5c-4c5a-8539-8a8e931508ce',
  718. '4b12c255-5f44-4056-8ab6-d33721394ab2',
  719. '1f2f9ad3-e465-4152-afce-26715e3902af',
  720. 'bba7590c-735a-41c3-a501-ab4285fc36e8',
  721. '51c7426f-934f-4a18-bc1f-053e994969cc',
  722. '9ec15578-a78b-4f9d-ae8c-f15677d03d0a',
  723. '6fc632fe-5833-4c26-a079-70f9a3fa1957',
  724. '86a886f5-e540-4f57-abfd-cee4e3d328ab',
  725. '66e50efa-c3c4-4e3e-8892-5ebdec85a008',
  726. '2b66ee3b-e74a-446a-a92d-9cdc11a43123',
  727. '09533510-ec3a-4c45-8220-097a2a7e4237',
  728. 'be879d1f-1ccd-4e5f-9871-449a736a9279',
  729. '2371ba86-0598-44eb-99de-c73b7cca15db',
  730. '77f87528-e5c0-4ddf-80ea-43d383f5e58e',
  731. '9b7aa0c9-6393-4337-95cd-2bf0c57a662c',
  732. '93811e7f-fa3f-4487-9310-ef28ba3530f4',
  733. '43ecedc4-45fa-4ab7-b87b-357be07b19fa',
  734. 'a7fa4f17-9a9e-4d0b-bca7-2edfdcd75afb',
  735. '3682bc09-96ab-4d17-9010-b9fc31dc72bd',
  736. '04eff65e-3e19-4b57-b3ba-f1f63f52b8ba',
  737. '9eaea71a-97c8-456d-afc4-97d00e2e83bd',
  738. 'e3d846fd-c9e7-44b1-966d-ba74b4953f54',
  739. '2db6561b-3657-418a-ba18-b726a86d1fb1',
  740. '93b32d4b-a918-4940-bcef-00fbeceff525',
  741. '18e6f96a-c4d3-4cca-9248-f7c9099c6706',
  742. '3e1866ed-c9d0-415f-a080-ed1b34704110',
  743. 'd4ee5661-646b-4a58-b2b8-ad309666d64e',
  744. 'b678edb6-4717-423f-a8ac-6abc80eeab97',
  745. 'e8d68e11-d1e9-4bc7-8e22-e426f50f70a2',
  746. '8e96efbd-b990-4e2e-ad43-49e9dae73794',
  747. '72793b29-c939-4201-82b8-7ded1e6c6fe5',
  748. '59b5a6bc-ae2a-4157-b262-bf7a4858aace',
  749. 'e6b642ef-4239-4063-b471-da5b987b6aeb',
  750. 'f5ebf426-b4bc-4744-a2f3-a35a22c6c326',
  751. 'a7e80ecb-2a53-4879-a0f4-d313f78d3c01',
  752. 'cf32535a-b754-4cee-a51d-be4dc2220a2f',
  753. '521c66d6-00cc-4ec6-b391-0d9ce1995c42',
  754. '523b17d0-629f-44de-8f24-0c3915493fb0',
  755. '771b45c4-dde0-4d6a-ba69-6d8f537e4c1f',
  756. 'f9b374fd-1af4-4623-b117-c75fa4e7f4f8',
  757. '479f343e-51b7-49bd-8ebb-cb81af8ae7b0',
  758. 'cc992aae-2942-4836-9351-cedbd1cc4e61',
  759. '3f5d1192-4c56-43a6-9140-18043d6c41e5',
  760. 'dffad9b6-f3f2-4470-be45-94c81af04a02',
  761. '39289aa9-2506-4d04-866e-e6eec9b4d9db',
  762. '243299ec-6a98-43ac-b3db-272f5abbbd78',
  763. '9f715766-ef6a-479d-895d-945952a8ff6e',
  764. '2ff9bd86-8621-4f04-b560-abff5a202232',
  765. '75da24ed-8196-4eb1-8413-3916d7b271a3',
  766. '6adc96f3-c6e5-4a8d-a33f-5bbcbb92b296',
  767. '0b2dcfbc-d334-4032-b354-f6fa98a57d99',
  768. 'e2110a26-3af6-4c53-8b38-51ed4b415d48',
  769. '85e4c259-f531-43dd-a2b8-76cb750f8604',
  770. '1a6731a3-cc57-4463-84e1-bca0917c2399',
  771. 'd574dac8-4440-48f0-af37-b982db545ea3',
  772. '753ca661-d930-4f33-bce3-5385c310744f',
  773. 'e70800f3-836b-43e9-aa8c-c5e789d7054e',
  774. '32a94a0c-c14c-4208-8bd1-0d84c69d690e',
  775. 'f5d242b3-db25-4877-8a63-4d4dcf8f8f2c',
  776. '87399fcb-34fb-494b-b74f-02979a665dc0',
  777. '85796371-1079-4fff-947d-671720377e72',
  778. '40f04a01-e373-430a-a1f5-cbb8fbcff4cb',
  779. '6e6a3d09-c65d-4996-bd96-035f5d19e634',
  780. 'd340ea8f-e869-46d5-8813-5cce7991edea',
  781. '8a72592b-09fb-4910-b4e9-c76ef039b44f',
  782. '740b8b24-c7f5-4df5-a13a-92a1c37619bc',
  783. 'c19ef79f-d3f3-4125-8e1a-83cee110e03b',
  784. '1894992c-2575-4949-971d-c84669fcfd06',
  785. '4d51ace2-9f18-4f01-be7b-1ab4694e62dd',
  786. 'c1564967-890f-49e2-983a-933df4cbf8d0',
  787. 'aff088da-91e6-400a-ab84-c6cf300b361f',
  788. 'b0557e5e-41c5-4273-b793-dcb8a0613e6f',
  789. 'd0317e30-bcc4-4b03-9417-4dba3a216105',
  790. '86a28ef8-f3fc-44ef-942b-a9a658bb0731',
  791. '53623415-70e8-44f6-9ea6-bd709e40984c',
  792. '9ee23eee-850c-4cb0-8147-829ae0502705',
  793. 'd6fbfc1e-6093-4e70-8432-453246c80eb3',
  794. 'ac0e96dd-ec15-4b39-834d-1000ac3aa4c4',
  795. '1e8c9744-8054-405b-997c-de13e58967a4',
  796. 'c87c282c-6a83-40d1-86bc-af3045c0c41a',
  797. '4c221226-f490-4657-bd98-cf24bba48d7e',
  798. 'fd218bdd-7c18-41d6-a592-59a4c3ee98fe',
  799. '0c916db0-f7fa-4abc-a548-ca81cb416e59',
  800. '9f3c9615-3066-45d8-99a9-eacc8f6d692d',
  801. '6ed5074e-c7df-49f1-84c8-bb6276db9d1d',
  802. 'c2eb2c78-60d3-4616-9215-5ca810c58e4d',
  803. '4aef197d-5c62-4bce-aab2-804c87db5b28',
  804. '3231a06f-118a-437f-b863-4ffcba56d03a',
  805. 'a827a795-f86e-46eb-8369-f63b061d87d9',
  806. 'd4fd8c14-81d1-41b3-b652-f1dfb107d0d6',
  807. 'a0f2b207-0ef7-4ca4-b595-12f46b4b8434',
  808. '115f8e21-ebdb-4241-9c34-91fbef1b6fb9',
  809. '34c8923a-0230-448a-9d06-a8f2922520a3',
  810. '04803687-4689-45a6-b19e-4d3a39ccc348',
  811. '8bb657c9-7638-4ab9-af92-a4370d53960e',
  812. '1e766445-9971-4358-86be-fba295460866',
  813. '367c0575-b150-44eb-b447-5468d4d833fe',
  814. '2a379010-1f57-43f7-8f99-1f254ad93c26',
  815. '496adcc6-2897-4f16-9e9b-75fbcfd313a0',
  816. 'c32a4e86-637f-4c68-8824-2d4370eea5ee',
  817. 'b03b9f85-6d51-4c9c-a354-22bd3aa67462',
  818. '829a1242-f1e0-4154-aacf-362c021172f2',
  819. '4a451d51-b96c-4740-9018-7d22bbd842cf',
  820. '497a3b9a-55da-4991-af53-657c04edd0b3',
  821. 'b89b915f-f4ea-44f6-ae3a-e45af1942022',
  822. '781c4777-a869-4857-b052-71cbecbf6e35',
  823. '16a1d9aa-4bba-4c6f-86e5-7f7a281e7cd2',
  824. 'a5125445-cd2c-44b1-af19-addd25b8eeef',
  825. '81f574b9-9da2-43ae-ac6c-54ceb637c1fa',
  826. '1d469b5a-386c-4ace-9477-826c2d9d2b5d',
  827. '4fb0c252-5df1-44f9-a6e4-40078740a4e8',
  828. '1d7574e8-cf7c-460f-aad9-b4eec908121c',
  829. 'b0d23d24-a66f-4fb7-badc-980bebe0118d',
  830. 'e9570402-e4db-4a7c-9d5c-c5f95ad8ed0a',
  831. 'b08a57bc-6f1a-491c-a126-490ad5c8f90c',
  832. '583f3908-5caf-4703-84c6-e32cbbafca1e',
  833. '271cf872-cc61-493d-a595-be644bb2e098',
  834. 'a031cf56-0aa1-40c1-a325-14f6f1204cad',
  835. '3f492d1f-d95d-4947-8944-1e47fbe6abb4',
  836. '44d282b7-413f-4f1a-b5cf-5b9b81acbb6a',
  837. 'cef3a415-dc3f-4143-b905-5b1bac1b10c9',
  838. '37fe497b-1ba6-46e7-a9b9-fd70993b9753',
  839. 'c0db0c30-590c-42bd-bac7-d065a05843cd',
  840. '19532426-9ee6-4cc0-8d7b-7c5753b95b64',
  841. '7421dcb4-14d3-4656-9257-a2b287ff41a8',
  842. 'bd5805f7-a7eb-4189-8e48-9b3978d22362',
  843. '012861ec-8bbb-42e2-9e39-349a5b172c21',
  844. '731daff9-ccf2-48d3-88bc-ff02ec7ff2f9',
  845. '5b47d6c3-df81-4456-a165-4af6ee34c375',
  846. '2129126a-838f-4e3d-a8a4-1bf9e8d70ce8',
  847. 'acb84287-1cf7-4aa5-8892-e92beb6f6871',
  848. 'b2d337e4-16b4-459d-9d7f-922458e2671c',
  849. 'c63b9cd7-bce4-4c80-91c2-c305916d3d22',
  850. '1a7d052b-97b6-40ab-9b45-3e163710ea10',
  851. 'bd096e5e-0dc3-4b2e-9e4a-ffc3ac2a8e8b',
  852. '1afbab3e-193c-408c-b024-3365730d1698',
  853. '6e268ebe-aa65-4fa0-8fc1-877d0688cf8d',
  854. '89675ae3-9773-4b37-bc69-6a926f608b0e',
  855. 'd96a0716-89e1-4b5b-b02a-0cb438bd4933',
  856. '693e024a-1b71-4c9e-868e-ad9524728988',
  857. '5fb1ad4b-7a79-4a55-b627-3d1354a22754',
  858. 'c050b6d6-5f1a-4f3f-9385-521d9f992f11',
  859. '62051b3d-1a64-4509-914c-a382f573c050',
  860. '8b6c6a22-3a4c-48f4-bba4-57db1af2ec2e',
  861. 'ca5d3896-35ad-4848-ad2a-beb04263999d',
  862. '1bac6904-2f36-45f5-9e8e-894e28a5674d',
  863. '89f1a5f6-3c29-4338-8a00-5645dbaa80ad',
  864. 'def9d072-fee5-44f6-bc18-5b2750d4efc5',
  865. '032e2e84-6154-49ee-8d4d-e3b3b631595b',
  866. '6cb4e7ba-9be8-4c8a-bf4a-437faf96c084',
  867. 'd6df2ed5-8963-42c0-8832-537a210e900e',
  868. 'ec647fea-a650-4b18-b267-3f8d9d104c23',
  869. '10374436-b76b-4d73-853e-abe12b8f0079',
  870. '8b87190e-3fd1-40d3-9a7f-efb986cd7fa5',
  871. '30803959-1b88-4b8a-8716-d74e58f2eacd',
  872. 'b7c69c8d-b4c0-4523-ac73-f9629d2b5c37',
  873. 'da21dd7d-fe43-474f-bcd0-e2819b71ab40',
  874. 'ae97438f-afc8-4f01-90da-da5fbbc7b759',
  875. '95920cea-040e-40a0-a9fa-ea7e48945e5e',
  876. 'bf0ec2c2-b1b5-41a4-990b-ebd32e64bcc5',
  877. '06add3e9-8566-44b0-8962-6f1377410b48',
  878. '1a56021a-b4e5-45e0-83e5-7ec707097271',
  879. 'd35c54ea-3985-484f-9a3a-abc4be8fc774',
  880. 'a7c3bd26-ac43-4a61-99fe-428ea141a826',
  881. '414a46cb-4e88-4217-adfd-395f3f4cb12c',
  882. '241729ee-cfe7-4ee2-868e-3f617fd62bba',
  883. 'c05c28db-8b03-4d0c-8a37-c0e36c6fd0e8',
  884. '5b72fe37-3bc6-4563-9a1e-bfd62b692980',
  885. '73609b0e-1bc7-4c64-a39e-df52a34a5325',
  886. '477bba0c-d64f-4543-90eb-481183874bf8',
  887. 'd2d5be63-6e49-46d5-ae96-3b106b907902',
  888. '9091e31c-28c6-4a31-9958-36d0875ef8d7',
  889. '4fedd41a-d3d2-475d-8804-8c716ac4e160',
  890. '5d322e5c-ad86-42b2-a20d-1fa0e3279361',
  891. '99297e99-3b10-4353-a691-02492f2b88d1',
  892. '5b1206de-1b99-4b96-8e98-5c85ca630cea',
  893. '65d501e8-4663-4ae8-a07e-59b30b75a645',
  894. 'b53311e3-5276-45d6-87a1-36bf28b653be',
  895. '6bd75463-1dec-4001-ab24-cd2e07986759',
  896. '9b3201a9-ce44-41a7-8ad5-6769f726c2d0',
  897. '0acf8a5d-0feb-4497-9a0a-e95f86138157',
  898. '522597e8-bada-4c5b-bdf2-06af764a4bfe',
  899. '1fca91fb-3e03-438e-8f1b-a9b77b14634c',
  900. 'c8bd6ef8-ff2e-40c5-8f15-973caea0ed58',
  901. 'ba318882-7eeb-42a0-bfcb-09ac71fc0046',
  902. '0e1d09bd-f176-4e21-9f55-b821703a7b24',
  903. '3f58f289-a206-4fbd-93c6-0752d3d0a250',
  904. 'fd23121d-959d-443c-ac22-4cf7cac3751c',
  905. 'd3b4384a-290e-4cb0-bfda-b34097d5ca72',
  906. '2d7b5467-0e74-40ae-ab21-bf29ee3fe02c',
  907. 'd3db6faa-4b07-460a-bcbd-48dcc109fbc4',
  908. 'e5d14fe7-a5a0-4610-b1b7-87c9d936c7ff',
  909. 'f386b6f5-1fd2-4a2e-8ec0-6762ddd5c477',
  910. '60c09883-dff1-49ee-bafb-1991aab238aa',
  911. '6664e420-91ad-4c89-9955-313b163f722e',
  912. 'b81724c3-c045-436b-9d55-f528918de742',
  913. '5de09e10-e4bd-4df2-8628-9e432b17ec65',
  914. 'af93606e-5dbc-4401-99e6-adea66903418',
  915. 'fe7998e5-0a31-45a8-aab0-1867092d855c',
  916. 'd64bdffe-8388-4a9c-a3f9-bbd1b75ea224',
  917. 'c8845227-73ea-45fe-920c-be3e166b04c3',
  918. '6087c06a-10fc-4c92-adb3-95f85423fe2e',
  919. '6c64f697-21cf-4d58-8810-d0306e0c5dc4',
  920. 'bc2ee64e-cb01-4101-9d2d-fd37f31fd881',
  921. 'c076b996-1f81-4f4a-8c04-a1a69348863f',
  922. 'f2fab9c5-2a57-4f0a-8b48-000fc08eec98',
  923. 'b496b620-713e-4312-8d80-4f89d10187de',
  924. '6995deff-b9e8-479b-84fc-d981efab4d3b',
  925. 'cd7e8c81-231f-42ab-a30d-7665e9097a71',
  926. '38452e41-1ec3-40ca-ac3a-2579e47e5f16',
  927. '16e904e2-b77b-4723-86ee-ba85a9d3762f',
  928. '9e5e308a-c291-4feb-a225-336f0f949489',
  929. '8391694a-dccb-48eb-8d3b-56401e5fb030',
  930. 'f210dd0a-e288-477a-9a16-d622cc92a818',
  931. '17908451-473c-4fd8-848c-23ef7846fa43',
  932. 'cea1ec2e-02e6-4777-b931-b2042b3f1230',
  933. '70fd95b8-be8c-4545-a46f-6c050449a822',
  934. '057d4f31-3338-4d7b-869c-98fcb114153d',
  935. '8d032ab5-c7db-4ceb-9a37-f55f8a59416c',
  936. '5e8a8ffe-73ac-4a29-9bcc-a03c06b25b2e',
  937. '55fd11e2-047f-4acf-9533-22023684dd58',
  938. '45a4b0c1-dbbf-423e-b287-d44c71089f69',
  939. 'c52cd0d3-4385-4efb-8f33-f947564a70cb',
  940. '07d593c2-9ad7-4ae5-b471-b3e2622c940b',
  941. 'adf77ae2-63f7-4732-82d0-29d434f83445',
  942. 'bdee46ba-fab6-485d-ad89-fda5578859cc',
  943. 'f8b9bccc-1c4f-433d-9917-f4ad007f7105',
  944. '7d2bd01e-5435-4dbd-8e9b-897e777691f6',
  945. '56cacfd9-aeef-4477-abb9-2a22e0a92ae7',
  946. '891c7363-60c7-4aa5-846e-e7e3913e37d4',
  947. '376c26d3-8ebc-4c10-a5c1-aef9606318a8',
  948. '3efc8c68-3cee-4bc6-bdcd-ffc4c1a3437b',
  949. '1a7e5fda-eb4c-4f62-ad2d-b3e04e0e725a',
  950. 'dd4b0cd7-73d4-46fa-bf19-12e35f64be43',
  951. 'ccf206a1-fcc8-4552-b12f-ebed670cff73',
  952. 'c275d71f-cdb3-443c-82ab-821dd80500ea',
  953. 'e269c78b-2b0c-4fd1-bc0f-2ff671151030',
  954. '41e4371e-7495-4008-9951-7b3ab843429e',
  955. 'c54ac4b5-9267-4087-b724-6b0d44713162',
  956. 'e43fb790-aa3f-4209-838d-d830a9c5fd53',
  957. '982f3d88-bfe1-46c8-ac95-7adbd06a98f1',
  958. '8ded07a1-1dda-4dea-8e0d-05475693642c',
  959. 'edb7d6b2-4d86-486f-b4b6-bac71fe6c460',
  960. 'c3416899-550b-4e1a-93f5-690dcf67cd6b',
  961. '89a915cf-aee4-4472-91e6-7f33d5ef490b',
  962. 'c3587e4c-020a-4bef-8ad5-bcbb9a7ea485',
  963. '91e8d5b4-8b73-470b-b900-7cd8f5508e82'
  964. )";
  965. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetItemQueryIterator<StudentArtResult>(sql))
  966. {
  967. art_idNames.Add(item);
  968. }
  969. List<dynamic> unfinish = new List<dynamic>();
  970. ConcurrentDictionary<string, int> schoolFinish = new ConcurrentDictionary<string, int>();
  971. ConcurrentDictionary<string, int> schoolUnFinish = new ConcurrentDictionary<string, int>();
  972. List<Class> classes = new List<Class>();
  973. foreach (var z in art_idNames)
  974. {
  975. var data = z.results.Where(x => (x.subjectId.Equals("subject_painting") && x.quotaId.Equals("quota_21") && x.score == -1)
  976. || (x.subjectId.Equals("subject_music") && x.quotaId.Equals("quota_21") && x.score == -1)
  977. || (x.subjectId.Equals("subject_music") && x.quotaId.Equals("quota_22") && x.score == -1)
  978. || (x.subjectId.Equals("subject_painting") && x.quotaId.Equals("quota_22") && x.files.IsEmpty())
  979. );
  980. if (data.Any())
  981. {
  982. var p21 = z.results.FindAll(x => x.subjectId.Equals("subject_painting") && x.quotaId.Equals("quota_21"))?.First();
  983. var p22 = z.results.FindAll(x => x.subjectId.Equals("subject_painting") && x.quotaId.Equals("quota_22"))?.First();
  984. int p22source = 0, p21source = 0, m21source = 0, m22source = 0;
  985. if (p21.score > -1)
  986. {
  987. p21source = 1;
  988. }
  989. if (p22.files.IsNotEmpty())
  990. {
  991. p22source = p22.files.Count;
  992. }
  993. var m21 = z.results.FindAll(x => x.subjectId.Equals("subject_music") && x.quotaId.Equals("quota_21"))?.First();
  994. if (m21.score > -1)
  995. {
  996. m21source = 1;
  997. }
  998. var m22 = z.results.FindAll(x => x.subjectId.Equals("subject_music") && x.quotaId.Equals("quota_22"))?.First();
  999. if (m22.score > -1)
  1000. {
  1001. m22source = 1;
  1002. }
  1003. string className = "";
  1004. string periodName = "";
  1005. string schoolName = "";
  1006. School school = schools.Find(a => a.id.Equals(z.school));
  1007. schoolName = school?.name;
  1008. if (!string.IsNullOrWhiteSpace(z.classIds?.First()))
  1009. {
  1010. var clasz = classes.Find(x => x.id.Equals(z.classIds?.First()));
  1011. if (clasz == null)
  1012. {
  1013. clasz = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<Class>(z.classIds.First(), new PartitionKey($"Class-{z.school}"));
  1014. classes.Add(clasz);
  1015. }
  1016. className = clasz?.name;
  1017. var period = school?.period?.Where(m => m.id.Equals(clasz.periodId));
  1018. if (period.Any())
  1019. {
  1020. periodName = period.First().name + "-" + period.First().periodType;
  1021. }
  1022. }
  1023. unfinish.Add(new { z.school, schoolName = schoolName, z.studentId, z.studentName, z.artId, periodName, classname = className, p21source, p22source, m21source, m22source, taskId = m22?.taskId });
  1024. if (schoolUnFinish.ContainsKey(schoolName))
  1025. {
  1026. schoolUnFinish[schoolName]++;
  1027. }
  1028. else { schoolUnFinish.TryAdd(schoolName, 1); }
  1029. }
  1030. else
  1031. {
  1032. School school = schools.Find(a => a.id.Equals(z.school));
  1033. string schoolName = school?.name;
  1034. if (schoolFinish.ContainsKey(schoolName))
  1035. {
  1036. schoolFinish[schoolName]++;
  1037. }
  1038. else { schoolFinish.TryAdd(schoolName, 1); }
  1039. }
  1040. }
  1041. return Ok(new { unfinish, schoolFinish , schoolUnFinish });
  1042. }
  1043. [ProducesDefaultResponseType]
  1044. [HttpPost("check-ems")]
  1045. public async Task<IActionResult> CheckPjx(JsonElement json)
  1046. {
  1047. var table = _azureStorage.GetCloudTableClient().GetTableReference("ScYxpt");
  1048. int itemId = 0;
  1049. if (json.TryGetProperty("itemId", out JsonElement _itemId)) {
  1050. itemId= _itemId.GetInt32();
  1051. }
  1052. List< ScTeacher > teachers = await table.FindListByDict<ScTeacher>(new Dictionary<string, object>() { { "PartitionKey", "ScTeacher" }, { "ProjectItemID", itemId } });
  1053. List<dynamic> unbind = new List<dynamic>();
  1054. List<dynamic> unupload_rzcl = new List<dynamic>();
  1055. List<dynamic> uploads_rzcl = new List<dynamic>();
  1056. List<dynamic> unupload_video = new List<dynamic>();
  1057. List<dynamic> uploads_video = new List<dynamic>();
  1058. foreach (var teacher in teachers)
  1059. {
  1060. if (!string.IsNullOrWhiteSpace(teacher.schoolCode) && !string.IsNullOrWhiteSpace(teacher.tmdid))
  1061. {
  1062. int upcont = 0;
  1063. string sql = "select value c from c where c.currency=1";
  1064. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
  1065. .GetItemQueryIterator<AbilitySub>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"AbilitySub-{teacher.schoolCode}-{teacher.tmdid}") }))
  1066. {
  1067. if (item.uploads.IsNotEmpty())
  1068. {
  1069. upcont++;
  1070. uploads_rzcl.Add(new { teacher.TeacherName,teacher.SchoolName,teacher.PXID,time= DateTimeOffset.FromUnixTimeMilliseconds(item.uploads.OrderByDescending(m => m.time).FirstOrDefault().time).ToString("yyyy-MM-dd HH:mm:ss"), teacher?.tmdid });
  1071. }
  1072. }
  1073. if(upcont<3)
  1074. {
  1075. unupload_rzcl.Add(new { teacher.TeacherName, teacher.SchoolName, teacher.PXID ,teacher?.tmdid});
  1076. }
  1077. string sql_video =$"select value c from c where c.id='{teacher.tmdid}'";
  1078. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
  1079. .GetItemQueryIterator<ClassVideo>(queryText: sql_video, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"ClassVideo-{teacher.schoolCode}") }))
  1080. {
  1081. if (item.files.IsNotEmpty())
  1082. {
  1083. uploads_video.Add(new { teacher.TeacherName, teacher.SchoolName, teacher.PXID, time = DateTimeOffset.FromUnixTimeMilliseconds(item.files.OrderByDescending(m => m.time).FirstOrDefault().time).ToString("yyyy-MM-dd HH:mm:ss"), teacher?.tmdid });
  1084. }
  1085. else
  1086. {
  1087. unupload_video.Add(new { teacher.TeacherName, teacher.SchoolName, teacher.PXID, teacher?.tmdid });
  1088. }
  1089. }
  1090. }
  1091. else {
  1092. unbind.Add(new { teacher.TeacherName,teacher.SchoolName,teacher.PXID});
  1093. }
  1094. }
  1095. Dictionary<string, object> dict = new Dictionary<string, object>();
  1096. var tchs= teachers.GroupBy(z => z.areaId).Select(b => new { areaId = b.Key, schools = b.Select(v=>v.schoolCode).ToHashSet(), pushTeachers = b.Where(c=>!string.IsNullOrWhiteSpace(c.tmdid)).Select(d=>d.tmdid)});
  1097. return Ok(new { unbind , unupload_rzcl, uploads_rzcl, uploads_video, unupload_video , tchs });
  1098. }
  1099. [ProducesDefaultResponseType]
  1100. [HttpPost("sendmsg")]
  1101. public async Task<IActionResult> Sendmsg(JsonElement json)
  1102. {
  1103. byte[] bytes = Encoding.UTF8.GetBytes(json.GetRawText());
  1104. var memoryStream = new MemoryStream(bytes);
  1105. Azure.Response res = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).CreateItemStreamAsync(memoryStream, new PartitionKey("Base12"));
  1106. if (res.Status == 201)
  1107. {
  1108. return Ok(201);
  1109. }
  1110. //var messageBlobPDF = new ServiceBusMessage(new { userType = "tmdid", bizType = "OfflineRecord" }.ToJsonString());
  1111. //await _serviceBus.GetServiceBusClient().SendMessageAsync("screenpdf", messageBlobPDF);
  1112. return Ok();
  1113. }
  1114. [ProducesDefaultResponseType]
  1115. [HttpPost("get-subTime")]
  1116. public async Task<IActionResult> GetSubTime(JsonElement request) {
  1117. if (!request.TryGetProperty("ids", out JsonElement id)) return BadRequest();
  1118. List<string> ids = id.ToObject<List<string>>();
  1119. var queryClass = $"select c.time from c ";
  1120. var client = _azureCosmos.GetCosmosClient();
  1121. List<(string td, long tt)> ht = new();
  1122. foreach (string tmdId in ids) {
  1123. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIterator(queryText: queryClass,
  1124. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"HomeworkRecord-{tmdId}") }))
  1125. {
  1126. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  1127. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  1128. {
  1129. var accounts = json.RootElement.GetProperty("Documents").EnumerateArray();
  1130. while (accounts.MoveNext())
  1131. {
  1132. JsonElement account = accounts.Current;
  1133. account.TryGetProperty("time", out JsonElement time);
  1134. ht.Add((tmdId,time.GetInt64()));
  1135. }
  1136. }
  1137. }
  1138. }
  1139. var home = ht.Select(x => new
  1140. {
  1141. id = x.td,
  1142. time = DateTimeOffset.FromUnixTimeMilliseconds(x.tt).ToString("yyyy-MM-dd HH:mm")
  1143. //time = DateTimeHelper.FromUnixTimestampOffSet(x.tt,8).ToString("yyyy-MM-dd HH:mm")
  1144. });
  1145. return Ok(home);
  1146. }
  1147. [ProducesDefaultResponseType]
  1148. [HttpPost("get-semester")]
  1149. public async Task<IActionResult> GetSemester(JsonElement json)
  1150. {
  1151. List<Semester> semesterList = new List<Semester>();
  1152. semesterList.Add(
  1153. new Semester
  1154. {
  1155. id = Guid.NewGuid().ToString(),
  1156. name = "第二学期",
  1157. start = 0,
  1158. month = 3,
  1159. day = 1
  1160. });
  1161. semesterList.Add(
  1162. new Semester
  1163. {
  1164. id = Guid.NewGuid().ToString(),
  1165. name = "第一学期",
  1166. start = 1,
  1167. month = 9,
  1168. day = 1
  1169. });
  1170. //semesterList.Add(
  1171. // new Semester
  1172. // {
  1173. // id = "q",
  1174. // name = "第四学期",
  1175. // start = 0,
  1176. // month = 7,
  1177. // day = 1
  1178. // });
  1179. //semesterList.Add(
  1180. // new Semester
  1181. // {
  1182. // id = "q",
  1183. // name = "第三学期",
  1184. // start = 0,
  1185. // month = 4,
  1186. // day = 1
  1187. // });
  1188. semesterList = SortSemester(semesterList);
  1189. return Ok(semesterList);
  1190. }
  1191. private List<Semester> SortSemester(List<Semester> semesterList)
  1192. {
  1193. int Year = DateTimeOffset.UtcNow.Year;
  1194. List<KeyValuePair<int, Semester>> pairs = new List<KeyValuePair<int, Semester>>();
  1195. semesterList.ForEach(se => {
  1196. string sm = se.month >= 10 ? $"{se.month}" : $"0{se.month}";
  1197. string sd = se.day >= 10 ? $"{se.day}" : $"0{se.day}";
  1198. int order = int.Parse($"{Year}{sm}{sd}");
  1199. pairs.Add(new KeyValuePair<int, Semester>(order, se));
  1200. });
  1201. var orderPairs = pairs.OrderBy(z => z.Key);
  1202. semesterList = orderPairs.Select(z => z.Value).ToList();
  1203. int startIndex = semesterList.FindIndex(z => z.start == 1);
  1204. if (startIndex == -1)
  1205. {
  1206. //未设置学期的情况默认9月份开始的。
  1207. startIndex = semesterList.FindIndex(z => z.month == 9);
  1208. //如果还未找到,就以排序结果为准
  1209. if (startIndex == -1)
  1210. {
  1211. startIndex = 0;
  1212. }
  1213. }
  1214. if (startIndex > 0)
  1215. {
  1216. List<Semester> before = semesterList.Take(startIndex).ToList();
  1217. List<Semester> after = semesterList.Skip(startIndex).ToList();
  1218. semesterList = new List<Semester>();
  1219. semesterList.AddRange(after);
  1220. semesterList.AddRange(before);
  1221. return semesterList;
  1222. }
  1223. else
  1224. {
  1225. return semesterList;
  1226. }
  1227. }
  1228. /*
  1229. [
  1230. {"method":"台北市","params":{"CountryId":"TW","CityId":"30"}},1
  1231. {"method":"新北市","params":{"CountryId":"TW","CityId":"01"}},1
  1232. {"method":"桃园市","params":{"CountryId":"TW","CityId":"03"}},1
  1233. {"method":"台中市","params":{"CountryId":"TW","CityId":"66"}},1
  1234. {"method":"台南市","params":{"CountryId":"TW","CityId":"67"}},1
  1235. {"method":"高雄市","params":{"CountryId":"TW","CityId":"64"}},1
  1236. {"method":"基隆市","params":{"CountryId":"TW","CityId":"17"}},1
  1237. {"method":"新竹市","params":{"CountryId":"TW","CityId":"18"}},1
  1238. {"method":"嘉义市","params":{"CountryId":"TW","CityId":"20"}},1
  1239. {"method":"新竹县","params":{"CountryId":"TW","CityId":"04"}},1
  1240. {"method":"苗栗县","params":{"CountryId":"TW","CityId":"05"}},1
  1241. {"method":"彰化县","params":{"CountryId":"TW","CityId":"07"}},1
  1242. {"method":"南投县","params":{"CountryId":"TW","CityId":"08"}},1
  1243. {"method":"云林县","params":{"CountryId":"TW","CityId":"09"}},1
  1244. {"method":"嘉义县","params":{"CountryId":"TW","CityId":"10"}},1
  1245. {"method":"屏东县","params":{"CountryId":"TW","CityId":"13"}},1
  1246. {"method":"宜兰县","params":{"CountryId":"TW","CityId":"02"}},1
  1247. {"method":"花莲县","params":{"CountryId":"TW","CityId":"15"}},1
  1248. {"method":"台东县","params":{"CountryId":"TW","CityId":"14"}},1
  1249. {"method":"澎湖县","params":{"CountryId":"TW","CityId":"16"}},1
  1250. {"method":"金门县","params":{"CountryId":"TW","CityId":"71"}},
  1251. {"method":"连江县","params":{"CountryId":"TW","CityId":"72"}}
  1252. ]
  1253. */
  1254. /// <summary>
  1255. /// 测试blob多线程写入同一个文件
  1256. /// </summary>
  1257. /// <returns></returns>
  1258. [ProducesDefaultResponseType]
  1259. [HttpPost("get-schools")]
  1260. public async Task<IActionResult> GetSchools(JsonElement json)
  1261. {
  1262. string msg = "{\"standard\":\"standard3\",\"tmdids\":[\"1635136038\"],\"school\":\"pbjyey\",\"update\":[\"TeacherAbility\"],\"statistics\":0}";
  1263. try
  1264. {
  1265. TeacherTrainChange change = msg.ToObject<TeacherTrainChange>();
  1266. var client = _azureCosmos.GetCosmosClient();
  1267. string insql = $"where c.id in ({string.Join(",", change.tmdids.Select(x => $"'{x}'"))})";
  1268. string selsql = $"select value(c) from c {insql} ";
  1269. List<TeacherTrain> teacherTrains = new List<TeacherTrain>();
  1270. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<TeacherTrain>(queryText: selsql,
  1271. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"TeacherTrain-{change.school}") }))
  1272. {
  1273. teacherTrains.Add(item);
  1274. }
  1275. if (change.statistics != 1)
  1276. {
  1277. List<Task<ItemResponse<TeacherTrain>>> task = new List<Task<ItemResponse<TeacherTrain>>>();
  1278. teacherTrains.ForEach(x =>
  1279. {
  1280. x.update.UnionWith(change.update);
  1281. task.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<TeacherTrain>(x, x.id, new PartitionKey($"TeacherTrain-{change.school}")));
  1282. });
  1283. await task.TaskPage(5);
  1284. var unchange = change.tmdids.Except(teacherTrains.Select(x => x.id));
  1285. if (unchange != null)
  1286. {
  1287. task.Clear();
  1288. unchange.ToList().ForEach(x =>
  1289. {
  1290. TeacherTrain teacherTrain = new TeacherTrain
  1291. {
  1292. pk = "TeacherTrain",
  1293. id = x,
  1294. code = $"TeacherTrain-{change.school}",
  1295. tmdid = x,
  1296. school = change.school,
  1297. update = new HashSet<string> { StatisticsService.TeacherAbility,
  1298. StatisticsService.TeacherClass, StatisticsService.OfflineRecord }
  1299. };
  1300. teacherTrain.update.UnionWith(change.update);
  1301. task.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync<TeacherTrain>(teacherTrain, new PartitionKey($"TeacherTrain-{change.school}")));
  1302. });
  1303. await task.TaskPage(1);
  1304. }
  1305. }
  1306. else
  1307. {
  1308. Area area = null;
  1309. string sql = $"select value(c) from c where c.standard='{change.standard}'";
  1310. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Area>(queryText: sql,
  1311. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-Area") }))
  1312. {
  1313. area = item;
  1314. }
  1315. AreaSetting setting = null;
  1316. if (area != null)
  1317. {
  1318. try
  1319. {
  1320. //优先找校级
  1321. setting = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<AreaSetting>(change.school, new PartitionKey("AreaSetting"));
  1322. }
  1323. catch (CosmosException)
  1324. {
  1325. try
  1326. {
  1327. setting = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<AreaSetting>(area.id, new PartitionKey("AreaSetting"));
  1328. }
  1329. catch (CosmosException)
  1330. {
  1331. setting = null;
  1332. }
  1333. }
  1334. }
  1335. if (setting == null)
  1336. {
  1337. setting = new AreaSetting
  1338. {
  1339. allTime = 50,
  1340. classTime = 5,
  1341. submitTime = 15,
  1342. onlineTime = 20,
  1343. offlineTime = 10,
  1344. lessonMinutes = 45,
  1345. };
  1346. }
  1347. List<Task<TeacherTrain>> task = new List<Task<TeacherTrain>>();
  1348. teacherTrains.ForEach(x =>
  1349. {
  1350. x.update.UnionWith(change.update);
  1351. task.Add(StatisticsService.StatisticsTeacher(x, setting, area, client, null));
  1352. });
  1353. await task.TaskPage(1);
  1354. var unchange = change.tmdids.Except(teacherTrains.Select(x => x.id));
  1355. if (unchange != null)
  1356. {
  1357. task.Clear();
  1358. unchange.ToList().ForEach(x =>
  1359. {
  1360. task.Add(StatisticsService.StatisticsTeacher(new TeacherTrain
  1361. {
  1362. pk = "TeacherTrain",
  1363. id = x,
  1364. code = $"TeacherTrain-{change.school}",
  1365. tmdid = x,
  1366. school = change.school,
  1367. update = new HashSet<string> { StatisticsService.TeacherAbility,
  1368. StatisticsService.TeacherClass, StatisticsService.OfflineRecord }
  1369. }, setting, area, client, null));
  1370. });
  1371. await task.TaskPage(1);
  1372. }
  1373. }
  1374. }
  1375. catch (CosmosException ex)
  1376. {
  1377. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-研修数据变更,重新统计-TeacherTrainChange\n{msg}\n{ex.Message}\n{ex.StackTrace}\nCosmosException{ex.Status}", GroupNames.醍摩豆服務運維群組);
  1378. }
  1379. catch (Exception ex)
  1380. {
  1381. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-研修数据变更,重新统计-TeacherTrainChange\n{msg}\n{ex.Message}\n{ex.StackTrace}\n", GroupNames.醍摩豆服務運維群組);
  1382. }
  1383. /*
  1384. string path = $"{_environment.ContentRootPath}/JsonFile/Core/city.json";
  1385. StreamReader streamReader = new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), Encoding.UTF8);
  1386. StringBuilder stringBuilder = new StringBuilder();
  1387. string text;
  1388. while ((text = streamReader.ReadLine()) != null)
  1389. {
  1390. stringBuilder.Append(text.ToString());
  1391. }
  1392. streamReader.Close();
  1393. string input = stringBuilder.ToString();
  1394. List<string> region = new List<string>() {
  1395. "110000", "110100", "110200",
  1396. "120000", "120100", "120200",
  1397. "310000", "310100", "310200",
  1398. "500000", "500100", "810100",
  1399. "810200", "810300", "820100",
  1400. "820200", "820300"
  1401. };
  1402. List<string> cityids = new List<string>() {
  1403. "30","01","03","66","67","64","17","18","20","04","05","07","08","09","10","13","02","15","14","16","71","72"
  1404. };
  1405. Dictionary<string, List<CodeName>> regions = input.ToObject<Dictionary<string, List<CodeName>>>();
  1406. List<List<string>> datas = new List<List<string>>() { region };
  1407. foreach (var r in regions)
  1408. {
  1409. if (!region.Contains(r.Key) && !r.Key.StartsWith("71"))
  1410. {
  1411. datas.Add(r.Value.Select(x => x.code).ToList());
  1412. }
  1413. }
  1414. List<Task<List<SchoolInfo>>> tasks = new List<Task<List<SchoolInfo>>>();
  1415. //datas.ForEach(x =>
  1416. //{
  1417. // tasks.Add(GetSchoolAsync(x));
  1418. //});
  1419. List<SchoolInfo> schoolInfos = new List<SchoolInfo>();
  1420. //var schools = await Task.WhenAll(tasks);
  1421. //var schools =await GetSchoolAsync(cityids);
  1422. // schoolInfos.AddRange(schools);
  1423. //foreach (var schs in schools)
  1424. //{
  1425. // schoolInfos.AddRange(schs);
  1426. //}
  1427. List<string> nodatas = new List<string>();
  1428. foreach (var data in datas) {
  1429. (List<SchoolInfo> schoolIn, List<string> nodata) = await GetSchoolAsync(data);
  1430. schoolInfos.AddRange(schoolIn);
  1431. nodatas.AddRange(nodata);
  1432. }
  1433. await _dingDing.SendBotMsg($"os,test,{nodatas.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
  1434. return Ok(schoolInfos);
  1435. */
  1436. return Ok();
  1437. }
  1438. public async Task<(List<SchoolInfo> schoolInfos, List<string> nodata)> GetSchoolAsync(List<string> regions)
  1439. {
  1440. List<SchoolInfo> schools = new List<SchoolInfo>();
  1441. List<string> nodata = new List<string>();
  1442. foreach (var region in regions)
  1443. {
  1444. Dictionary<string, object> data = new Dictionary<string, object>();
  1445. data.Add("method", "api/School/getSchool");
  1446. data.Add("params", new { CountryId = "CN", CityId = region });
  1447. HttpResponseMessage responseMessage = await _httpClient.CreateClient().PostAsJsonAsync("https://contest.teammodel.cn/api/School/getSchool", data);
  1448. if (responseMessage.StatusCode == HttpStatusCode.OK)
  1449. {
  1450. string Content = await responseMessage.Content.ReadAsStringAsync();
  1451. try
  1452. {
  1453. Content.ToObject<JsonElement>().TryGetProperty("result", out JsonElement content);
  1454. if (content.ValueKind.Equals(JsonValueKind.Object) && content.TryGetProperty("data", out JsonElement _data))
  1455. {
  1456. if (_data.ValueKind.Equals(JsonValueKind.Array))
  1457. {
  1458. List<SchoolInfo> infos = _data.ToObject<List<SchoolInfo>>();
  1459. if (infos.IsNotEmpty())
  1460. {
  1461. schools.AddRange(infos.Where(x => x.name != null && x.cityName != null).ToList());
  1462. }
  1463. }
  1464. else
  1465. {
  1466. nodata.Add(data.ToJsonString());
  1467. continue;
  1468. }
  1469. }
  1470. else
  1471. {
  1472. nodata.Add(data.ToJsonString());
  1473. continue;
  1474. }
  1475. }
  1476. catch (Exception ex)
  1477. {
  1478. nodata.Add(data.ToJsonString());
  1479. throw new Exception(ex.Message, ex.InnerException);
  1480. }
  1481. }
  1482. }
  1483. return (schools, nodata);
  1484. }
  1485. public class SchoolInfo
  1486. {
  1487. public string typeName { get; set; }
  1488. public string provinceName { get; set; }
  1489. public string provinceId { get; set; }
  1490. public string id { get; set; }
  1491. public string name { get; set; }
  1492. public string cityId { get; set; }
  1493. public string cityName { get; set; }
  1494. public string address { get; set; }
  1495. }
  1496. public class CodeName
  1497. {
  1498. public string code { get; set; }
  1499. public string name { get; set; }
  1500. }
  1501. /// <summary>
  1502. /// 测试blob多线程写入同一个文件
  1503. /// </summary>
  1504. /// <returns></returns>
  1505. [ProducesDefaultResponseType]
  1506. [HttpPost("generate-school-codes")]
  1507. public async Task<IActionResult> GenerateSchoolCodes(JsonElement json)
  1508. {
  1509. List<SchoolData> schoolss = json.GetProperty("schools").ToObject<List<SchoolData>>();
  1510. dynamic data = await SchoolService.GenerateSchoolCode(schoolss, _dingDing, _environment);
  1511. return Ok(data);
  1512. }
  1513. private async Task<int> SendNotification()
  1514. {
  1515. // _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.AccessToken}");
  1516. var pa = new { grant_type = "device", client_id = "9794e418-c4ef-4fd5-a42d-accaa2d96d6e", client_secret = "ruL?I79h0w1AZaZXtBaZeZuQLQXLa=:-" };
  1517. HttpResponseMessage responseMessage = await _httpClient.CreateClient().PostAsJsonAsync("https://api2-rc.teammodel.net/oauth2/token", pa);
  1518. if (responseMessage.StatusCode == HttpStatusCode.OK)
  1519. {
  1520. return 200;
  1521. }
  1522. else if (responseMessage.StatusCode == HttpStatusCode.Unauthorized)
  1523. {
  1524. return 401;
  1525. }
  1526. else
  1527. {
  1528. return 500;
  1529. }
  1530. }
  1531. /// <summary>
  1532. /// 测试redis通配符
  1533. /// </summary>
  1534. /// <param name="request"></param>
  1535. /// <returns></returns>
  1536. [ProducesDefaultResponseType]
  1537. [HttpGet("test-delete-read")]
  1538. public async Task<IActionResult> TestDelete()
  1539. {
  1540. foreach (var cnt in _azureStorage.GetBlobServiceClient().GetBlobContainers())
  1541. {
  1542. Console.WriteLine(cnt.Name);
  1543. }
  1544. await SendNotification();
  1545. var client = _azureCosmos.GetCosmosClient();
  1546. string aaa = "0";
  1547. try
  1548. {
  1549. ItemResponse<Student> a = await client.GetContainer(Constant.TEAMModelOS, "Student").DeleteItemAsync<Student>("1111111", new PartitionKey($"Course-111111"));
  1550. Ok(a.GetRawResponse().Status);
  1551. }
  1552. catch (CosmosException ex)
  1553. {
  1554. if (ex.Response.Status == 404)
  1555. {
  1556. aaa = "404";
  1557. }
  1558. }
  1559. try
  1560. {
  1561. ItemResponse<Student> a = await client.GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<Student>("1111111", new PartitionKey($"Course-111111"));
  1562. Ok(a.GetRawResponse().Status);
  1563. }
  1564. catch (CosmosException ex)
  1565. {
  1566. if (ex.Response.Status == 404)
  1567. {
  1568. aaa = aaa + " 404";
  1569. }
  1570. }
  1571. try
  1572. {
  1573. var a = await client.GetContainer(Constant.TEAMModelOS, "Student").DeleteItemStreamAsync("1111111", new PartitionKey($"Course-111111"));
  1574. Ok(a.Status);
  1575. }
  1576. catch (CosmosException ex)
  1577. {
  1578. if (ex.Response.Status == 404)
  1579. {
  1580. aaa = "404";
  1581. }
  1582. }
  1583. try
  1584. {
  1585. var a = await client.GetContainer(Constant.TEAMModelOS, "Student").ReadItemStreamAsync("1111111", new PartitionKey($"Course-111111"));
  1586. Ok(a.Status);
  1587. }
  1588. catch (CosmosException ex)
  1589. {
  1590. if (ex.Response.Status == 404)
  1591. {
  1592. aaa = aaa + " 404";
  1593. }
  1594. }
  1595. return Ok(new { aaa });
  1596. }
  1597. /// <summary>
  1598. /// 测试redis通配符
  1599. /// </summary>
  1600. /// <param name="request"></param>
  1601. /// <returns></returns>
  1602. [ProducesDefaultResponseType]
  1603. [HttpGet("test-redis")]
  1604. public async Task<IActionResult> TestRedis()
  1605. {
  1606. try
  1607. {
  1608. var client = _azureCosmos.GetCosmosClient();
  1609. List<ItemInfo> items = new List<ItemInfo>();
  1610. var queryslt = $"SELECT value(c) FROM c where c.pid = null ";
  1611. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ItemInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-hbcn") }))
  1612. {
  1613. items.Add(item);
  1614. }
  1615. List<ItemCond> itemConds = new List<ItemCond>();
  1616. items.GroupBy(x => x.periodId).Select(y => new { key = y.Key, list = y.ToList() }).ToList().ForEach(z =>
  1617. {
  1618. ItemCond cond = new ItemCond() { id = z.key, code = $"ItemCond-hbcn", pk = "ItemCond", ttl = -1, count = z.list.Count, grades = new List<GradeCount>(), subjects = new List<SubjectItemCount>() };
  1619. z.list.ForEach(y =>
  1620. {
  1621. ItemService.CountItemCond(y, null, cond);
  1622. });
  1623. itemConds.Add(cond);
  1624. });
  1625. itemConds.ForEach(async cond =>
  1626. {
  1627. await client.GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync<ItemCond>(cond, new PartitionKey(cond.code));
  1628. });
  1629. return Ok(new { itemConds });
  1630. }
  1631. catch (Exception ex) { await _dingDing.SendBotMsg($"TEAMModelFunction,ActivityHttpTrigger,fix-itemcond()\n{ex.Message}\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組); }
  1632. return Ok(new { });
  1633. }
  1634. /// <summary>
  1635. ///
  1636. /// </summary>
  1637. /// <param name="request"></param>
  1638. /// <returns></returns>
  1639. [ProducesDefaultResponseType]
  1640. //[AuthToken(Roles = "teacher")]
  1641. [HttpPost("get-DownloadContent-item")]
  1642. public async Task<IActionResult> DownloadContentItem(JsonElement request)
  1643. {
  1644. ItemBlob itemBlob = null;
  1645. try
  1646. {
  1647. BlobDownloadInfo blobDownloadResult = await _azureStorage.GetBlobContainerClient($"hbcn").GetBlobClient($"/item/12b865c9-a223-278a-2be1-e336b9ead99e/12b865c9-a223-278a-2be1-e336b9ead99e.json")
  1648. .DownloadAsync();
  1649. if (blobDownloadResult != null)
  1650. {
  1651. var json = JsonDocument.Parse(blobDownloadResult.Content);
  1652. itemBlob = json.RootElement.ToObject<ItemBlob>();
  1653. }
  1654. }
  1655. catch (Exception ex)
  1656. {
  1657. itemBlob = null;
  1658. }
  1659. return Ok(new { itemBlob });
  1660. }
  1661. /// <summary>
  1662. ///
  1663. /// </summary>
  1664. /// <param name="request"></param>
  1665. /// <returns></returns>
  1666. [ProducesDefaultResponseType]
  1667. //[AuthToken(Roles = "teacher")]
  1668. [HttpPost("get-bind-data")]
  1669. public async Task<IActionResult> GetData(JsonElement request)
  1670. {
  1671. var areaId = request.GetProperty("areaId");
  1672. var table = _azureStorage.GetCloudTableClient().GetTableReference("ScYxpt");
  1673. List<ScTeacher> teachers = await table.FindListByDict<ScTeacher>(new Dictionary<string, object> { { "PartitionKey", "ScTeacher" }, { "areaId", $"{areaId}" } });
  1674. return Ok(teachers.Select(x => new { x.areaId, x.PXID, x.TID, x.TeacherName, x.tmdid, x.SchoolName, x.DisName }));
  1675. }
  1676. /// 删除
  1677. /// </summary>
  1678. /// <param name="request"></param>
  1679. /// <returns></returns>
  1680. [ProducesDefaultResponseType]
  1681. [AuthToken(Roles = "admin,teacher")]
  1682. [HttpPost("get-save-log")]
  1683. public async Task<IActionResult> SaveLog(JsonElement request)
  1684. {
  1685. BlobDownloadResult Recording = await _azureStorage.GetBlobContainerClient("1595321354").GetBlobClient($"records/271528531841781760/Record/.Recording.json").DownloadContentAsync();
  1686. var json = Recording.Content.ToString();
  1687. var jsonByte = Encoding.UTF8.GetBytes(json);
  1688. Stream stream = new MemoryStream(jsonByte);
  1689. var doc = JsonDocument.Parse(stream);
  1690. School school = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>("hbcn", new PartitionKey("Base"));
  1691. _ = _azureStorage.SaveLog("find-school", school.ToJsonString(), httpContext: HttpContext, dingDing: _dingDing, scope: "school");
  1692. return Ok(new { doc, school, });
  1693. }
  1694. /// <summary>
  1695. ///
  1696. /// </summary>
  1697. /// <param name="request"></param>
  1698. /// <returns></returns>
  1699. [ProducesDefaultResponseType]
  1700. //[AuthToken(Roles = "teacher")]
  1701. [HttpPost("get-ip")]
  1702. public async Task<IActionResult> GetIp(JsonElement request)
  1703. {
  1704. try
  1705. {
  1706. BlobDownloadResult baseblobDownload = await _azureStorage.GetBlobContainerClient("habook").GetBlobClient($"/records/299813002894381056/IES/Base.json").DownloadContentAsync();
  1707. LessonBase lessonBase = baseblobDownload.Content.ToObjectFromJson<LessonBase>();
  1708. return Ok(lessonBase);
  1709. }
  1710. catch (RequestFailedException ex) when (ex.Status == 404)
  1711. {
  1712. return BadRequest("文件不存在!");
  1713. }
  1714. LessonBase lessonBases = request.ToObject<LessonBase>();
  1715. //List<TmdInfo> tmds= request.ToObject<List<TmdInfo>>();
  1716. //var content = new StringContent(tmds.Select(x=>x.id).ToJsonString(), Encoding.UTF8, "application/json");
  1717. //string json = await _coreAPIHttpService.GetUserInfos(content);
  1718. //string _researchKey = Regex.Replace($"{request.GetProperty("key")}", "[ \\[ \\] \\^ \\-|()【】/' {}_*×――(^)$%~!@#$…&%¥—+=<>《》!!???::•`·、。,;,.;\"‘’“”-]", " ");
  1719. //string[] mm = Regex.Split(_researchKey, "\\s+", RegexOptions.IgnoreCase);
  1720. //var token = await CoreTokenExtensions.CreateAccessToken("c7317f88-7cea-4e48-ac57-a16071f7b884", "kguxh:V.PLmxBdaI@jnrTrDSth]A3346", "China");
  1721. //string ip = await _searcher.SearchIpAsync($"{request.GetProperty("ip")}");
  1722. // return Ok(new { activity, ip, token.AccessToken,token.TokenType,token.IdToken, mm });
  1723. return Ok(lessonBases);
  1724. }
  1725. /// 删除
  1726. /// </summary>
  1727. /// <param name="request"></param>
  1728. /// <returns></returns>
  1729. [ProducesDefaultResponseType]
  1730. [HttpPost("check-online-record")]
  1731. public async Task<IActionResult> CheckOnlinerecord(JsonElement request)
  1732. {
  1733. string sql = $"select c.id,c.name ,b.schoolId as code from c join b in c.schools where b.areaId='9ae614ba-0771-4502-a56e-0537bc5207c3'";
  1734. List<IdNameCode> codes = new List<IdNameCode>();
  1735. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetItemQueryIterator<IdNameCode>(sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base") }))
  1736. {
  1737. codes.Add(item);
  1738. }
  1739. List<dynamic> data = new List<dynamic>(); ;
  1740. foreach (IdNameCode code in codes)
  1741. {
  1742. try
  1743. {
  1744. TeacherTrain train = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<TeacherTrain>(code.id, new PartitionKey($"TeacherTrain-{code.code}"));
  1745. data.Add(new { code.id, code.name, code.code, train.totalTime, train.onlineTime, train.classTime, train.offlineTime });
  1746. }
  1747. catch (Exception ex)
  1748. {
  1749. data.Add(new { code.id, code.name, code.code, totalTime = 0, onlineTime = 0, classTime = 0, offlineTime = 0 });
  1750. }
  1751. }
  1752. return Ok(new { data });
  1753. }
  1754. [HttpPost("test-scteacher")]
  1755. public async Task<IActionResult> TestScteacher(JsonElement json)
  1756. {
  1757. var table = _azureStorage.GetCloudTableClient().GetTableReference("ScYxpt");
  1758. List<ScTeacher> teachers = await table.FindListByDict<ScTeacher>(new Dictionary<string, object>() { { "PartitionKey", "ScTeacher" }, { "areaId", "e6fb5d40-bd85-7327-cea8-ea5c642836d2" }, { "SchoolName", "岳池县大佛初级中学校" } });
  1759. //var techs= teachers.Where(t => string.IsNullOrWhiteSpace(t.tmdid));
  1760. return Ok(teachers);
  1761. }
  1762. [HttpPost("get-token")]
  1763. public async Task<IActionResult> GetToken(JsonElement request)
  1764. {
  1765. if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
  1766. if (!request.TryGetProperty("host", out JsonElement host)) return BadRequest();
  1767. if (!request.TryGetProperty("name", out JsonElement name)) return BadRequest();
  1768. if (!request.TryGetProperty("picture", out JsonElement picture)) return BadRequest();
  1769. if (!request.TryGetProperty("areaId", out JsonElement areaId)) return BadRequest();
  1770. if (!request.TryGetProperty("school", out JsonElement school)) return BadRequest();
  1771. int timezone = 8;
  1772. if (HttpContext.Request.Headers.TryGetValue("Time-Zone", out var Time_Zone) && int.TryParse(Time_Zone, out int tz))
  1773. {
  1774. timezone=tz;
  1775. }
  1776. var auth_token = JwtAuthExtension.CreateAuthToken(host.ToString(), id.ToString(), name.ToString(),
  1777. picture.ToString(), _option.JwtSecretKey,
  1778. scope: "student", Website: "IES",timezone, areaId: areaId.ToString(),schoolID: school.ToString(), roles: new[] { "student" }, expire: 1);
  1779. //var techs= teachers.Where(t => string.IsNullOrWhiteSpace(t.tmdid));
  1780. return Ok(auth_token);
  1781. }
  1782. [HttpPost("test-scteacher-dn")]
  1783. public async Task<IActionResult> TestScteacherDn(JsonElement json)
  1784. {
  1785. var table = _azureStorage.GetCloudTableClient().GetTableReference("ScYxpt");
  1786. string sqls = "select distinct value(c.id )from c where c.code='Base' and IS_DEFINED(c.finalScore)=true ";
  1787. //https://teammodelos.blob.core.chinacloudapi.cn/teammodelos
  1788. //https://teammodelos.blob.core.chinacloudapi.cn/teammodelos/yxpt%2Fjinniu%2Fscbind%2F1647432004.json
  1789. List<ScTeacher> teachers = await table.FindListByDict<ScTeacher>(new Dictionary<string, object>() { { "PartitionKey", "ScTeacher" }, { "areaId", "870a5a6b-1ab3-461a-bdeb-baec19780ddb" } });
  1790. List<string> ids = new List<string>();
  1791. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
  1792. .GetItemQueryIterator<string>(sqls, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base") }))
  1793. {
  1794. ids.Add(item);
  1795. }
  1796. long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  1797. List<string> erorr = new List<string>();
  1798. List<ScTeacher> teachersUp = new List<ScTeacher>();
  1799. foreach (var id in ids)
  1800. {
  1801. try
  1802. {
  1803. BlobDownloadResult baseblobDownload = await _azureStorage.GetBlobContainerClient("teammodelos").GetBlobClient($"/yxpt/jinniu/scbind/{id}.json").DownloadContentAsync();
  1804. ScBindData scBindData = baseblobDownload.Content.ToObjectFromJson<ScBindData>();
  1805. var tcd = teachers.Find(x => x.RowKey.Equals(scBindData.pxid));
  1806. if (tcd != null)
  1807. {
  1808. Teacher teacher = new Teacher
  1809. {
  1810. createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
  1811. pk = "Base",
  1812. code = "Base",
  1813. id = id,
  1814. name = scBindData.username,
  1815. size = 2,
  1816. defaultSchool = tcd.schoolCode,
  1817. schools = new List<TeacherSchool> {
  1818. new TeacherSchool
  1819. {
  1820. schoolId = tcd.schoolCode, status = "join", time = now, name = scBindData.sn, areaId = tcd.areaId
  1821. }
  1822. },
  1823. binds = new List<ThirdBind> {
  1824. new ThirdBind
  1825. {
  1826. type= "scsyxpt",userid=scBindData.userid,username= scBindData.username,account=scBindData.account,data=new List<string>{ scBindData.ToJsonString()}
  1827. }
  1828. }
  1829. };
  1830. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(teacher, new PartitionKey("Base"));
  1831. tcd.tmdid = id;
  1832. teachersUp.Add(tcd);
  1833. }
  1834. }
  1835. catch (Exception)
  1836. {
  1837. erorr.Add(id);
  1838. }
  1839. }
  1840. await table.SaveOrUpdateAll(teachersUp);
  1841. return Ok();
  1842. }
  1843. [HttpPost("fix-jinniupujiang-teacher-videotime")]
  1844. public async Task<IActionResult> GetScteacher(JsonElement json)
  1845. {
  1846. if (!json.TryGetProperty("areaId", out JsonElement _areaId)) { return BadRequest(); }
  1847. Area area = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).ReadItemAsync<Area>($"{_areaId}", new PartitionKey("Base-Area"));
  1848. AreaSetting setting = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).ReadItemAsync<AreaSetting>($"{_areaId}", new PartitionKey("AreaSetting"));
  1849. List<string> teachers = new List<string>();
  1850. //获取这个区的教师 //psywgy
  1851. string schoolSql = $"SELECT value c.id FROM c join a in c.schools where a.areaId='{_areaId}' and c.code='Base' ";
  1852. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
  1853. .GetItemQueryIterator<string>(schoolSql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base") }))
  1854. {
  1855. teachers.Add(item);
  1856. }
  1857. //获取这些老师的研修记录
  1858. string tr = $"SELECT distinct value(c) FROM c join a in c.currency.teacherAilities where c.id in ({string.Join(",", teachers.Select(x => $"'{x}'"))}) and c.pk='TeacherTrain' and a.videoTime<300 ";
  1859. List<TeacherTrain> teacherTrains = new List<TeacherTrain>();
  1860. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
  1861. .GetItemQueryIterator<TeacherTrain>(tr, requestOptions: new QueryRequestOptions { }))
  1862. {
  1863. if (!item.tmdid.Equals("1528783259") || !item.tmdid.Equals("1530606136"))
  1864. {
  1865. teacherTrains.Add(item);
  1866. }
  1867. }
  1868. //获取这个区的能力点树状结构
  1869. string sql = $" select distinct value(b.id ) from c join b in c.children where c.code='AbilityTask-{area.standard}' ";
  1870. List<string> nodeIdsDB = new List<string>();
  1871. await foreach (var y in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).GetItemQueryIterator<string>
  1872. (sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"AbilityTask-{area.standard}") }))
  1873. {
  1874. nodeIdsDB.Add(y);
  1875. }
  1876. List<AbilitySub> abilitySubs = new List<AbilitySub>();
  1877. List<TeacherVideoTime> teacherVideoTimes = new List<TeacherVideoTime>();
  1878. string ids = teacherTrains.Select(x => x.id).ToJsonString();
  1879. string sqls = $" select value(c) from c where c.code='AbilityTask-{area.standard}'";
  1880. List<AbilityTask> abilityTasks = new List<AbilityTask>();
  1881. Dictionary<string, RecordFileAbility> valuePairs = new Dictionary<string, RecordFileAbility>();
  1882. await foreach (var y in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).GetItemQueryIterator<AbilityTask>
  1883. (sqls, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"AbilityTask-{area.standard}") }))
  1884. {
  1885. abilityTasks.Add(y);
  1886. }
  1887. foreach (var item in teacherTrains)
  1888. {
  1889. List<TeacherAbility> teacherAbility = new List<TeacherAbility>();
  1890. if (item.currency.teacherAilities.Count() > 3)
  1891. {
  1892. //如果选择了大于三个能力点的教师,则优先获取上传了认证材料的的能力点,
  1893. var uploadHas = item.currency.teacherAilities.FindAll(x => x.uploadHas == 1 && x.videoTime < 300);
  1894. if (uploadHas.Any())
  1895. {
  1896. teacherAbility.AddRange(uploadHas);
  1897. }
  1898. if (teacherAbility.Count < 3)
  1899. {
  1900. // 如果仍然未满足数量。则再去获取 没有上传认证材料,但是又有学习时间长的能力点。
  1901. var hasVideoTime = item.currency.teacherAilities.FindAll(x => x.uploadHas != 1 && x.videoTime < 300).OrderByDescending(o => o.videoTime);
  1902. var disCount = 3 - teacherAbility.Count;
  1903. teacherAbility.AddRange(hasVideoTime.Take(disCount));
  1904. }
  1905. }
  1906. else
  1907. {
  1908. teacherAbility.AddRange(item.currency.teacherAilities.Where(ab => ab.videoTime < 300));
  1909. }
  1910. TeacherFile teacherFile = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<TeacherFile>(item.id, new PartitionKey($"TeacherFile-{item.code.Replace("TeacherTrain-", "")}"));
  1911. foreach (var ability in teacherAbility)
  1912. {
  1913. TeacherVideoTime teacherVideoTime = new TeacherVideoTime { code = item.code.Replace("TeacherTrain-", ""), id = item.id, abilityId = ability.id, no = ability.no, train_time = ability.videoTime };
  1914. double fileview = 0;
  1915. var filerecord = teacherFile.fileRecords.FindAll(x => x.files.Where(y => y.abilityId.Equals(ability.id)).Count() > 0);
  1916. filerecord.ForEach(x => {
  1917. var file = x.files.FindAll(y => y.abilityId.Equals($"{ability.id}"));
  1918. if (file.IsNotEmpty())
  1919. {
  1920. fileview += x.view;
  1921. }
  1922. });
  1923. double fminut = fileview / 60;
  1924. teacherVideoTime.files_time = fminut;
  1925. var tech = abilityTasks.FindAll(x => x.abilityId.Equals(ability.id));
  1926. // double limit = 0;
  1927. tech.ForEach(task =>
  1928. {
  1929. task.children.ForEach(y =>
  1930. {
  1931. y.rnodes.ForEach(r =>
  1932. {
  1933. if (valuePairs.ContainsKey(r.hash))
  1934. {
  1935. valuePairs.TryGetValue(r.hash, out var value);
  1936. var ablt = value.fileAbilities.Find(z => z.abilityId.Equals(task.abilityId) && z.taskId.Equals(task.id) && z.nodeId.Equals(y.id));
  1937. if (ablt == null)
  1938. {
  1939. value.fileAbilities.Add(new FileAbility { url = r.link, abilityId = task.abilityId, taskId = task.id, nodeId = y.id });
  1940. // limit = limit + r.duration;
  1941. }
  1942. }
  1943. else
  1944. {
  1945. valuePairs.Add(r.hash, new RecordFileAbility
  1946. {
  1947. fileRecord =
  1948. new FileRecord { hash = r.hash, size = r.size.Value, duration = r.duration, view = (int)r.duration, type = r.type, done = true },
  1949. fileAbilities = new List<FileAbility> { new FileAbility { url = r.link, abilityId = task.abilityId, taskId = task.id, nodeId = y.id } }
  1950. });
  1951. // limit = limit + r.duration;
  1952. }
  1953. });
  1954. });
  1955. });
  1956. HashSet<string> childIds = new HashSet<string>();
  1957. foreach (var ps in valuePairs)
  1958. {
  1959. HashSet<string> abilityIds = teacherFile.fileRecords.SelectMany(x => x.files).Select(x => x.abilityId).Where(abid => abid.Equals(ability.id)).ToHashSet();
  1960. double view = 0;
  1961. foreach (var abid in abilityIds)
  1962. {
  1963. var record = teacherFile.fileRecords.FindAll(x => x.files.Where(y => y.abilityId.Equals(abid)).Count() > 0);
  1964. record.ForEach(x => {
  1965. var file = x.files.FindAll(y => y.abilityId.Equals($"{abid}"));
  1966. if (file.IsNotEmpty())
  1967. {
  1968. view += x.view;
  1969. }
  1970. });
  1971. }
  1972. double minut = view / 60;
  1973. teacherVideoTime.after_time = minut;
  1974. if (minut < 300)
  1975. {
  1976. var fils = teacherFile.fileRecords.Find(x => x.hash.Equals(ps.Key));
  1977. if (fils != null)
  1978. {
  1979. ps.Value.fileAbilities.ForEach(x =>
  1980. {
  1981. var a = fils.files.Find(z => z.nodeId.Equals(x.nodeId) && z.abilityId.Equals(x.abilityId));
  1982. if (a == null)
  1983. {
  1984. childIds.Add(x.nodeId);
  1985. fils.files.Add(new FileAbility { url = x.url, abilityId = x.abilityId, taskId = x.taskId, nodeId = x.nodeId });
  1986. }
  1987. });
  1988. }
  1989. else
  1990. {
  1991. ps.Value.fileAbilities.ForEach(x =>
  1992. {
  1993. childIds.Add(x.nodeId);
  1994. });
  1995. teacherFile.fileRecords.Add(new FileRecord
  1996. {
  1997. hash = ps.Value.fileRecord.hash,
  1998. size = ps.Value.fileRecord.size,
  1999. duration = ps.Value.fileRecord.duration,
  2000. view = (int)ps.Value.fileRecord.view,
  2001. type = ps.Value.fileRecord.type,
  2002. done = true,
  2003. files = ps.Value.fileAbilities
  2004. });
  2005. }
  2006. }
  2007. else
  2008. {
  2009. break;
  2010. }
  2011. }
  2012. if (childIds.Any())
  2013. {
  2014. string code = teacherFile.code.Replace("TeacherFile-", "");
  2015. if (!string.IsNullOrWhiteSpace(code))
  2016. {
  2017. try
  2018. {
  2019. AbilitySub abilitySub = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<AbilitySub>(ability.id, new PartitionKey($"AbilitySub-{code}-{teacherFile.id}"));
  2020. var taskIds = abilitySub.taskRcds.Select(x => x.id);
  2021. var notin = childIds.Except(taskIds);
  2022. if (notin.Any())
  2023. {
  2024. abilitySub.taskRcds.AddRange(notin.Select(x => new AbilityTaskRcd { id = x, done = true }));
  2025. abilitySubs.Add(abilitySub);
  2026. }
  2027. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReplaceItemAsync(abilitySub, abilitySub.id, new PartitionKey($"AbilitySub-{code}-{teacherFile.id}"));
  2028. }
  2029. catch (Exception ex)
  2030. {
  2031. }
  2032. }
  2033. }
  2034. teacherVideoTimes.Add(teacherVideoTime);
  2035. }
  2036. teacherFile = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReplaceItemAsync<TeacherFile>(teacherFile, teacherFile.id, new PartitionKey(teacherFile.code));
  2037. item.update.Add(StatisticsService.TeacherAbility);
  2038. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReplaceItemAsync<TeacherTrain>(item, item.id, new PartitionKey(item.code));
  2039. }
  2040. var data = teacherVideoTimes.GroupBy(x => x.code).Select(x => new { x.Key, count = x.ToList().Count, list = x.ToList() }).OrderByDescending(x => x.count);
  2041. return Ok(new { data, abilitySubs });
  2042. }
  2043. public class TeacherVideoTime
  2044. {
  2045. public string code { get; set; }
  2046. public string id { get; set; }
  2047. public string abilityId { get; set; }
  2048. public string no { get; set; }
  2049. public double train_time { get; set; }
  2050. public double files_time { get; set; }
  2051. public double after_time { get; set; }
  2052. }
  2053. [HttpPost("get-teacher-video")]
  2054. public async Task<IActionResult> GetScteacherClassVideo(JsonElement json)
  2055. {
  2056. string sql = " SELECT c.id ,c.school as code FROM c where c.pk='ClassVideo' and c.school<>'SYSTEM_NO_SCHOOL' and ARRAY_LENGTH(c.files)>0 ";
  2057. List<IdNameCode> idNameCodes = new List<IdNameCode>();
  2058. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetItemQueryIterator<IdNameCode>(sql, requestOptions: new QueryRequestOptions { }))
  2059. {
  2060. idNameCodes.Add(item);
  2061. }
  2062. foreach (var item in idNameCodes)
  2063. {
  2064. try
  2065. {
  2066. TeacherTrain teacherTrain = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<TeacherTrain>(item.id, new PartitionKey($"TeacherTrain-{item.code}"));
  2067. if (!teacherTrain.teacherClasses.Any())
  2068. {
  2069. teacherTrain.update.Add("TeacherClass");
  2070. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReplaceItemAsync<TeacherTrain>(teacherTrain, teacherTrain.id, new PartitionKey($"TeacherTrain-{item.code}"));
  2071. }
  2072. }
  2073. catch (Exception ex)
  2074. {
  2075. continue;
  2076. }
  2077. }
  2078. return Ok();
  2079. }
  2080. [HttpPost("test-batch")]
  2081. public async Task<IActionResult> TestBatchFUN(JsonElement json)
  2082. {
  2083. List<Task<ItemResponse<TestBatch>>> nameCodes = new List<Task<ItemResponse<TestBatch>>>();
  2084. for (int i = 0; i < 10; i++)
  2085. {
  2086. nameCodes.Add(_azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).
  2087. CreateItemAsync(new TestController.TestBatch { id = Guid.NewGuid().ToString(), code = $"TestBatch-{i}", pk = "TestBatch" }, new PartitionKey($"TestBatch-{i}")));
  2088. }
  2089. await Task.WhenAll(nameCodes);
  2090. return Ok();
  2091. }
  2092. public class TestBatch : CosmosEntity
  2093. {
  2094. }
  2095. [HttpPost("export-teacher")]
  2096. public async Task<IActionResult> ExportTeacher(JsonElement json)
  2097. {
  2098. List<string> schools = new()
  2099. {
  2100. "dghznx",
  2101. "cxhhlx",
  2102. "xjaxx",
  2103. "zjqxx",
  2104. "xnygxx",
  2105. "lxxcfx",
  2106. "gxjrxx",
  2107. "cdgxsx",
  2108. "yzxx",
  2109. "kjyxx",
  2110. "wjylxx",
  2111. "dsgjxx",
  2112. "ydzt",
  2113. "xndbxx",
  2114. "sqtszx",
  2115. "cdxczx",
  2116. "ghsyzx",
  2117. "lqsx",
  2118. "cdxxps",
  2119. "xcfx",
  2120. "xyqxx",
  2121. "xncbyy",
  2122. "cdlqjk",
  2123. "lqdmxx",
  2124. "lqyx",
  2125. "pclxxx",
  2126. "cdfzx",
  2127. "xnblxx",
  2128. "ghsx",
  2129. "khdycz",
  2130. "khbmxx",
  2131. "khdecz",
  2132. "khzx",
  2133. "khhbzx",
  2134. "gxxcxx",
  2135. "khhtxx",
  2136. "khdxxx",
  2137. "khsyxx"
  2138. };
  2139. var cosmosClient = _azureCosmos.GetCosmosClient();
  2140. foreach (var item in schools)
  2141. {
  2142. School school = await cosmosClient.GetContainer("TEAMModelOS", "School").ReadItemAsync<School>($"{item}", new PartitionKey("Base"));
  2143. List<Teacher> teachers = new();
  2144. await foreach (var tch in cosmosClient.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<Teacher>(queryText:
  2145. $"SELECT value(c) FROM c join s in c.schools where s.schoolId='{item}' and c.code='Base'",
  2146. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
  2147. {
  2148. teachers.Add(tch);
  2149. }
  2150. if (teachers.Count > 0)
  2151. {
  2152. foreach (var teacher in teachers)
  2153. {
  2154. teacher.schools.ForEach(tch => { if (tch.schoolId.Equals(item)) { tch.areaId = school.areaId; } });
  2155. await cosmosClient.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Teacher>(teacher, teacher.id, new PartitionKey("Base"));
  2156. }
  2157. }
  2158. }
  2159. return Ok();
  2160. }
  2161. public class RecordFileAbility
  2162. {
  2163. public FileRecord fileRecord { get; set; }
  2164. public List<FileAbility> fileAbilities { get; set; }
  2165. }
  2166. [HttpPost("test-blob-folder")]
  2167. public async Task<IActionResult> TestBlobFolder(JsonElement json)
  2168. {
  2169. string location = _option.Location;
  2170. bool lockKey = await _azureRedis.GetRedisClient(8).KeyExistsAsync($"LessonRecord:Unused:Lock:{location}");
  2171. //key不存在的时候 。
  2172. if (!lockKey)
  2173. {
  2174. var schoolKeys = new List<IdCodeCount>();
  2175. var teacherKeys = new List<IdCodeCount>();
  2176. string sql = "select value c.id from c where c.code='Base'";
  2177. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).
  2178. GetItemQueryIterator<string>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base") }))
  2179. {
  2180. teacherKeys.Add(new IdCodeCount { id = item, code = "Teacher" });
  2181. }
  2182. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).
  2183. GetItemQueryIterator<string>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base") }))
  2184. {
  2185. schoolKeys.Add(new IdCodeCount { id = item, code = "School" });
  2186. }
  2187. string sqlcount = "select value count(1) from c where c.pk='LessonRecord'";
  2188. foreach (var key in schoolKeys)
  2189. {
  2190. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).
  2191. GetItemQueryIterator<int>(queryText: sqlcount, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"LessonRecord-{key.id}") }))
  2192. {
  2193. key.count = item;
  2194. break;
  2195. }
  2196. }
  2197. foreach (var key in teacherKeys)
  2198. {
  2199. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).
  2200. GetItemQueryIterator<int>(queryText: $"select value count(1) from c where c.pk='LessonRecord' and c.tmdid='{key.id}'",
  2201. requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"LessonRecord") }))
  2202. {
  2203. key.count = item;
  2204. break;
  2205. }
  2206. }
  2207. schoolKeys.AddRange(teacherKeys);
  2208. //以下代码作用,用于根据当前拥有的课例数判断区分学校和个人使用课例频率越多的,
  2209. //并均分每次需要处理的学校和个人容器个数,避免每次处理批次花费时间相差太大。
  2210. //将每个批次处理数量级控制在500-1000左右。
  2211. List<IEnumerable<IdCodeCount>> counts = new List<IEnumerable<IdCodeCount>>();
  2212. //501-∞
  2213. var count501_ = schoolKeys.Where(x => x.count >= 501); //至少500条
  2214. counts.AddRange(count501_.Page(1));//1个学校
  2215. //201-500
  2216. var count201_500 = schoolKeys.Where(x => x.count >= 201 && x.count <= 500); //至少402条-1000条
  2217. counts.AddRange(count201_500.Page(2));//2个学校
  2218. //100-200
  2219. var count100_200 = schoolKeys.Where(x => x.count >= 100 && x.count <= 200);//至少500条-1000条
  2220. counts.AddRange(count100_200.Page(5));//5个学校
  2221. //51-99
  2222. var count51_99 = schoolKeys.Where(x => x.count >= 51 && x.count <= 99);//至少500条-990条
  2223. counts.AddRange(count51_99.Page(10));//10个学校
  2224. //21-50
  2225. var count21_50 = schoolKeys.Where(x => x.count >= 21 && x.count <= 50);//至少410条-1000条
  2226. counts.AddRange(count21_50.Page(20));//20个学校
  2227. //10-20
  2228. var count10_20 = schoolKeys.Where(x => x.count >= 10 && x.count <= 20);//至少500条-1000条
  2229. counts.AddRange(count10_20.Page(50));//50个学校
  2230. //5-9
  2231. var count0_9 = schoolKeys.Where(x => x.count >= 5 && x.count <= 9);//至少500条-900条
  2232. counts.AddRange(count0_9.Page(100));//100个学校
  2233. //2-4
  2234. var count2_4 = schoolKeys.Where(x => x.count >= 2 && x.count <= 4);//至少500条-1000条
  2235. counts.AddRange(count2_4.Page(250));
  2236. //0-1
  2237. var count0_1 = schoolKeys.Where(x => x.count >= 0 && x.count <= 1);//至少500,就算没有课例也算一次。
  2238. counts.AddRange(count0_1.Page(500));
  2239. int field = 1;
  2240. counts.Count();
  2241. foreach (var item in counts)
  2242. {
  2243. bool stuallstatus = await _azureRedis.GetRedisClient(8).HashSetAsync($"LessonRecord:Unused:Lock:{location}", field, new { status = 0, item }.ToJsonString());
  2244. field += 1;
  2245. }
  2246. await _dingDing.SendBotMsg($"{location},获取到:{schoolKeys.Count} 个学校和个人的容器\n" +
  2247. $"大概要处理:{schoolKeys.Sum(x => x.count) + schoolKeys.Where(x => x.count >= 0).Count()} 条数据\n" +
  2248. $"将数据分为:{field - 1} 次处理,每次处理500-1000条数据。", GroupNames.醍摩豆服務運維群組);
  2249. }
  2250. return Ok(new { });
  2251. }
  2252. public class IdCodeCount
  2253. {
  2254. public string id { get; set; }
  2255. public string code { get; set; }
  2256. public int count { get; set; }
  2257. }
  2258. /// <summary>
  2259. /// 随机获取三个不同类型的题目
  2260. /// </summary>
  2261. /// <param name="request"></param>
  2262. /// <returns></returns>
  2263. [HttpPost("gen-pdf")]
  2264. //[Authorize(Roles = Constant.Role_Root)]
  2265. public IActionResult GenPdf(JsonElement json)
  2266. {
  2267. //https://article.itxueyuan.com/JAxOnG
  2268. //http://t.zoukankan.com/hsiang-p-14608694.html
  2269. //https://github.com/rdvojmoc/DinkToPdf
  2270. //https://blog.csdn.net/u011966339/article/details/114964016?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-114964016-blog-118609642.pc_relevant_antiscanv2&spm=1001.2101.3001.4242.1&utm_relevant_index=3
  2271. var html = @"
  2272. <!DOCTYPE html>
  2273. <html>
  2274. <head>
  2275. <meta charset=""UTF-8"">
  2276. <meta http-equiv=""X-UA-Compatible"" content=""IE=edge"">
  2277. <meta name=""viewport"" content=""width=device-width, initial-scale=1.0"">
  2278. <title>校本研修活动完成情况</title>
  2279. <style>
  2280. body {
  2281. font-family: ""fangsong"";
  2282. display: flex;
  2283. flex-direction: column;
  2284. align-items: center;
  2285. }
  2286. .tch-table,
  2287. .details-table {
  2288. width: 100%;
  2289. }
  2290. .tch-table table {
  2291. width: 100%;
  2292. margin: 15px 0;
  2293. border: 0;
  2294. }
  2295. .tch-table th {
  2296. background-color: #c5c5c5;
  2297. color: #222222;
  2298. }
  2299. .tch-table,
  2300. .tch-table th,
  2301. .tch-table td {
  2302. font-size: 0.95em;
  2303. text-align: center;
  2304. padding: 4px;
  2305. border-collapse: collapse;
  2306. font-weight: bolder;
  2307. }
  2308. .tch-table th,
  2309. .tch-table td {
  2310. border-bottom: 1px solid #918b8c;
  2311. border-width: 1px 0 1px 0;
  2312. }
  2313. .tch-table tr {
  2314. border: 1px solid #ffffff;
  2315. height: 3.2em;
  2316. }
  2317. .title {
  2318. font-weight: bold;
  2319. align-self: flex-start;
  2320. margin: 30px 5px;
  2321. }
  2322. .title::before {
  2323. content: """";
  2324. width: 10px;
  2325. height: 10px;
  2326. background: #3a3a3a;
  2327. display: inline-block;
  2328. margin-right: 10px;
  2329. }
  2330. </style>
  2331. </head>
  2332. <body>
  2333. <h1 style=""text-align:center;font-weight: bold;"">校本研修活动完成情况</h1>
  2334. <p class=""title"">教师信息</p>
  2335. <table class=""tch-table"" id=""tchTable"">
  2336. <tr>
  2337. <th style=""width: 33.3%;"">教师姓名</th>
  2338. <th style=""width: 33.3%;"">机构</th>
  2339. <th style=""width: 33.3%;"">教研组</th>
  2340. </tr>
  2341. <tr>
  2342. <td>张三</td>
  2343. <td>四川省成都市盐道街中学</td>
  2344. <td>高中政治教研组</td>
  2345. </tr>
  2346. </table>
  2347. <p class=""title"">活动明细</p>
  2348. <table class=""tch-table"" id=""acTable"">
  2349. <tr>
  2350. <th style=""width: 25%;"">活动主题</th>
  2351. <th style=""width: 15%;"">活动类型</th>
  2352. <th style=""width: 5%;"">任务学时</th>
  2353. <th style=""width: 5%;"">完成学时</th>
  2354. <th style=""width: 20%;"">活动时间</th>
  2355. <th style=""width: 10%;"">活动内容</th>
  2356. <th style=""width: 10%;"">活动任务</th>
  2357. <th style=""width: 10%;"">状态</th>
  2358. </tr>
  2359. <tr>
  2360. <td>语文学科如何在A1技术支持下进行学情分析</td>
  2361. <td>信息化教学案例展示与分享</td>
  2362. <td>1</td>
  2363. <td>1</td>
  2364. <td>2022-04-07 到 2022-04-14</td>
  2365. <td></td>
  2366. <td>扫码签到、作业提交、问卷反馈、评测活动</td>
  2367. <td>已完成</td>
  2368. </tr>
  2369. </table>
  2370. </body>
  2371. </html>
  2372. ";
  2373. try
  2374. {
  2375. GlobalSettings globalSettings = new GlobalSettings();
  2376. globalSettings.ColorMode = ColorMode.Color;
  2377. globalSettings.Orientation = Orientation.Portrait;
  2378. globalSettings.PaperSize = PaperKind.A4;
  2379. globalSettings.Margins = new MarginSettings { Top = 25, Bottom = 25 };
  2380. ObjectSettings objectSettings = new ObjectSettings();
  2381. objectSettings.PagesCount = true;
  2382. objectSettings.HtmlContent = html;
  2383. //WebSettings webSettings = new WebSettings();
  2384. //webSettings.DefaultEncoding = "utf-8";
  2385. HeaderSettings headerSettings = new HeaderSettings();
  2386. headerSettings.FontSize = 15;
  2387. headerSettings.FontName = "fangsong";
  2388. headerSettings.Right = "";
  2389. // headerSettings.Line = true;
  2390. FooterSettings footerSettings = new FooterSettings();
  2391. footerSettings.FontSize = 12;
  2392. footerSettings.FontName = "Ariel";
  2393. footerSettings.Center = "校本研修活动完成情况([page]/[toPage])页";
  2394. // footerSettings.Line = true;
  2395. objectSettings.HeaderSettings = headerSettings;
  2396. objectSettings.FooterSettings = footerSettings;
  2397. //objectSettings.WebSettings = webSettings;
  2398. HtmlToPdfDocument htmlToPdfDocument = new HtmlToPdfDocument()
  2399. {
  2400. GlobalSettings = globalSettings,
  2401. Objects = { objectSettings },
  2402. };
  2403. var a = _converter.Convert(htmlToPdfDocument);
  2404. MemoryStream m = new MemoryStream(a);
  2405. FileStream fs = new FileStream("F:\\1111111111111\\SimplePdf1.pdf", FileMode.Create, FileAccess.Write, FileShare.Read);
  2406. m.WriteTo(fs);
  2407. m.Close();
  2408. fs.Close();
  2409. var doc = new HtmlToPdfDocument()
  2410. {
  2411. GlobalSettings = {
  2412. ColorMode = ColorMode.Color,
  2413. Orientation = Orientation.Portrait,
  2414. PaperSize = PaperKind.A4,
  2415. Margins = new MarginSettings() { Top = 10 },
  2416. Out = @"F:\test.pdf",
  2417. },
  2418. Objects = {
  2419. new ObjectSettings()
  2420. {
  2421. Page = "https://teammodelos.blob.core.chinacloudapi.cn/0-public/pie-borderRadius.html",
  2422. },
  2423. }
  2424. };
  2425. _converter.Convert(doc);
  2426. return Ok();
  2427. // return Ok(File(a, "application/octet-stream", "SimplePdf.pdf"));
  2428. }
  2429. catch (Exception ex)
  2430. {
  2431. return BadRequest(new { ex = ex.StackTrace, exmsg = ex.Message });
  2432. }
  2433. }
  2434. /*
  2435. //自主學習綱領 資料架構測試
  2436. [HttpPost("test-selflearn-structure")]
  2437. public async Task<IActionResult> TestSelfLearnStructure(JsonElement json)
  2438. {
  2439. string tmid = "1595321354";
  2440. ////個人課程
  2441. //主體
  2442. SelfLearn selfLearnT = new SelfLearn();
  2443. selfLearnT.code = $"SelfLearn-{tmid}";
  2444. selfLearnT.id = "a6dc752f-7cae-44a5-9b7b-92cfe71cea14";
  2445. selfLearnT.scope = "private";
  2446. selfLearnT.name = "測試課程課綱";
  2447. selfLearnT.course = new IdName();
  2448. selfLearnT.course.id = "ae64e6a4-54f3-10df-a7f3-79dbe252d295";
  2449. selfLearnT.course.name = "測試課程001";
  2450. selfLearnT.creatorId = $"{tmid}";
  2451. selfLearnT.creatorName = "Miss Lo";
  2452. selfLearnT.release = true;
  2453. selfLearnT.groupLists.Add(new IdName { id = "a986bf87-da87-4bd3-bd90-19ee9fd52836", name = "測試課程名單" });
  2454. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnT);
  2455. //節點:章節
  2456. SelfLearnNode selfLearnNodeTChapter = new SelfLearnNode();
  2457. selfLearnNodeTChapter.code = $"SelfLearn-{tmid}";
  2458. selfLearnNodeTChapter.id = "0990cbb6-3228-41d0-aeb0-62209f37dc0d";
  2459. selfLearnNodeTChapter.name = "第一章節";
  2460. selfLearnNodeTChapter.selfLearnId = selfLearnT.id;
  2461. selfLearnNodeTChapter.nodeType = "chapter";
  2462. selfLearnNodeTChapter.openType = "order";
  2463. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnNodeTChapter);
  2464. //節點:項目
  2465. SelfLearnNode selfLearnNodeTContent = new SelfLearnNode();
  2466. selfLearnNodeTContent.code = $"SelfLearn-{tmid}";
  2467. selfLearnNodeTContent.id = "5627184f-e9b4-4ceb-a1d0-47727db569b1";
  2468. selfLearnNodeTContent.name = "四則運算";
  2469. selfLearnNodeTContent.selfLearnId = selfLearnT.id;
  2470. selfLearnNodeTContent.selfLearnNodeId = selfLearnNodeTChapter.id;
  2471. selfLearnNodeTContent.nodeType = "content";
  2472. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnNodeTContent);
  2473. //內容:作業
  2474. SelfLearnContentHomework selfLearnTContentHomework = new SelfLearnContentHomework();
  2475. selfLearnTContentHomework.code = $"SelfLearn-{tmid}";
  2476. //內容:評量
  2477. SelfLearnContentExam selfLearnTContentExam = new SelfLearnContentExam();
  2478. selfLearnTContentExam.code = $"SelfLearn-{tmid}";
  2479. selfLearnTContentExam.id = "07e6fdd2-6083-4eb6-ac6d-06421edb0b48";
  2480. selfLearnTContentExam.name = "隨堂測驗1";
  2481. selfLearnTContentExam.selfLearnId = selfLearnT.id;
  2482. selfLearnTContentExam.selfLearnNodeId = selfLearnNodeTContent.id;
  2483. selfLearnTContentExam.contentType = "exam";
  2484. //自主課綱的試卷需要從試題庫拷貝到課綱Blob之下 容器:個人課綱:{個人ID} 路徑:selflearn/{selfLearn本體ID}/paper/{試卷名稱}/{試卷各個檔案}
  2485. ////自主課綱Blob需納管入Blob容量計算系統之下
  2486. List<Dictionary<string, string>> sourcePaperDic = new List<Dictionary<string, string>>();
  2487. sourcePaperDic.Add(new Dictionary<string, string>() { { "id", "184914dd-05e0-04f4-e14a-cfce53545018" }, { "blobContainer", "1595321354" }, { "blob", "paper/個人評量測試卷1" }, { "name", "個人評量測試卷1" } });
  2488. foreach (Dictionary<string, string> sourcePaperInfoDic in sourcePaperDic)
  2489. {
  2490. string targetScope = "private";
  2491. var sourceBlobContainer = _azureStorage.GetBlobContainerClient(sourcePaperInfoDic["blobContainer"]);
  2492. string sourceBlobPath = (!sourcePaperInfoDic["blob"].EndsWith("/")) ? sourcePaperInfoDic["blob"] + "/" : sourcePaperInfoDic["blob"];
  2493. var destBlobContainer = _azureStorage.GetBlobContainerClient(tmid); //拷貝對象容器
  2494. string destBlobPath = $"/selflearn/{selfLearnT.id}/paper/{sourcePaperInfoDic["name"]}/";
  2495. Azure.Pageable<BlobItem> sourceBlobs = sourceBlobContainer.GetBlobs(prefix: sourceBlobPath);
  2496. if (sourceBlobs.Count() > 0)
  2497. {
  2498. foreach (var blob in sourceBlobs)
  2499. {
  2500. var sourceFileBlob = sourceBlobContainer.GetBlobClient(blob.Name);
  2501. if (sourceFileBlob.Exists())
  2502. {
  2503. var sourceFileUri = sourceBlobContainer.GetBlobClient(blob.Name).Uri;
  2504. string fileName = blob.Name.Replace(sourceBlobPath, "");
  2505. string destBlobFilePath = $"{destBlobPath}{fileName}";
  2506. await destBlobContainer.GetBlobClient(destBlobFilePath).StartCopyFromUriAsync(sourceFileUri);
  2507. }
  2508. }
  2509. }
  2510. }
  2511. //內容:評量 DB操作
  2512. PaperSimple paper = new PaperSimple()
  2513. {
  2514. id = "184914dd-05e0-04f4-e14a-cfce53545018",
  2515. subjectId = null,
  2516. code = "Paper-1595321354",
  2517. name = "個人評量測試卷1",
  2518. blob = $"/selflearn/{selfLearnT.id}/paper/個人評量測試卷1/",
  2519. scope = "private",
  2520. multipleRule = 1,
  2521. point = new List<double>() { 50, 50 }, //這裡和題庫的格式不同,需要轉換
  2522. answers = new List<List<string>>() { new List<string>() { "B" }, new List<string>() { "A" } }, //這裡和題庫的格式不同,需要轉換
  2523. type = new List<string>() { "single", "single" }, //這裡和題庫的格式不同,需要轉換
  2524. field = new List<int>() { 1, 1 } //認知層次 這裡須由各題的Blob中取得後轉換
  2525. };
  2526. paper.subjectId = selfLearnT.course.id;
  2527. ExamInfo examT = new ExamInfo();
  2528. examT.pk = "Exam";
  2529. examT.scope = "private";
  2530. examT.owner = "teacher";
  2531. examT.code = $"Exam-{tmid}";
  2532. examT.creatorId = $"{tmid}";
  2533. examT.name = "隨堂測驗1";
  2534. examT.papers.Add(paper);
  2535. selfLearnTContentExam.examInfo = examT;
  2536. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnTContentExam);
  2537. ////學校課程
  2538. //主體
  2539. SelfLearn selfLearnS = new SelfLearn();
  2540. selfLearnS.pk = "SelfLearn";
  2541. selfLearnS.code = $"SelfLearn-{tmid}";
  2542. selfLearnS.id = "f05f79f2-c58d-4e27-8214-48385e2ac3cd";
  2543. selfLearnS.scope = "private";
  2544. selfLearnS.school = "hbgl";
  2545. selfLearnS.name = "數學一年級上學期課綱";
  2546. selfLearnS.subject = new IdName();
  2547. selfLearnS.subject.id = "c5f96ea0-e65c-f15c-dc59-410da564c185";
  2548. selfLearnS.subject.name = "數學";
  2549. selfLearnS.period = new IdName();
  2550. selfLearnS.period.id = "127e71a7-0ca8-82b8-476b-5269b78066f7";
  2551. selfLearnS.period.name = "測試國中";
  2552. selfLearnS.course = new IdName();
  2553. selfLearnS.course.id = "0d4fa541-ad4f-bee1-c604-764275f6d10e";
  2554. selfLearnS.course.name = "數學一";
  2555. selfLearnS.creatorId = $"{tmid}";
  2556. selfLearnS.creatorName = "Miss Lo";
  2557. selfLearnS.release = true;
  2558. selfLearnS.classes.Add(new IdName { id = "d3090c56-21de-4cc8-a962-a7e7eaa2e913", name = "2023年A班" });
  2559. selfLearnS.groupLists.Add(new IdName { id = "54a39ec1-be0b-43cd-a978-f3133552f291", name = "七年A班" });
  2560. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnS);
  2561. //節點:章節
  2562. SelfLearnNode selfLearnNodeSChapter = new SelfLearnNode();
  2563. selfLearnNodeSChapter.code = $"SelfLearn-{tmid}";
  2564. selfLearnNodeSChapter.id = "77172663-aa17-44c6-8259-61870c44121f";
  2565. selfLearnNodeSChapter.name = "第一章節";
  2566. selfLearnNodeSChapter.selfLearnId = selfLearnS.id;
  2567. selfLearnNodeSChapter.nodeType = "chapter";
  2568. selfLearnNodeSChapter.openType = "order";
  2569. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnNodeSChapter);
  2570. //節點:項目
  2571. SelfLearnNode selfLearnNodeSContent = new SelfLearnNode();
  2572. selfLearnNodeSContent.code = $"SelfLearn-{tmid}";
  2573. selfLearnNodeSContent.id = "f28c6ecd-38a6-4edb-9160-363a116b8c3b";
  2574. selfLearnNodeSContent.name = "四則運算";
  2575. selfLearnNodeSContent.selfLearnId = selfLearnS.id;
  2576. selfLearnNodeSContent.selfLearnNodeId = selfLearnNodeSChapter.id;
  2577. selfLearnNodeSContent.nodeType = "content";
  2578. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnNodeSContent);
  2579. //內容:作業
  2580. SelfLearnContentHomework selfLearnSContentHomework = new SelfLearnContentHomework();
  2581. selfLearnSContentHomework.code = $"SelfLearn-{tmid}";
  2582. //內容:評量
  2583. SelfLearnContentExam selfLearnSContentExam = new SelfLearnContentExam();
  2584. selfLearnSContentExam.code = $"SelfLearn-{tmid}";
  2585. selfLearnSContentExam.id = "3f088f49-fefa-4af5-a324-c577ffb6d1f8";
  2586. selfLearnSContentExam.name = "隨堂測驗1";
  2587. selfLearnSContentExam.selfLearnId = selfLearnS.id;
  2588. selfLearnSContentExam.selfLearnNodeId = selfLearnNodeSContent.id;
  2589. selfLearnSContentExam.contentType = "exam";
  2590. //自主課綱試卷拷貝到課綱
  2591. foreach (Dictionary<string, string> sourcePaperInfoDic in sourcePaperDic)
  2592. {
  2593. string targetScope = "private";
  2594. var sourceBlobContainer = _azureStorage.GetBlobContainerClient(sourcePaperInfoDic["blobContainer"]);
  2595. string sourceBlobPath = (!sourcePaperInfoDic["blob"].EndsWith("/")) ? sourcePaperInfoDic["blob"] + "/" : sourcePaperInfoDic["blob"];
  2596. var destBlobContainer = _azureStorage.GetBlobContainerClient(tmid); //拷貝對象容器
  2597. string destBlobPath = $"/selflearn/{selfLearnS.id}/paper/{sourcePaperInfoDic["name"]}/";
  2598. Azure.Pageable<BlobItem> sourceBlobs = sourceBlobContainer.GetBlobs(prefix: sourceBlobPath);
  2599. if (sourceBlobs.Count() > 0)
  2600. {
  2601. foreach (var blob in sourceBlobs)
  2602. {
  2603. var sourceFileBlob = sourceBlobContainer.GetBlobClient(blob.Name);
  2604. if (sourceFileBlob.Exists())
  2605. {
  2606. var sourceFileUri = sourceBlobContainer.GetBlobClient(blob.Name).Uri;
  2607. string fileName = blob.Name.Replace(sourceBlobPath, "");
  2608. string destBlobFilePath = $"{destBlobPath}{fileName}";
  2609. await destBlobContainer.GetBlobClient(destBlobFilePath).StartCopyFromUriAsync(sourceFileUri);
  2610. }
  2611. }
  2612. }
  2613. }
  2614. paper.blob = $"/selflearn/{selfLearnS.id}/paper/個人評量測試卷1/";
  2615. ExamInfo examS = new ExamInfo();
  2616. examS.pk = "Exam";
  2617. examS.scope = "school";
  2618. examS.owner = "teacher";
  2619. examS.code = $"Exam-{tmid}";
  2620. examS.creatorId = $"{tmid}";
  2621. examS.name = "隨堂測驗1";
  2622. examS.papers.Add(paper);
  2623. selfLearnSContentExam.examInfo = examS;
  2624. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(selfLearnSContentExam);
  2625. return Ok();
  2626. }
  2627. //自主學習綱領 生成評量架構測試
  2628. [HttpPost("test-selflearn-create-exam")]
  2629. public async void TestSelfLearnCreateExam(JsonElement json)
  2630. {
  2631. //輸入項:startTime (-1 會以現在時間記入)
  2632. long startTime = (json.TryGetProperty("startTime", out JsonElement startTimeJ)) ? startTimeJ.GetInt64() : -1;
  2633. var client = _azureCosmos.GetCosmosClient();
  2634. string tmid = "1595321354";
  2635. long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  2636. string code = string.Empty;
  2637. string selfLearnContentExamId = string.Empty;
  2638. SelfLearn selfLearn = new SelfLearn();
  2639. SelfLearnContentExam contentExam = new SelfLearnContentExam();
  2640. //[個人評量學校課程]
  2641. code = $"SelfLearn-{tmid}";
  2642. selfLearnContentExamId = "3f088f49-fefa-4af5-a324-c577ffb6d1f8"; //個人評量學校班級
  2643. contentExam = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<SelfLearnContentExam>(selfLearnContentExamId, new PartitionKey(code));
  2644. if (contentExam != null)
  2645. {
  2646. string selfLearnId = contentExam.selfLearnId;
  2647. selfLearn = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<SelfLearn>(selfLearnId, new PartitionKey(code));
  2648. }
  2649. if (!string.IsNullOrWhiteSpace(selfLearn.id))
  2650. {
  2651. //評量的架構只能生成 編制班(複數班) OR 選課班(複數班) 擇一,如果同步對象有編制班也有選課班,需生成兩個評量活動
  2652. int examCount = 0;
  2653. if (selfLearn.classes.Count > 0) examCount++;
  2654. if (selfLearn.groupLists.Count > 0) examCount++;
  2655. List<string> actExamInfoId = new List<string>() { "dbdcddc5-a79e-400f-a0b9-42801b176c21", "0c02b5e7-1aea-4126-b872-10baa2b4db56" };
  2656. for (int i = 0; i < examCount; i++)
  2657. {
  2658. string contentExamJsonStr = System.Text.Json.JsonSerializer.Serialize<ExamInfo>(contentExam.examInfo);
  2659. ExamInfo actExamInfo = System.Text.Json.JsonSerializer.Deserialize<ExamInfo>(contentExamJsonStr); //要生成的Exam
  2660. actExamInfo.id = actExamInfoId[i]; //假設每次生成新的評量;實作的時候應該在Exam埋入自主課綱相關的ID,如果可取得此ID的評量則更新
  2661. actExamInfo.source = "0"; //目前先設定為"線上評量",實際上應讓老師選擇
  2662. actExamInfo.creatorId = tmid;
  2663. actExamInfo.year = DateTimeOffset.UtcNow.Year;
  2664. IdName selfLearnSubject = selfLearn.subject;
  2665. IdName selfLearnCourse = selfLearn.course;
  2666. IdName selfLearnPeriod = selfLearn.period;
  2667. if (contentExam.examInfo.scope.Equals("school")) //學校 編制班、選課班 ※編制班、選課班無法共存只能擇一
  2668. {
  2669. actExamInfo.school = selfLearn.school;
  2670. actExamInfo.period.id = selfLearnPeriod.id;
  2671. actExamInfo.period.name = selfLearnPeriod.name;
  2672. actExamInfo.subjects.Add(new ExamSubject() { id = selfLearnSubject.id, name = selfLearnSubject.name });
  2673. if (actExamInfo.id.Equals("dbdcddc5-a79e-400f-a0b9-42801b176c21")) //編制班
  2674. {
  2675. foreach (IdName classRow in selfLearn.classes)
  2676. {
  2677. actExamInfo.classes.Add(classRow.id);
  2678. List<string> targetRow = new List<string>() { $"{selfLearn.course.id}", "class", classRow.id };
  2679. actExamInfo.targets.Add(System.Text.Json.JsonSerializer.SerializeToElement(targetRow));
  2680. }
  2681. }
  2682. else if (actExamInfo.id.Equals("0c02b5e7-1aea-4126-b872-10baa2b4db56")) //選課班
  2683. {
  2684. foreach (IdName groupRow in selfLearn.groupLists)
  2685. {
  2686. actExamInfo.stuLists.Add(groupRow.id);
  2687. List<string> targetRow = new List<string>() { $"{selfLearn.course.id}", "teach", groupRow.id };
  2688. actExamInfo.targets.Add(System.Text.Json.JsonSerializer.SerializeToElement(targetRow));
  2689. }
  2690. }
  2691. }
  2692. else if (contentExam.examInfo.scope.Equals("private"))
  2693. {
  2694. foreach (IdName groupRow in selfLearn.groupLists)
  2695. {
  2696. actExamInfo.subjects.Add(new ExamSubject() { id = selfLearn.course.id, name = selfLearn.course.name });
  2697. actExamInfo.stuLists.Add(groupRow.id);
  2698. List<string> targetRow = new List<string>() { $"{selfLearn.course.id}", groupRow.id };
  2699. actExamInfo.targets.Add(System.Text.Json.JsonSerializer.SerializeToElement(targetRow));
  2700. }
  2701. }
  2702. //以下是Blob拷貝程序
  2703. //ExamInfo內容取得、調整
  2704. //※規則 owner:"school" => 校園評測 "teacher" => 個人評測
  2705. //※規則 scope:"school" => 校本班級 "private" => 個人班級
  2706. //※規則 BLOB容器: scope:"school" => {學校ID}下 scope:"private" => {個人ID}下
  2707. //試卷情報字典
  2708. string paperSubjectId = actExamInfo.subjects.First().id;
  2709. List<Dictionary<string, string>> sourcePaperInfo = new List<Dictionary<string, string>>();
  2710. foreach (PaperSimple paperInfo in contentExam.examInfo.papers)
  2711. {
  2712. string paperBlobPath = (!paperInfo.blob.EndsWith("/")) ? paperInfo.blob + "/" : paperInfo.blob;
  2713. paperBlobPath = (paperInfo.blob.StartsWith("/")) ? paperBlobPath.Remove(0, 1) : paperBlobPath;
  2714. string paperBlobContainer = tmid;
  2715. sourcePaperInfo.Add(new Dictionary<string, string>() { { "id", paperInfo.id }, { "blobContainer", paperBlobContainer }, { "subjectId", paperSubjectId }, { "blob", paperBlobPath } });
  2716. }
  2717. //取得自主課綱下的試卷資料(blob)、複製到評測紀錄下
  2718. //Blob搬運
  2719. int paperIndex = 0;
  2720. foreach (Dictionary<string, string> recordPaperInfoDic in sourcePaperInfo)
  2721. {
  2722. string targetScope = actExamInfo.scope; //評測對象 school:校本班級 private:私人課程
  2723. var sourceBlobContainer = _azureStorage.GetBlobContainerClient(recordPaperInfoDic["blobContainer"]);
  2724. string sourceBlobPath = recordPaperInfoDic["blob"];
  2725. string destBlobContainerId = (!string.IsNullOrWhiteSpace(actExamInfo.school) && actExamInfo.scope.Equals("school")) ? actExamInfo.school : actExamInfo.creatorId;
  2726. var destBlobContainer = _azureStorage.GetBlobContainerClient(destBlobContainerId); //拷貝對象容器
  2727. string destBlobPath = $"exam/{actExamInfo.id}/paper/{recordPaperInfoDic["subjectId"]}"; //拷貝對象路徑 path:exam/{評測ID}/paper/{subjectID}/ ※2022-1-6 式樣變更[原]/paper/{試卷ID}/ [新]/paper/{subjectID}/
  2728. Azure.Pageable<BlobItem> sourceBlobs = sourceBlobContainer.GetBlobs(prefix: sourceBlobPath);
  2729. if (sourceBlobs.Count() > 0)
  2730. {
  2731. foreach (var blob in sourceBlobs)
  2732. {
  2733. var sourceFileBlob = sourceBlobContainer.GetBlobClient(blob.Name);
  2734. if (sourceFileBlob.Exists())
  2735. {
  2736. var sourceFileUri = sourceBlobContainer.GetBlobClient(blob.Name).Uri;
  2737. string fileName = blob.Name.Replace(sourceBlobPath, "");
  2738. string destBlobFilePath = $"{destBlobPath}/{fileName}";
  2739. await destBlobContainer.GetBlobClient(destBlobFilePath).StartCopyFromUriAsync(sourceFileUri);
  2740. }
  2741. }
  2742. }
  2743. actExamInfo.papers[paperIndex].blob = destBlobPath;
  2744. actExamInfo.papers[paperIndex].subjectId = selfLearnSubject.id;
  2745. paperIndex++;
  2746. }
  2747. //以下是ExamController生成評量邏輯
  2748. actExamInfo.createTime = now;
  2749. actExamInfo.startTime = startTime;
  2750. if (actExamInfo.startTime <= 0) actExamInfo.startTime = now;
  2751. actExamInfo.endTime = actExamInfo.startTime + 172800000; //結束時間設為2天後 ※實際上應由老師設定
  2752. List<string> classes = ExamService.getClasses(actExamInfo.classes, actExamInfo.stuLists);
  2753. (List<RMember> tchList, List<RGroupList> classLists) = await GroupListService.GetMemberByListids(_coreAPIHttpService, client, _dingDing, classes, selfLearn.school);
  2754. actExamInfo.stuCount = tchList.Count;
  2755. actExamInfo.progress = (actExamInfo.startTime > now) ? "pending" : "going";
  2756. var messageBlob = new ServiceBusMessage();
  2757. if (actExamInfo.scope.Equals("school"))
  2758. {
  2759. actExamInfo.size = await _azureStorage.GetBlobContainerClient(actExamInfo.school).GetBlobsSize($"exam/{actExamInfo.id}");
  2760. await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "insert", root = $"exam", name = actExamInfo.school }, _serviceBus, _configuration, _azureRedis);
  2761. }
  2762. else
  2763. {
  2764. string schoolId = string.Empty; //看學生是否有屬於學校,如果有則填入學校ID
  2765. foreach (RMember stuInfo in tchList)
  2766. {
  2767. if (!string.IsNullOrWhiteSpace(stuInfo.schoolId) && string.IsNullOrWhiteSpace(schoolId)) schoolId = stuInfo.schoolId;
  2768. }
  2769. actExamInfo.school = (!string.IsNullOrWhiteSpace(schoolId)) ? schoolId : "SYSTEM_NO_SCHOOL";
  2770. actExamInfo.size = await _azureStorage.GetBlobContainerClient(actExamInfo.creatorId).GetBlobsSize($"exam/{actExamInfo.id}");
  2771. await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "insert", root = $"exam", name = actExamInfo.creatorId }, _serviceBus, _configuration, _azureRedis);
  2772. }
  2773. int n = 0;
  2774. List<string> sheetIds = new List<string>();
  2775. foreach (PaperSimple simple in actExamInfo.papers)
  2776. {
  2777. simple.blob = $"/exam/{actExamInfo.id}/paper/{actExamInfo.subjects[n].id}";
  2778. n++;
  2779. simple.sheet = null;
  2780. }
  2781. ExamInfo exam = await client.GetContainer(Constant.TEAMModelOS, "Common").UpsertItemAsync(actExamInfo, new PartitionKey($"{actExamInfo.code}"));
  2782. await BIStats.SetTypeAddStats(client, _dingDing, exam.school, "Exam", 1);//BI统计增/减量
  2783. }
  2784. }
  2785. //[個人評量個人課程]
  2786. //取得自主學習綱領內容、自主學習綱領主體
  2787. code = $"SelfLearn-{tmid}";
  2788. selfLearnContentExamId = "07e6fdd2-6083-4eb6-ac6d-06421edb0b48"; //個人評量個人課程
  2789. contentExam = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<SelfLearnContentExam>(selfLearnContentExamId, new PartitionKey(code));
  2790. if (contentExam != null)
  2791. {
  2792. string selfLearnId = contentExam.selfLearnId;
  2793. selfLearn = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<SelfLearn>(selfLearnId, new PartitionKey(code));
  2794. }
  2795. if(!string.IsNullOrWhiteSpace(selfLearn.id))
  2796. {
  2797. //補足實體化需要項目
  2798. //targets.row:
  2799. //個人課程: [0]:課程ID(CourseBase.id)[1]stuListId(GroupList.id)
  2800. //學校課程 編制班[0]:課程ID(CourseBase.id)[1]"class"[2]classId
  2801. //學校課程 選課班[0]:課程ID(CourseBase.id)[1]"teach"[2]stuListId(GroupList.id)
  2802. string contentExamJsonStr = System.Text.Json.JsonSerializer.Serialize<ExamInfo>(contentExam.examInfo);
  2803. ExamInfo actExamInfo = System.Text.Json.JsonSerializer.Deserialize<ExamInfo>(contentExamJsonStr); //要生成的Exam
  2804. actExamInfo.id = "78c4232d-b716-40a7-9901-c85b73da79a2"; //假設每次生成新的評量;實作的時候應該在Exam埋入自主課綱相關的ID,如果可取得此ID的評量則更新
  2805. actExamInfo.source = "0"; //目前先設定為"線上評量",實際上應讓老師選擇
  2806. actExamInfo.creatorId = tmid;
  2807. actExamInfo.year = DateTimeOffset.UtcNow.Year;
  2808. IdName selfLearnSubject = selfLearn.subject;
  2809. IdName selfLearnCourse = selfLearn.course;
  2810. IdName selfLearnPeriod = selfLearn.period;
  2811. if (contentExam.examInfo.scope.Equals("school")) //學校 編制班、選課班
  2812. {
  2813. actExamInfo.school = selfLearn.school;
  2814. actExamInfo.period.id = selfLearnPeriod.id;
  2815. actExamInfo.period.name = selfLearnPeriod.name;
  2816. actExamInfo.subjects.Add(new ExamSubject() { id = selfLearnSubject.id, name = selfLearnSubject.name });
  2817. foreach(IdName classRow in selfLearn.classes)
  2818. {
  2819. actExamInfo.classes.Add(classRow.id);
  2820. List<string> targetRow = new List<string>() { $"{selfLearn.course.id}", "class", classRow.id };
  2821. actExamInfo.targets.Add(System.Text.Json.JsonSerializer.SerializeToElement(targetRow));
  2822. }
  2823. foreach (IdName groupRow in selfLearn.groupLists)
  2824. {
  2825. actExamInfo.stuLists.Add(groupRow.id);
  2826. List<string> targetRow = new List<string>() { $"{selfLearn.course.id}", "teach", groupRow.id };
  2827. actExamInfo.targets.Add(System.Text.Json.JsonSerializer.SerializeToElement(targetRow));
  2828. }
  2829. }
  2830. else if(contentExam.examInfo.scope.Equals("private"))
  2831. {
  2832. foreach (IdName groupRow in selfLearn.groupLists)
  2833. {
  2834. actExamInfo.subjects.Add(new ExamSubject() { id = selfLearn.course.id, name = selfLearn.course.name });
  2835. actExamInfo.stuLists.Add(groupRow.id);
  2836. List<string> targetRow = new List<string>() { $"{selfLearn.course.id}", groupRow.id };
  2837. actExamInfo.targets.Add(System.Text.Json.JsonSerializer.SerializeToElement(targetRow));
  2838. }
  2839. }
  2840. //以下是Blob拷貝程序
  2841. //ExamInfo內容取得、調整
  2842. //※規則 owner:"school" => 校園評測 "teacher" => 個人評測
  2843. //※規則 scope:"school" => 校本班級 "private" => 個人班級
  2844. //※規則 BLOB容器: scope:"school" => {學校ID}下 scope:"private" => {個人ID}下
  2845. //試卷情報字典
  2846. string paperSubjectId = actExamInfo.subjects.First().id;
  2847. List <Dictionary<string, string>> sourcePaperInfo = new List<Dictionary<string, string>>();
  2848. foreach (PaperSimple paperInfo in contentExam.examInfo.papers)
  2849. {
  2850. string paperBlobPath = (!paperInfo.blob.EndsWith("/")) ? paperInfo.blob + "/" : paperInfo.blob;
  2851. paperBlobPath = (paperInfo.blob.StartsWith("/")) ? paperBlobPath.Remove(0, 1) : paperBlobPath;
  2852. string paperBlobContainer = tmid;
  2853. sourcePaperInfo.Add(new Dictionary<string, string>() { { "id", paperInfo.id }, { "blobContainer", paperBlobContainer }, { "subjectId", paperSubjectId }, { "blob", paperBlobPath } });
  2854. }
  2855. //取得自主課綱下的試卷資料(blob)、複製到評測紀錄下
  2856. //Blob搬運
  2857. int paperIndex = 0;
  2858. foreach (Dictionary<string, string> recordPaperInfoDic in sourcePaperInfo)
  2859. {
  2860. string targetScope = actExamInfo.scope; //評測對象 school:校本班級 private:私人課程
  2861. var sourceBlobContainer = _azureStorage.GetBlobContainerClient(recordPaperInfoDic["blobContainer"]);
  2862. string sourceBlobPath = recordPaperInfoDic["blob"];
  2863. string destBlobContainerId = (!string.IsNullOrWhiteSpace(actExamInfo.school) && actExamInfo.scope.Equals("school")) ? actExamInfo.school : actExamInfo.creatorId;
  2864. var destBlobContainer = _azureStorage.GetBlobContainerClient(destBlobContainerId); //拷貝對象容器
  2865. string destBlobPath = $"exam/{actExamInfo.id}/paper/{recordPaperInfoDic["subjectId"]}"; //拷貝對象路徑 path:exam/{評測ID}/paper/{subjectID}/ ※2022-1-6 式樣變更[原]/paper/{試卷ID}/ [新]/paper/{subjectID}/
  2866. Azure.Pageable<BlobItem> sourceBlobs = sourceBlobContainer.GetBlobs(prefix: sourceBlobPath);
  2867. if (sourceBlobs.Count() > 0)
  2868. {
  2869. foreach (var blob in sourceBlobs)
  2870. {
  2871. var sourceFileBlob = sourceBlobContainer.GetBlobClient(blob.Name);
  2872. if (sourceFileBlob.Exists())
  2873. {
  2874. var sourceFileUri = sourceBlobContainer.GetBlobClient(blob.Name).Uri;
  2875. string fileName = blob.Name.Replace(sourceBlobPath, "");
  2876. string destBlobFilePath = $"{destBlobPath}/{fileName}";
  2877. await destBlobContainer.GetBlobClient(destBlobFilePath).StartCopyFromUriAsync(sourceFileUri);
  2878. }
  2879. }
  2880. }
  2881. actExamInfo.papers[paperIndex].blob = destBlobPath;
  2882. actExamInfo.papers[paperIndex].subjectId = selfLearn.course.id;
  2883. paperIndex++;
  2884. }
  2885. //以下是ExamController生成評量邏輯
  2886. actExamInfo.createTime = now;
  2887. actExamInfo.startTime = startTime;
  2888. if (actExamInfo.startTime <= 0) actExamInfo.startTime = now;
  2889. actExamInfo.endTime = actExamInfo.startTime + 172800000; //結束時間設為2天後 ※實際上應由老師設定
  2890. List<string> classes = ExamService.getClasses(actExamInfo.classes, actExamInfo.stuLists);
  2891. (List<RMember> tchList, List<RGroupList> classLists) = await GroupListService.GetMemberByListids(_coreAPIHttpService, client, _dingDing, classes, selfLearn.school);
  2892. actExamInfo.stuCount = tchList.Count;
  2893. actExamInfo.progress = (actExamInfo.startTime > now) ? "pending" : "going";
  2894. var messageBlob = new ServiceBusMessage();
  2895. if (actExamInfo.scope.Equals("school"))
  2896. {
  2897. actExamInfo.size = await _azureStorage.GetBlobContainerClient(actExamInfo.school).GetBlobsSize($"exam/{actExamInfo.id}");
  2898. await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "insert", root = $"exam", name = actExamInfo.school }, _serviceBus, _configuration, _azureRedis);
  2899. }
  2900. else
  2901. {
  2902. string schoolId = string.Empty; //看學生是否有屬於學校,如果有則填入學校ID
  2903. foreach (RMember stuInfo in tchList)
  2904. {
  2905. if (!string.IsNullOrWhiteSpace(stuInfo.schoolId) && string.IsNullOrWhiteSpace(schoolId)) schoolId = stuInfo.schoolId;
  2906. }
  2907. actExamInfo.school = (!string.IsNullOrWhiteSpace(schoolId)) ? schoolId: "SYSTEM_NO_SCHOOL";
  2908. actExamInfo.size = await _azureStorage.GetBlobContainerClient(actExamInfo.creatorId).GetBlobsSize($"exam/{actExamInfo.id}");
  2909. await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "insert", root = $"exam", name = actExamInfo.creatorId }, _serviceBus, _configuration, _azureRedis);
  2910. }
  2911. int n = 0;
  2912. List<string> sheetIds = new List<string>();
  2913. foreach (PaperSimple simple in actExamInfo.papers)
  2914. {
  2915. simple.blob = $"/exam/{actExamInfo.id}/paper/{actExamInfo.subjects[n].id}";
  2916. n++;
  2917. simple.sheet = null;
  2918. }
  2919. ExamInfo exam = await client.GetContainer(Constant.TEAMModelOS, "Common").UpsertItemAsync(actExamInfo, new PartitionKey($"{actExamInfo.code}"));
  2920. await BIStats.SetTypeAddStats(client, _dingDing, exam.school, "Exam", 1);//BI统计增/减量
  2921. }
  2922. }
  2923. */
  2924. //統測資料架構生成測試
  2925. /*
  2926. [HttpPost("add-joint-exam")]
  2927. public async Task<IActionResult> AddJointExam(JsonElement json)
  2928. {
  2929. var client = _azureCosmos.GetCosmosClient();
  2930. JointExam jointExam = new JointExam();
  2931. jointExam.code = "JointExam";
  2932. jointExam.id = "daaa3965-db28-49ae-8074-c9d4865b62ad";
  2933. jointExam.creatorId = "1595321354";
  2934. jointExam.name = "統測測試(一)";
  2935. jointExam.scope = "private";
  2936. //課程列表
  2937. ////課程1: [1595321354]"courseId": "e1d817e5-71b3-bc50-52ac-fa828e5f38d6", "groupId": "4dd434a8-a94a-4373-9a05-1a1add533a71",
  2938. JointExam.JointExamGroup jointExamGroup1 = new JointExam.JointExamGroup();
  2939. jointExamGroup1.creatorId = "1595321354";
  2940. JointExam.JointExamGroup.JointExamGroupCourse jointExamGroupCourse1 = new JointExam.JointExamGroup.JointExamGroupCourse();
  2941. jointExamGroupCourse1.courseId = "e1d817e5-71b3-bc50-52ac-fa828e5f38d6";
  2942. jointExamGroupCourse1.courseName = "test";
  2943. jointExamGroupCourse1.groupListIds.Add("4dd434a8-a94a-4373-9a05-1a1add533a71");
  2944. jointExamGroup1.courseLists.Add(jointExamGroupCourse1);
  2945. jointExam.groupLists.Add(jointExamGroup1);
  2946. ////課程2: [1522758684]"courseId": "424eb44d-8904-4e34-bfaf-e138f8e369cb", "groupId": "5bf63f35-f82f-432e-9b78-a4f38b5edb81",
  2947. JointExam.JointExamGroup jointExamGroup2 = new JointExam.JointExamGroup();
  2948. jointExamGroup2.creatorId = "1522758684";
  2949. JointExam.JointExamGroup.JointExamGroupCourse jointExamGroupCourse2 = new JointExam.JointExamGroup.JointExamGroupCourse();
  2950. jointExamGroupCourse2.courseId = "424eb44d-8904-4e34-bfaf-e138f8e369cb";
  2951. jointExamGroupCourse2.courseName = "1522758684個人課程";
  2952. jointExamGroupCourse2.groupListIds.Add("5bf63f35-f82f-432e-9b78-a4f38b5edb81");
  2953. jointExamGroup2.courseLists.Add(jointExamGroupCourse2);
  2954. jointExam.groupLists.Add(jointExamGroup2);
  2955. //試卷
  2956. ///STEP1 Blob拷貝 ※此步驟由前端做
  2957. ///拷貝目標:{TMID/SchoolId}/jointexam/{jointExam.id}/paper/{paperId}
  2958. string paperSourceBlobPath = "paper/語文理解";
  2959. string paperSourceBlobContainer = "tbslgb";
  2960. string paperSourceScope = "school";
  2961. var paperSourceBlobContainerClient = _azureStorage.GetBlobContainerClient(paperSourceBlobContainer);
  2962. string paperId = "1c6a1e85-4b34-b8af-00de-a379bc47a26c";
  2963. string paperTargetBlobPath = $"jointexam/{jointExam.id}/paper/{paperId}";
  2964. string paperTargetBlobContainer = jointExam.creatorId;
  2965. var paperTargetBlobContainerClient = _azureStorage.GetBlobContainerClient(paperTargetBlobContainer);
  2966. Pageable<BlobItem> sourceBlobs = paperSourceBlobContainerClient.GetBlobs(prefix: paperSourceBlobPath);
  2967. if (sourceBlobs.Count() > 0)
  2968. {
  2969. foreach (var blob in sourceBlobs)
  2970. {
  2971. var sourceFileBlob = paperSourceBlobContainerClient.GetBlobClient(blob.Name);
  2972. if (sourceFileBlob.Exists())
  2973. {
  2974. var sourceFileUri = paperSourceBlobContainerClient.GetBlobClient(blob.Name).Uri;
  2975. string fileName = blob.Name.Replace(paperSourceBlobPath, "");
  2976. string destBlobFilePath = $"{paperTargetBlobPath}{fileName}";
  2977. await paperTargetBlobContainerClient.GetBlobClient(destBlobFilePath).StartCopyFromUriAsync(sourceFileUri);
  2978. }
  2979. else
  2980. {
  2981. bool paperDataCopyErrFlg = true;
  2982. }
  2983. }
  2984. }
  2985. ///STEP2 document製作
  2986. PaperSimple paper = new PaperSimple() { id= paperId , code = "Paper-tbslgb", name = "語文理解", blob = $"/{paperTargetBlobPath}", scope = "school", multipleRule = 1, point = new List<double>() { 50, 50}, answers = new List<List<string>>() { new List<string>() { "D" }, new List<string>() { "D" } }, knowledge = new List<List<string>>(), type = new List<string>() { "single","single"}, field=new List<int>() { 2, 2 } };
  2987. jointExam.papers.Add(paper);
  2988. //時間
  2989. jointExam.createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  2990. jointExam.startTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  2991. jointExam.endTime = DateTimeOffset.UtcNow.AddDays(2).ToUnixTimeMilliseconds();
  2992. jointExam.progress = "going";
  2993. await client.GetContainer(Constant.TEAMModelOS, "Common").UpsertItemAsync<JointExam>(jointExam, new PartitionKey("JointExam"));
  2994. return Ok();
  2995. }
  2996. */
  2997. //評量統一生成測試
  2998. /*
  2999. [HttpPost("add-exam-byJoint")]
  3000. public async Task<IActionResult> AddExamByJointExam(JsonElement json)
  3001. {
  3002. if (!json.TryGetProperty("jointExamId", out JsonElement _jointExamId)) return BadRequest();
  3003. var client = _azureCosmos.GetCosmosClient();
  3004. string tmid = "1595321354";
  3005. JointExam jointExam = new JointExam();
  3006. await foreach (JointExam item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<JointExam>(
  3007. queryText: $"select * from c where c.id = '{_jointExamId}' and c.creatorId = '{tmid}'",
  3008. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"JointExam") }))
  3009. {
  3010. jointExam = item;
  3011. }
  3012. if(string.IsNullOrWhiteSpace(jointExam.id))
  3013. {
  3014. return BadRequest();
  3015. }
  3016. //評量資料生成 ExamInfo actExamInfo
  3017. List<ExamInfo> examList = new List<ExamInfo>();
  3018. if(jointExam.groupLists.Count > 0)
  3019. {
  3020. foreach (JointExam.JointExamGroup jointExamGroup in jointExam.groupLists)
  3021. {
  3022. string actExamCreatorId = jointExamGroup.creatorId;
  3023. foreach(JointExam.JointExamGroup.JointExamGroupCourse jointExamGroupCourse in jointExamGroup.courseLists)
  3024. {
  3025. string actExamCourseId = jointExamGroupCourse.courseId;
  3026. string actExamCourseName = jointExamGroupCourse.courseName;
  3027. //評量資料生成
  3028. ExamInfo actExamInfo = new ExamInfo();
  3029. actExamInfo.code = $"Exam-{jointExamGroup.creatorId}";
  3030. actExamInfo.owner = "teacher";
  3031. actExamInfo.scope = jointExam.scope;
  3032. actExamInfo.creatorId = actExamCreatorId;
  3033. actExamInfo.id = Guid.NewGuid().ToString();
  3034. actExamInfo.source = "1"; //目前先設定為"智慧教室評量",實際上應讓老師選擇
  3035. actExamInfo.name = jointExam.name;
  3036. actExamInfo.jointExamId = jointExam.id;
  3037. ///評量stuLists
  3038. foreach (string actGroupId in jointExamGroupCourse.groupListIds)
  3039. {
  3040. actExamInfo.stuLists.Add(actGroupId);
  3041. List<string> targetRow = new List<string>() { actExamCourseId, actGroupId };
  3042. actExamInfo.targets.Add(System.Text.Json.JsonSerializer.SerializeToElement(targetRow));
  3043. actExamInfo.subjects.Add(new ExamSubject() { id = actExamCourseId, name = actExamCourseName });
  3044. }
  3045. ///試卷 ※先用統購的試卷記入,生成評量(generateExam)時會做blob的路徑修正
  3046. actExamInfo.papers = JsonConvert.DeserializeObject<List<PaperSimple>>(JsonConvert.SerializeObject(jointExam.papers));
  3047. ///時間
  3048. actExamInfo.year = DateTimeOffset.UtcNow.Year;
  3049. actExamInfo.startTime = jointExam.startTime;
  3050. actExamInfo.endTime = jointExam.endTime;
  3051. examList.Add(actExamInfo);
  3052. }
  3053. }
  3054. }
  3055. //生成評量
  3056. if(examList.Count > 0)
  3057. {
  3058. foreach(ExamInfo exam in examList)
  3059. {
  3060. await generateExam(jointExam, exam);
  3061. }
  3062. }
  3063. return Ok();
  3064. }
  3065. */
  3066. //生成評量(單)
  3067. /*
  3068. private async Task<string> generateExam(JointExam jointExam, ExamInfo exam)
  3069. {
  3070. var client = _azureCosmos.GetCosmosClient();
  3071. long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  3072. string Result = string.Empty;
  3073. exam.createTime = now;
  3074. if (exam.startTime <= 0) exam.startTime = now;
  3075. List<(string pId, List<string> gid)> ps = new();
  3076. var group = exam.groupLists;
  3077. if (group.Count > 0)
  3078. {
  3079. foreach (var keys in group)
  3080. {
  3081. foreach (KeyValuePair<string, List<string>> pp in keys)
  3082. {
  3083. ps.Add((pp.Key, pp.Value));
  3084. }
  3085. }
  3086. }
  3087. List<string> classes = ExamService.getClasses(exam.classes, exam.stuLists);
  3088. (List<RMember> tchList, List<RGroupList> classLists) = await GroupListService.GetMemberByListids(_coreAPIHttpService, client, _dingDing, classes, exam.school, ps);
  3089. exam.stuCount = tchList.Count;
  3090. string mode = string.Empty;
  3091. Response response = null;
  3092. if (string.IsNullOrEmpty(exam.id))
  3093. {
  3094. mode = "add";
  3095. }
  3096. else
  3097. {
  3098. response = await client.GetContainer("TEAMModelOS", "Common").ReadItemStreamAsync(exam.id, new PartitionKey($"{exam.code}"));
  3099. if (response.Status == 200) mode = "upd";
  3100. else mode = "add";
  3101. }
  3102. //DB操作
  3103. if (mode.Equals("add")) //新建
  3104. {
  3105. if(string.IsNullOrWhiteSpace(exam.id)) exam.id = Guid.NewGuid().ToString();
  3106. exam.progress = (exam.startTime > now) ? "pending" : "going";
  3107. var messageBlob = new ServiceBusMessage();
  3108. exam.size = await _azureStorage.GetBlobContainerClient(exam.creatorId).GetBlobsSize($"exam/{exam.id}"); //統測只允許老師個人,Blob只指向creatorId
  3109. await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "insert", root = $"exam", name = exam.creatorId }, _serviceBus, _configuration, _azureRedis);
  3110. int n = 0;
  3111. List<string> sheetIds = new List<string>();
  3112. foreach (PaperSimple simple in exam.papers)
  3113. {
  3114. simple.blob = $"/exam/{exam.id}/paper/{exam.subjects[n].id}";
  3115. n++;
  3116. simple.sheet = null;
  3117. }
  3118. exam = await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(exam, new PartitionKey($"{exam.code}"));
  3119. await BIStats.SetTypeAddStats(client, _dingDing, exam.school, "Exam", 1);//BI统计增/减量
  3120. }
  3121. else if(response != null) //更新
  3122. {
  3123. using var json = await JsonDocument.ParseAsync(response.ContentStream);
  3124. ExamInfo info = json.ToObject<ExamInfo>();
  3125. if (info.progress.Equals("going"))
  3126. {
  3127. Result = "活动正在进行中,无法修改";
  3128. }
  3129. var messageBlob = new ServiceBusMessage();
  3130. exam.size = await _azureStorage.GetBlobContainerClient(exam.creatorId).GetBlobsSize($"exam/{exam.id}");
  3131. await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "update", root = $"exam", name = exam.creatorId }, _serviceBus, _configuration, _azureRedis);
  3132. exam.progress = info.progress;
  3133. int n = 0;
  3134. foreach (PaperSimple simple in exam.papers)
  3135. {
  3136. simple.blob = "/exam/" + exam.id + "/paper/" + exam.subjects[n].id;
  3137. n++;
  3138. }
  3139. exam = await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(exam, exam.id, new PartitionKey($"{exam.code}"));
  3140. }
  3141. //Blob操作 ※取得試卷源(blob)、複製到評測紀錄下
  3142. ///試卷源字典
  3143. List<Dictionary<string, string>> sourcePaperInfo = new List<Dictionary<string, string>>();
  3144. foreach (PaperSimple paperInfo in jointExam.papers)
  3145. {
  3146. string paperBlobPath = (!paperInfo.blob.EndsWith("/")) ? paperInfo.blob + "/" : paperInfo.blob;
  3147. paperBlobPath = (paperInfo.blob.StartsWith("/")) ? paperBlobPath.Remove(0, 1) : paperBlobPath;
  3148. sourcePaperInfo.Add(new Dictionary<string, string>() { { "id", paperInfo.id }, { "blob", paperBlobPath }, { "itemcount", paperInfo.point.Count.ToString() } });
  3149. }
  3150. bool paperDataCopyErrFlg = false; //試卷資料拷貝錯誤Flag true:拷貝錯誤
  3151. //Blob拷貝程序
  3152. int paperIndex = 0;
  3153. foreach (Dictionary<string, string> sourcePaperInfoDic in sourcePaperInfo)
  3154. {
  3155. //拷貝源:Container => jointExam.creatorId Path:papers.blob
  3156. //拷貝對象:Container => exam.creatorId, Path:exam/{exam.id}/paper/{exam.subjects[paperIndex].id}/
  3157. string targetScope = exam.scope; //評測對象 school:校本班級 private:私人課程
  3158. var sourceBlobContainer = _azureStorage.GetBlobContainerClient(jointExam.creatorId);
  3159. var blobPrivateContainer = _azureStorage.GetBlobContainerClient(exam.creatorId);
  3160. string sourceBlobPath = sourcePaperInfoDic["blob"];
  3161. string subjectId = exam.subjects[paperIndex].id;
  3162. string destBlobPath = $"exam/{exam.id}/paper/{subjectId}/"; //拷貝對象路徑 path:exam/{評測ID}/paper/{subjectID}/
  3163. Pageable<BlobItem> sourceBlobs = sourceBlobContainer.GetBlobs(prefix: sourceBlobPath);
  3164. if (sourceBlobs.Count() > 0)
  3165. {
  3166. foreach (var blob in sourceBlobs)
  3167. {
  3168. var sourceFileBlob = sourceBlobContainer.GetBlobClient(blob.Name);
  3169. if (sourceFileBlob.Exists())
  3170. {
  3171. var sourceFileUri = sourceBlobContainer.GetBlobClient(blob.Name).Uri;
  3172. string fileName = blob.Name.Replace(sourceBlobPath, "");
  3173. string destBlobFilePath = $"{destBlobPath}{fileName}";
  3174. await blobPrivateContainer.GetBlobClient(destBlobFilePath).StartCopyFromUriAsync(sourceFileUri);
  3175. }
  3176. else
  3177. {
  3178. paperDataCopyErrFlg = true;
  3179. }
  3180. }
  3181. }
  3182. paperIndex++;
  3183. }
  3184. return Result;
  3185. }
  3186. */
  3187. //統測資料架構
  3188. /*
  3189. public class JointExam : CosmosEntity
  3190. {
  3191. public string creatorId { get; set; }
  3192. public string name { get; set; }
  3193. public List<JointExamClass> classes { get; set; } = new();
  3194. public List<JointExamGroup> groupLists { get; set; } = new();
  3195. public List<PaperSimple> papers { get; set; } = new();
  3196. public string progress { get; set; }
  3197. public long createTime { get; set; }
  3198. public long updateTime { get; set; }
  3199. public long startTime { get; set; }
  3200. public long endTime { get; set; }
  3201. public string scope { get; set; }
  3202. public class JointExamClass
  3203. {
  3204. public string school { get; set; }
  3205. public List<string> classIds { get; set; } = new();
  3206. }
  3207. public class JointExamGroup
  3208. {
  3209. public string creatorId { get; set; }
  3210. public List<JointExamGroupCourse> courseLists { get; set; } = new();
  3211. public class JointExamGroupCourse
  3212. {
  3213. public string courseId { get; set; }
  3214. public string courseName { get; set; }
  3215. public List<string> groupListIds { get; set; } = new();
  3216. }
  3217. }
  3218. }
  3219. */
  3220. }
  3221. }