|
@@ -35,6 +35,8 @@ using DocumentFormat.OpenXml.EMMA;
|
|
|
using Microsoft.Extensions.Options;
|
|
|
using TEAMModelOS.Models;
|
|
|
using Microsoft.AspNetCore.Razor.TagHelpers;
|
|
|
+using HtmlAgilityPack;
|
|
|
+using Azure.Storage.Blobs;
|
|
|
|
|
|
namespace TEAMModelOS.FunctionV4
|
|
|
{
|
|
@@ -108,10 +110,11 @@ namespace TEAMModelOS.FunctionV4
|
|
|
//处理科目信息
|
|
|
List<string> sub = new List<string>();
|
|
|
School sc = new();
|
|
|
- if (!string.IsNullOrEmpty(info.school) && !info.school.Equals("SYSTEM_NO_SCHOOL")) {
|
|
|
+ if (!string.IsNullOrEmpty(info.school) && !info.school.Equals("SYSTEM_NO_SCHOOL"))
|
|
|
+ {
|
|
|
sc = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(info.school, new Azure.Cosmos.PartitionKey("Base"));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
foreach (ExamSubject subject in info.subjects)
|
|
|
{
|
|
|
sub.Add(subject.id);
|
|
@@ -234,7 +237,7 @@ namespace TEAMModelOS.FunctionV4
|
|
|
|
|
|
using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
|
|
|
Class classroom = json.ToObject<Class>();
|
|
|
-
|
|
|
+
|
|
|
foreach (SDK.Models.Period period in sc.period)
|
|
|
{
|
|
|
if (period.id.Equals(classroom.periodId))
|
|
@@ -426,10 +429,11 @@ namespace TEAMModelOS.FunctionV4
|
|
|
int fno = 0;
|
|
|
try
|
|
|
{
|
|
|
+ SetLearnRecordContent(info, data, _azureStorage, _azureCosmos);
|
|
|
//用来判定是否完成评分
|
|
|
//bool isScore = true;
|
|
|
await resultStatus(client, examClassResults);
|
|
|
-
|
|
|
+
|
|
|
await Activity(_coreAPIHttpService, info, classes, client, _dingDing, sub, examClassResults);
|
|
|
foreach (ExamSubject subject in info.subjects)
|
|
|
{
|
|
@@ -461,14 +465,15 @@ namespace TEAMModelOS.FunctionV4
|
|
|
};
|
|
|
//作答合格率
|
|
|
var sta = examClassResults.SelectMany(x => x.status).ToList();
|
|
|
- /* var stus = examClassResults.SelectMany(x => x.studentIds).ToList();
|
|
|
- var stuScores = examClassResults.SelectMany(x => x.studentScores).ToList();*/
|
|
|
+ /* var stus = examClassResults.SelectMany(x => x.studentIds).ToList();
|
|
|
+ var stuScores = examClassResults.SelectMany(x => x.studentScores).ToList();*/
|
|
|
var ansCount = sta.Where(x => x == 0).ToList();
|
|
|
var persent = ansCount.Count * 1.0 / sta.Count * 100;
|
|
|
var period = sc.period.Where(x => x.id.Equals(info.period.id)).FirstOrDefault();
|
|
|
List<string> subjects = info.subjects.Select(x => x.id).ToList();
|
|
|
//获取学期信息
|
|
|
- if (null != period && persent >= 60 && !subjects.Contains("subject_painting") && !subjects.Contains("subject_music")) {
|
|
|
+ if (null != period && persent >= 60 && !subjects.Contains("subject_painting") && !subjects.Contains("subject_music"))
|
|
|
+ {
|
|
|
var (currSemester, studyYear, currSemesterDate, date, nextSemester) = SchoolService.GetSemester(period, info.startTime);
|
|
|
//获取学生信息
|
|
|
(List<RMember> rmembers, List<RGroupList> groups) = await GroupListService.GetMemberByListids(_coreAPIHttpService, client, _dingDing, info.classes, info.school);
|
|
@@ -487,7 +492,8 @@ namespace TEAMModelOS.FunctionV4
|
|
|
var ec = examClassResults.Where(c => c.studentIds.Contains(member.id)).ToList();
|
|
|
double scores = 0;
|
|
|
List<(string subjectId, double score)> subScore = new();
|
|
|
- foreach (var eclass in ec) {
|
|
|
+ foreach (var eclass in ec)
|
|
|
+ {
|
|
|
int index_stu = eclass.studentIds.IndexOf(member.id);
|
|
|
scores += eclass.sum[index_stu];
|
|
|
subScore.Add((eclass.subjectId, eclass.sum[index_stu]));
|
|
@@ -524,9 +530,9 @@ namespace TEAMModelOS.FunctionV4
|
|
|
|
|
|
portrait.students.Add(student);
|
|
|
}
|
|
|
- string location = $"{Environment.GetEnvironmentVariable("Option:Location")}";
|
|
|
+ string location = $"{Environment.GetEnvironmentVariable("Option:Location")}";
|
|
|
var (status, json) = await _httpTrigger.RequestHttpTrigger(portrait, location, "upsert-student-portrait");
|
|
|
- }
|
|
|
+ }
|
|
|
//PortraitStudent student = new();
|
|
|
//处理试卷活动结束统计账户信息
|
|
|
List<FMember> idList = await GroupListService.GetFinishMemberInfo(_coreAPIHttpService, client, _dingDing, info.school, info.classes, info.stuLists, null);
|
|
@@ -534,6 +540,7 @@ namespace TEAMModelOS.FunctionV4
|
|
|
|
|
|
await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync<ExamInfo>(info, info.id, new Azure.Cosmos.PartitionKey(info.code));
|
|
|
}
|
|
|
+ //SetLearnRecordContent(info, data, _azureStorage);
|
|
|
}
|
|
|
catch (Exception e)
|
|
|
{
|
|
@@ -555,6 +562,345 @@ namespace TEAMModelOS.FunctionV4
|
|
|
|
|
|
}
|
|
|
|
|
|
+ private static async Task SetLearnRecordContent(ExamInfo info, TriggerData data, AzureStorageFactory _azureStorage, AzureCosmosFactory _azureCosmos)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (info.papers.Count > 0)
|
|
|
+ {
|
|
|
+ // debug用
|
|
|
+ //if (info.id == "d1dc1417-eeb0-4b4c-b1b3-7e9f99c95087")
|
|
|
+ //{
|
|
|
+ //}
|
|
|
+
|
|
|
+ for (int i = 0; i < info.papers.Count; i++)
|
|
|
+ {// 每一個科目的試卷
|
|
|
+ string rootName = "";
|
|
|
+ //if (info.school == "SYSTEM_NO_SCHOOL")
|
|
|
+ if (info.scope == "private")
|
|
|
+ {// 未入校老師的評量
|
|
|
+ rootName = info.creatorId;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {// 如果有學校代碼
|
|
|
+ rootName = info.school;
|
|
|
+ }
|
|
|
+ if (_azureStorage.GetBlobContainerClient(rootName).GetBlobClient($"{info.papers[i].blob}/index.json").Exists())
|
|
|
+ {// 如果試卷的blob存在,再開始
|
|
|
+
|
|
|
+ BlobDownloadResult paperblobDownload = await _azureStorage.GetBlobContainerClient(rootName).GetBlobClient($"{info.papers[i].blob}/index.json").DownloadContentAsync();
|
|
|
+ PaperIndex paperIndex = paperblobDownload.Content.ToObjectFromJson<PaperIndex>();
|
|
|
+ List<LearnRecordItem> learnRecordItems = new();
|
|
|
+ StringBuilder sbsql = new StringBuilder($" SELECT * FROM c WHERE c.examId = '{info.id}' and c.pk = 'ExamClassResult' and c.subjectId = '{info.subjects[i].id}' ");
|
|
|
+
|
|
|
+ #region === 開始拼裝資料 ===
|
|
|
+ if (info.classes.Count > 0 || info.stuLists.Count > 0)
|
|
|
+ {
|
|
|
+ // 組合SQL
|
|
|
+ if (info.classes.Count > 0)
|
|
|
+ {// 按照classes取ans.json
|
|
|
+ sbsql.Append($" and ARRAY_CONTAINS({System.Text.Json.JsonSerializer.Serialize(info.classes)}, c.info.id)");
|
|
|
+ //sbsql.Append($" and c.info.id in (");
|
|
|
+ //foreach (var classes in info.classes)
|
|
|
+ //{// 組合所有classesid
|
|
|
+ // if (classes == info.classes[info.classes.Count - 1])
|
|
|
+ // {
|
|
|
+ // sbsql.Append($"'{classes}' )");
|
|
|
+ // }
|
|
|
+ // else
|
|
|
+ // {
|
|
|
+ // sbsql.Append($"'{classes}',");
|
|
|
+ // }
|
|
|
+ //}
|
|
|
+ }
|
|
|
+ else if (info.stuLists.Count > 0)
|
|
|
+ {
|
|
|
+ sbsql.Append($" and ARRAY_CONTAINS({System.Text.Json.JsonSerializer.Serialize(info.stuLists)}, c.info.id)");
|
|
|
+ //sbsql.Append($" and c.info.id in (");
|
|
|
+ //foreach (var stuLists in info.stuLists)
|
|
|
+ //{// 組合所有stuListsid
|
|
|
+ // if (stuLists == info.stuLists[info.stuLists.Count - 1])
|
|
|
+ // {
|
|
|
+ // sbsql.Append($"'{stuLists}' )");
|
|
|
+ // }
|
|
|
+ // else
|
|
|
+ // {
|
|
|
+ // sbsql.Append($"'{stuLists}',");
|
|
|
+ // }
|
|
|
+ //}
|
|
|
+ }
|
|
|
+ // 取學生答案及學生名單
|
|
|
+ var client = _azureCosmos.GetCosmosClient();
|
|
|
+ Dictionary<string, List<string>> stuDic = new Dictionary<string, List<string>>();
|
|
|
+ if (!string.IsNullOrWhiteSpace(info.school) && !stuDic.ContainsKey(info.school))
|
|
|
+ {
|
|
|
+ stuDic.Add(info.school, new List<string>());
|
|
|
+ }
|
|
|
+ List<StudentAnswers> studentAnswersList = new List<StudentAnswers>();
|
|
|
+ List<string> stuListForSql = new List<string>();
|
|
|
+ await foreach (var item in client.GetContainer(Constant.TEAMModelOS, Constant.Common).GetItemQueryIterator<StudentAnswers>(queryText: sbsql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{rootName}") }))
|
|
|
+ {
|
|
|
+ studentAnswersList.Add(item);
|
|
|
+ stuListForSql.Union(item.studentIds);
|
|
|
+ }
|
|
|
+ //取得學校的學生名單
|
|
|
+ if(!string.IsNullOrWhiteSpace(info.school))
|
|
|
+ {
|
|
|
+ StringBuilder stusql = new StringBuilder($" SELECT c.id FROM c WHERE c.pk = 'Base' AND ARRAY_CONTAINS({System.Text.Json.JsonSerializer.Serialize(stuListForSql)}, c.id)");
|
|
|
+ await foreach (var item in client.GetContainer(Constant.TEAMModelOS, Constant.Student).GetItemQueryIterator<string>(queryText: stusql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{info.school}") }))
|
|
|
+ {
|
|
|
+ stuDic[info.school].Add(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 按照取出的學生答案blob 對答案 組合資料
|
|
|
+ foreach (var studentAnswers in studentAnswersList)
|
|
|
+ {// 每一個班級
|
|
|
+ foreach (var studentAnswersBlob in studentAnswers.studentAnswers)
|
|
|
+ {// 每一個學生
|
|
|
+ if (studentAnswersBlob.Count > 0)
|
|
|
+ {// 有學生的答案才開始
|
|
|
+ if (_azureStorage.GetBlobContainerClient(rootName).GetBlobClient($"/exam/{studentAnswersBlob[0]}").Exists())
|
|
|
+ {// 如果blob存在才開始
|
|
|
+ BlobDownloadResult ansblobDownload = await _azureStorage.GetBlobContainerClient(rootName).GetBlobClient($"/exam/{studentAnswersBlob[0]}").DownloadContentAsync();
|
|
|
+ List<List<string>> ansList = JsonConvert.DeserializeObject<List<List<string>>>(ansblobDownload.Content.ToString());
|
|
|
+ // 從blob路徑取出學生id
|
|
|
+ string[] arr = studentAnswersBlob[0].Split('/');
|
|
|
+ string stuid = arr[arr.Length - 2];
|
|
|
+ #region ===StartExam 開始課堂===
|
|
|
+ LearnRecordItem LRItem_StartExam = new();
|
|
|
+ LRItem_StartExam.verb = "StartExam";
|
|
|
+ LRItem_StartExam.actor = getStuId(info.school, stuid, stuDic);
|
|
|
+ LRItem_StartExam.time = info.createTime;
|
|
|
+ LRItem_StartExam.ID = info.id;
|
|
|
+ LRItem_StartExam.Desc = info.name;
|
|
|
+ LRItem_StartExam.Correct = null;
|
|
|
+ LRItem_StartExam.Choices = null;
|
|
|
+ LRItem_StartExam.ExamQuesQty = info.papers[i].point.Count;
|
|
|
+ LRItem_StartExam.TotalScore = 0;
|
|
|
+ foreach (var pointItem in info.papers[i].point)
|
|
|
+ {
|
|
|
+ LRItem_StartExam.TotalScore = LRItem_StartExam.TotalScore + pointItem;
|
|
|
+ }
|
|
|
+ LRItem_StartExam.Success = null;
|
|
|
+ learnRecordItems.Add(LRItem_StartExam);
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region ===評量題目===
|
|
|
+ for (int j = 0; j < ansList.Count; j++)
|
|
|
+ {
|
|
|
+ #region === 判斷題型 ===
|
|
|
+ // 這五種題型才記錄
|
|
|
+ if (paperIndex.slides[j].type == "single" ||
|
|
|
+ paperIndex.slides[j].type == "multiple" ||
|
|
|
+ paperIndex.slides[j].type == "judge" ||
|
|
|
+ paperIndex.slides[j].type == "complete" ||
|
|
|
+ paperIndex.slides[j].type == "subjective")
|
|
|
+ {
|
|
|
+ LearnRecordItem learnRecordItem = new();
|
|
|
+ // 單選
|
|
|
+ if (paperIndex.slides[j].type == "single") { learnRecordItem.verb = "AnsSingle"; }
|
|
|
+ // 複選
|
|
|
+ if (paperIndex.slides[j].type == "multiple") { learnRecordItem.verb = "AnsMultiple"; }
|
|
|
+ // 是非
|
|
|
+ if (paperIndex.slides[j].type == "judge") { learnRecordItem.verb = "AnsJudge"; }
|
|
|
+ // 填充
|
|
|
+ if (paperIndex.slides[j].type == "complete") { learnRecordItem.verb = "AnsComplete"; }
|
|
|
+ // 問答
|
|
|
+ if (paperIndex.slides[j].type == "subjective") { learnRecordItem.verb = "AnsSubjective"; }
|
|
|
+ learnRecordItem.actor = getStuId(info.school, stuid, stuDic);
|
|
|
+ learnRecordItem.time = data.endTime;
|
|
|
+ string[] arrurlsingle = paperIndex.slides[j].url.Split('.');
|
|
|
+ learnRecordItem.ID = arrurlsingle[0];
|
|
|
+
|
|
|
+ #region === 設定Correct Choices Desc===
|
|
|
+ if (_azureStorage.GetBlobContainerClient(rootName).GetBlobClient($"{info.papers[i].blob}/{paperIndex.slides[j].url}").Exists())
|
|
|
+ {
|
|
|
+ BlobDownloadResult itemblobDownload = await _azureStorage.GetBlobContainerClient(rootName).GetBlobClient($"{info.papers[i].blob}/{paperIndex.slides[j].url}").DownloadContentAsync();
|
|
|
+ QuestionData questionData = itemblobDownload.Content.ToObjectFromJson<QuestionData>();
|
|
|
+ setCorrectChoices(questionData, learnRecordItem);
|
|
|
+ // 使用HtmlAgilityPack解析HTML
|
|
|
+ HtmlDocument doc = new HtmlDocument();
|
|
|
+ doc.LoadHtml(questionData.item[0].question);
|
|
|
+ // 先刪除所有<img>標籤
|
|
|
+ foreach (var imgNode in doc.DocumentNode.Descendants("img").ToArray())
|
|
|
+ {
|
|
|
+ imgNode.Remove();
|
|
|
+ }
|
|
|
+ // 再取純文字
|
|
|
+ learnRecordItem.Desc = doc.DocumentNode.InnerText;
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+ learnRecordItem.ExamQuesQty = null;
|
|
|
+ learnRecordItem.TotalScore = null;
|
|
|
+ learnRecordItem.Points = paperIndex.slides[j].scoring == null ? new List<string>() : paperIndex.slides[j].scoring.knowledge;
|
|
|
+ //比對答案
|
|
|
+ learnRecordItem.Success = paperIndex.slides[j].scoring == null ? null : (paperIndex.slides[j].scoring.ans.SequenceEqual(ansList[j]) ? true : false);
|
|
|
+ learnRecordItems.Add(learnRecordItem);
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region ===EndExam 結束課堂===
|
|
|
+ LearnRecordItem LRItem_EndExam = new();
|
|
|
+ LRItem_EndExam.verb = "EndExam";
|
|
|
+ LRItem_EndExam.actor = getStuId(info.school, stuid, stuDic);
|
|
|
+ LRItem_EndExam.time = info.endTime;
|
|
|
+ LRItem_EndExam.ID = info.id;
|
|
|
+ LRItem_EndExam.Desc = info.name;
|
|
|
+ LRItem_EndExam.Correct = null;
|
|
|
+ LRItem_EndExam.Choices = null;
|
|
|
+ LRItem_EndExam.ExamQuesQty = info.papers[i].point.Count;
|
|
|
+ LRItem_EndExam.TotalScore = 0;
|
|
|
+ foreach (var pointItem in info.papers[i].point)
|
|
|
+ {
|
|
|
+ LRItem_EndExam.TotalScore = LRItem_EndExam.TotalScore + pointItem;
|
|
|
+ }
|
|
|
+ LRItem_EndExam.Success = null;
|
|
|
+ learnRecordItems.Add(LRItem_EndExam);
|
|
|
+
|
|
|
+ #endregion
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ if (learnRecordItems.Count > 0)
|
|
|
+ {
|
|
|
+ #region 寫入blob
|
|
|
+ // 容器名称
|
|
|
+ string containerName = "twmoeld";
|
|
|
+
|
|
|
+ // 新文件的名称
|
|
|
+ string blobName = $"/{DateTime.Now.ToString("yyyyMMdd")}/{info.id}.json";
|
|
|
+
|
|
|
+ // 要上传的文件内容
|
|
|
+ string fileContent = Newtonsoft.Json.JsonConvert.SerializeObject(learnRecordItems);
|
|
|
+
|
|
|
+ // 获取容器引用
|
|
|
+ BlobContainerClient containerClient = _azureStorage.GetBlobContainerClient(containerName);
|
|
|
+
|
|
|
+ // 获取 Blob 客户端
|
|
|
+ BlobClient blobClient = containerClient.GetBlobClient(blobName);
|
|
|
+
|
|
|
+ // 将文件内容上传到 Blob
|
|
|
+ using (MemoryStream stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(fileContent)))
|
|
|
+ {
|
|
|
+ await blobClient.UploadAsync(stream, true);
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 取得學習紀錄的actor
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="learnRecordItem"></param>
|
|
|
+ /// <param name="school"></param>
|
|
|
+ /// <param name="stuid"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private static string getStuId(string school, string stuid, Dictionary<string, List<string>> stuDic)
|
|
|
+ {
|
|
|
+ if (!string.IsNullOrWhiteSpace(school) && stuDic.ContainsKey(school) && stuDic[school].Contains(stuid))
|
|
|
+ {// 校內帳號用組合的 "Base-hbgl,473891247381"
|
|
|
+ return $"Base-{school.Trim()},{stuid}";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {// 未入校老師的評量
|
|
|
+ return stuid;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private static void setCorrectChoices(QuestionData questionData, LearnRecordItem learnRecordItem)
|
|
|
+ {
|
|
|
+ #region === Correct Choices ===
|
|
|
+ #region === 是非題邏輯 ===
|
|
|
+ if (questionData.exercise.type == "judge" && questionData.exercise.answer.Count > 0)
|
|
|
+ {// 如果是是非題 正確答案要用true false的方式設定
|
|
|
+ if (questionData.exercise.answer[0] == "A")
|
|
|
+ {
|
|
|
+ learnRecordItem.Correct = true;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ learnRecordItem.Correct = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {// 防呆 去html標籤
|
|
|
+ if (questionData.exercise.answer.Count > 0)
|
|
|
+ {
|
|
|
+ List<string> anslist = new();
|
|
|
+ foreach (var answer in questionData.exercise.answer)
|
|
|
+ {
|
|
|
+ // 使用HtmlAgilityPack解析HTML
|
|
|
+ HtmlDocument doc = new HtmlDocument();
|
|
|
+ doc.LoadHtml(answer);
|
|
|
+ // 再取純文字
|
|
|
+ anslist.Add(doc.DocumentNode.InnerText);
|
|
|
+ }
|
|
|
+ learnRecordItem.Correct = anslist;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ learnRecordItem.Correct = questionData.exercise.answer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+ if (questionData.item[0].option.Count > 0)
|
|
|
+ {// 如果有選項資料 記錄起來
|
|
|
+ foreach (var option in questionData.item[0].option)
|
|
|
+ {
|
|
|
+ ChoicesItem item = new();
|
|
|
+ item.id = option.code;
|
|
|
+ if (questionData.exercise.type == "judge")
|
|
|
+ {// 如果是是非題 固定選項
|
|
|
+
|
|
|
+ if (option.code == "A")
|
|
|
+ {
|
|
|
+ item.description.zhTW = "是";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ item.description.zhTW = "否";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (string.IsNullOrWhiteSpace(option.value))
|
|
|
+ {
|
|
|
+ item.description.zhTW = $"選項{option.code}";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 使用HtmlAgilityPack解析HTML
|
|
|
+ HtmlDocument doc = new HtmlDocument();
|
|
|
+ doc.LoadHtml(option.value);
|
|
|
+ // 再取純文字
|
|
|
+ item.description.zhTW = doc.DocumentNode.InnerText;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ learnRecordItem.Choices.Add(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+ }
|
|
|
+
|
|
|
public static async Task resultStatus(CosmosClient client, List<ExamClassResult> examClassResults)
|
|
|
{
|
|
|
List<Task<ItemResponse<ExamClassResult>>> tasks = new();
|
|
@@ -870,11 +1216,12 @@ namespace TEAMModelOS.FunctionV4
|
|
|
var addTmdidsCls = tchList.FindAll(x => x.type == 1);
|
|
|
List<StuActivity> stuActivities = new List<StuActivity>();
|
|
|
List<StuActivity> tmdActivities = new List<StuActivity>();
|
|
|
- var papers = info.papers.GroupBy(c => c.subjectId).Select(x => new {
|
|
|
- subject = x.Key,
|
|
|
- blob = x.ToList().Select(z => z.blob).ToList() });
|
|
|
- bool flag = info.papers.Exists(c => c.subjectId != null);
|
|
|
- //var subs = info.papers.Select(z => z.subjectId).Distinct().ToList();
|
|
|
+ var papers = info.papers.GroupBy(c => c.subjectId).Select(x => new
|
|
|
+ {
|
|
|
+ subject = x.Key,
|
|
|
+ blob = x.ToList().Select(z => z.blob).ToList()
|
|
|
+ });
|
|
|
+ bool flag = info.papers.Exists(c => c.subjectId != null);
|
|
|
if (addTmdidsCls.IsNotEmpty())
|
|
|
{
|
|
|
addTmdidsCls.ForEach(x =>
|
|
@@ -941,7 +1288,8 @@ namespace TEAMModelOS.FunctionV4
|
|
|
creatorId = info.creatorId,
|
|
|
subjects = sub,
|
|
|
blob = null,
|
|
|
- paper = flag ? papers.Select(c => new {
|
|
|
+ paper = flag ? papers.Select(c => new
|
|
|
+ {
|
|
|
c.subject,
|
|
|
blob = c.blob[new Random().Next(c.blob.Count)]
|
|
|
}) : "",
|
|
@@ -1024,7 +1372,8 @@ namespace TEAMModelOS.FunctionV4
|
|
|
creatorId = info.creatorId,
|
|
|
subjects = sub,
|
|
|
blob = null,
|
|
|
- paper = flag ? papers.Select(c => new {
|
|
|
+ paper = flag ? papers.Select(c => new
|
|
|
+ {
|
|
|
c.subject,
|
|
|
blob = c.blob[new Random().Next(c.blob.Count)]
|
|
|
}) : "",
|
|
@@ -1454,9 +1803,10 @@ namespace TEAMModelOS.FunctionV4
|
|
|
newScores.Add(sc > -1 ? sc : 0);
|
|
|
}
|
|
|
}
|
|
|
- else {
|
|
|
+ else
|
|
|
+ {
|
|
|
newScores.Add(0);
|
|
|
- }
|
|
|
+ }
|
|
|
classSrate += newScores.Sum();
|
|
|
score += newScores.Sum();
|
|
|
result.studentScores.Add(newScores);
|
|
@@ -1594,12 +1944,12 @@ namespace TEAMModelOS.FunctionV4
|
|
|
index_json = await _azureStorage.GetBlobContainerClient($"{info.creatorId}").GetBlobClient($"{info.papers[no].blob}/index.json").DownloadContentAsync();
|
|
|
}
|
|
|
//BlobDownloadResult index_json = await _azureStorage.GetBlobContainerClient($"{info.school}").GetBlobClient($"{info.papers[no].blob}/index.json").DownloadContentAsync();
|
|
|
- //JObject jo = JObject.Parse(new MemoryStream(Encoding.UTF8.GetBytes(index_json.Content.ToString())).ToString());
|
|
|
JsonElement RecordingJson = JsonDocument.Parse(new MemoryStream(Encoding.UTF8.GetBytes(index_json.Content.ToString()))).RootElement;
|
|
|
RecordingJson.TryGetProperty("slides", out JsonElement slides);
|
|
|
var sdes = slides.ToObject<List<Slides>>();
|
|
|
List<string> attachments = new List<string>();
|
|
|
- if (info.qamode == 1) {
|
|
|
+ if (info.qamode == 1)
|
|
|
+ {
|
|
|
attachments = RecordingJson.GetProperty("attachments").ToObject<List<string>>();
|
|
|
if (attachments.Count == 0)
|
|
|
{
|
|
@@ -1607,7 +1957,7 @@ namespace TEAMModelOS.FunctionV4
|
|
|
}
|
|
|
}
|
|
|
List<string> urls = new();
|
|
|
-
|
|
|
+
|
|
|
foreach (var ne in sdes)
|
|
|
{
|
|
|
if (!ne.type.Equals("compose"))
|
|
@@ -1615,7 +1965,6 @@ namespace TEAMModelOS.FunctionV4
|
|
|
urls.Add(ne.url);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
// 获取整体的题目ID集合
|
|
|
List<string> ids = new();
|
|
|
List<(string id, string pid, int level, string type, List<string> knows)> itemInfos = new();
|
|
@@ -1638,10 +1987,10 @@ namespace TEAMModelOS.FunctionV4
|
|
|
string pid = keys.Value<string>("pid");
|
|
|
itemInfos.Add((id, pid, level, type, knowledge));
|
|
|
}
|
|
|
-
|
|
|
- /* double[] point = StringHelper.ListTodouble(result.paper.point);
|
|
|
- double[,] res = StringHelper.ListToDouble(result.studentScores);
|
|
|
- var cdm = new ClouDASMatrix(res, point);*/
|
|
|
+
|
|
|
+ /* double[] point = StringHelper.ListTodouble(result.paper.point);
|
|
|
+ double[,] res = StringHelper.ListToDouble(result.studentScores);
|
|
|
+ var cdm = new ClouDASMatrix(res, point);*/
|
|
|
//需要努力的题目
|
|
|
//var ss = cdm.StriveTopic;
|
|
|
int n = 0;
|
|
@@ -1665,13 +2014,16 @@ namespace TEAMModelOS.FunctionV4
|
|
|
var itemScore = result.studentScores[index_stu];
|
|
|
List<int> index = new();
|
|
|
int index_item = 0;
|
|
|
- foreach (var sc in itemScore) {
|
|
|
- if (sc == 0) {
|
|
|
- index.Add(index_item+1);
|
|
|
+ foreach (var sc in itemScore)
|
|
|
+ {
|
|
|
+ if (sc == 0)
|
|
|
+ {
|
|
|
+ index.Add(index_item + 1);
|
|
|
}
|
|
|
index_item++;
|
|
|
}
|
|
|
- if (index.Count == 0) {
|
|
|
+ if (index.Count == 0)
|
|
|
+ {
|
|
|
continue;
|
|
|
}
|
|
|
//int[] item_index = ss[n];
|
|
@@ -1700,25 +2052,25 @@ namespace TEAMModelOS.FunctionV4
|
|
|
string accessKey = string.Empty;
|
|
|
if (location.Contains("China"))
|
|
|
{
|
|
|
- if(location.Equals("China")) //大陸正式站
|
|
|
+ if (location.Equals("China")) //大陸正式站
|
|
|
{
|
|
|
urlAction = "https://malearn.teammodel.cn";
|
|
|
accessKey = "2BcXFR_hvzG1pZjqIkaM7Dx74Hcu6m0PwwOacFpDpq44AzFuHJBRXA==";
|
|
|
}
|
|
|
- else if(location.Equals("China-Dep") || location.Equals("China-Test")) //大陸測試站
|
|
|
+ else if (location.Equals("China-Dep") || location.Equals("China-Test")) //大陸測試站
|
|
|
{
|
|
|
urlAction = "https://malearn-rc.teammodel.cn";
|
|
|
accessKey = "lghWhJduNiAlo-e8isqEoROjdR7DAC-50XNtanIwHKYlAzFu1aog_A==";
|
|
|
- }
|
|
|
+ }
|
|
|
}
|
|
|
else if (location.Contains("Global"))
|
|
|
{
|
|
|
- if(location.Equals("Global")) //國際正式站
|
|
|
+ if (location.Equals("Global")) //國際正式站
|
|
|
{
|
|
|
urlAction = "https://malearn.teammodel.net";
|
|
|
accessKey = "I-2lTcdggJkZWSBwOXQIm4oHx-huwX3d0wLe-9pgojThAzFuq_KNFg==";
|
|
|
}
|
|
|
- else if(location.Equals("Global-Test")) //國際測試站
|
|
|
+ else if (location.Equals("Global-Test")) //國際測試站
|
|
|
{
|
|
|
urlAction = "https://malearn-rc.teammodel.net";
|
|
|
accessKey = "_l4Cb_tHIRBw_iv3ZuwVqjkMwjg4_HtDaxhAmZ8OwJraAzFu_DAY8A==";
|
|
@@ -1738,14 +2090,17 @@ namespace TEAMModelOS.FunctionV4
|
|
|
}
|
|
|
string paramJson = JsonConvert.SerializeObject(errors);
|
|
|
var content = new StringContent(paramJson, Encoding.UTF8, "application/json");
|
|
|
- var response = await htc.PostAsync(connect, content);
|
|
|
- if ((int)response.StatusCode == 200) {
|
|
|
+ var response = await htc.PostAsync(connect, content);
|
|
|
+ if ((int)response.StatusCode == 200)
|
|
|
+ {
|
|
|
await task_error.TaskPage(10);
|
|
|
- }
|
|
|
+ }
|
|
|
}
|
|
|
- } catch (Exception e) {
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测错题异常{e.Message}\n{e.StackTrace}\n", GroupNames.醍摩豆服務運維群組);
|
|
|
- }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
public class Settlement
|
|
@@ -1757,20 +2112,85 @@ namespace TEAMModelOS.FunctionV4
|
|
|
public double qrate { get; set; }
|
|
|
}
|
|
|
|
|
|
- public class Slides
|
|
|
+ #region ===學習記錄用類別===
|
|
|
+ private class PaperIndex
|
|
|
+ {
|
|
|
+ public PaperIndex()
|
|
|
+ {
|
|
|
+ slides = new List<Slide>();
|
|
|
+ }
|
|
|
+ public List<Slide> slides { get; set; }
|
|
|
+ }
|
|
|
+ private class Slide
|
|
|
{
|
|
|
+ /// <summary>
|
|
|
+ /// blob 路徑
|
|
|
+ /// </summary>
|
|
|
public string url { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 題型
|
|
|
+ /// </summary>
|
|
|
public string type { get; set; }
|
|
|
- public Scoring scoring { get; set; } = new Scoring();
|
|
|
+ /// <summary>
|
|
|
+ /// scoring
|
|
|
+ /// </summary>
|
|
|
+ public Scoring scoring { get; set; }
|
|
|
+
|
|
|
+ }
|
|
|
+ private class Scoring
|
|
|
+ {
|
|
|
+ /// <summary>
|
|
|
+ /// knowledge
|
|
|
+ /// </summary>
|
|
|
+ public List<string> knowledge { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 答案
|
|
|
+ /// </summary>
|
|
|
+ public List<string> ans { get; set; }
|
|
|
+
|
|
|
}
|
|
|
+ private class StudentAnswers
|
|
|
+ {
|
|
|
+ /// <summary>
|
|
|
+ /// 學生作答 blob 路徑
|
|
|
+ /// </summary>
|
|
|
+ public List<List<string>> studentAnswers { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 學生ID
|
|
|
+ /// </summary>
|
|
|
+ public List<string> studentIds { get; set; } = new();
|
|
|
|
|
|
- public class Scoring
|
|
|
+ }
|
|
|
+ private class QuestionData
|
|
|
{
|
|
|
- public double score { get; set; }
|
|
|
- public List<string> knowledge { get; set; } = new List<string>();
|
|
|
- public int field { get; set; } = new();
|
|
|
- public List<string> ans { get; set; } = new List<string>();
|
|
|
+ public QuestionData()
|
|
|
+ {
|
|
|
+ item = new List<QuestionItem>();
|
|
|
+ }
|
|
|
+ public QuestionExercise exercise { get; set; }
|
|
|
+ public List<QuestionItem> item { get; set; }
|
|
|
+ }
|
|
|
+ private class QuestionItem
|
|
|
+ {
|
|
|
+ public QuestionItem()
|
|
|
+ {
|
|
|
+ option = new List<OptionItem>();
|
|
|
+ }
|
|
|
+ public string question { get; set; }
|
|
|
+ public List<OptionItem> option { get; set; }
|
|
|
+ }
|
|
|
+ private class OptionItem
|
|
|
+ {
|
|
|
+ public string code { get; set; }
|
|
|
+ public string value { get; set; }
|
|
|
+ }
|
|
|
+ private class QuestionExercise
|
|
|
+ {
|
|
|
+ public string type { get; set; }
|
|
|
+ public List<string> knowledge { get; set; }
|
|
|
+ public List<string> answer { get; set; }
|
|
|
}
|
|
|
|
|
|
+ #endregion
|
|
|
}
|
|
|
}
|