|
@@ -14,21 +14,32 @@ using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
|
|
using TEAMModelOS.SDK.Helper.Common.StringHelper;
|
|
using TEAMModelOS.SDK.Helper.Common.StringHelper;
|
|
using TEAMModelOS.SDK.Helper.Security.ShaHash;
|
|
using TEAMModelOS.SDK.Helper.Security.ShaHash;
|
|
using TEAMModelOS.Services.Analysis;
|
|
using TEAMModelOS.Services.Analysis;
|
|
|
|
+using Microsoft.Extensions.Options;
|
|
|
|
+using TEAMModelOS.Models;
|
|
|
|
+using Azure.Cosmos;
|
|
|
|
+using TEAMModelOS.SDK.Models.Cosmos.Student;
|
|
|
|
+using static TEAMModelOS.SDK.Models.Cosmos.Student.StudentAnalysis;
|
|
|
|
+using TEAMModelOS.SDK.Models.Cosmos.School;
|
|
|
|
+using static TEAMModelOS.SDK.Models.Cosmos.School.ClassAnalysis;
|
|
|
|
+using static TEAMModelOS.SDK.Models.Cosmos.School.GradeAnalysis;
|
|
|
|
|
|
namespace TEAMModelOS.Controllers.Analysis
|
|
namespace TEAMModelOS.Controllers.Analysis
|
|
{
|
|
{
|
|
- [Route("api/[controller]")]
|
|
|
|
|
|
+ [Route("analysis")]
|
|
[ApiController]
|
|
[ApiController]
|
|
public class AchievementController : Controller
|
|
public class AchievementController : Controller
|
|
{
|
|
{
|
|
|
|
|
|
private readonly AzureCosmosFactory _azureCosmos;
|
|
private readonly AzureCosmosFactory _azureCosmos;
|
|
-
|
|
|
|
|
|
+ private readonly DingDing _dingDing;
|
|
|
|
+ private readonly Option _option;
|
|
private const string CacheCosmosPrefix = "Analysis:";
|
|
private const string CacheCosmosPrefix = "Analysis:";
|
|
private const int timeoutSeconds = 3600;
|
|
private const int timeoutSeconds = 3600;
|
|
- public AchievementController(AzureCosmosFactory azureCosmos)
|
|
|
|
|
|
+ public AchievementController(AzureCosmosFactory azureCosmos, DingDing dingDing, IOptionsSnapshot<Option> option)
|
|
{
|
|
{
|
|
_azureCosmos = azureCosmos;
|
|
_azureCosmos = azureCosmos;
|
|
|
|
+ _dingDing = dingDing;
|
|
|
|
+ _option = option?.Value;
|
|
|
|
|
|
|
|
|
|
}
|
|
}
|
|
@@ -2209,5 +2220,300 @@ namespace TEAMModelOS.Controllers.Analysis
|
|
// throw new BizException(e.Message);
|
|
// throw new BizException(e.Message);
|
|
// }
|
|
// }
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ [HttpPost("getAnalysis")]
|
|
|
|
+ public async Task<IActionResult> getAnalysis(JsonElement request) {
|
|
|
|
+ //获取评测的ID
|
|
|
|
+ if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
|
|
|
|
+ if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
|
|
|
|
+ try {
|
|
|
|
+ var client = _azureCosmos.GetCosmosClient();
|
|
|
|
+ //获取本次评测所有科目结算结果
|
|
|
|
+ ExamInfo info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"Exam-{code}"));
|
|
|
|
+ School school = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<School>(code.ToString(), new PartitionKey($"Base"));
|
|
|
|
+ List<ExamResult> examResults = new List<ExamResult>();
|
|
|
|
+ var query = $"select c.id,c.name,c.subjectId,c.studentScores,c.studentIds,c.paper from c where c.examId = '{id}' ";
|
|
|
|
+ await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryIterator<ExamResult>(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamResult-{id}") }))
|
|
|
|
+ {
|
|
|
|
+ /*using var json = await JsonDocument.ParseAsync(item.ContentStream);
|
|
|
|
+ if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
|
|
|
|
+ {
|
|
|
|
+ foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
|
|
|
|
+ {
|
|
|
|
+ examResults.Add(obj.ToObject<ExamResult>());
|
|
|
|
+ }
|
|
|
|
+ }*/
|
|
|
|
+ examResults.Add(item);
|
|
|
|
+ }
|
|
|
|
+ //获取本次评测所有班级作答结果
|
|
|
|
+ List<ExamClassResult> examClassResults = new List<ExamClassResult>();
|
|
|
|
+ var queryClass = $"select c.id,c.name,c.subjectId,c.studentScores,c.studentIds,c.gradeId,c.info from c where c.examId = '{id}' and c.progress = true ";
|
|
|
|
+ await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryIterator<ExamClassResult>(queryText: queryClass, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{code}") }))
|
|
|
|
+ {
|
|
|
|
+ examClassResults.Add(item);
|
|
|
|
+ /*using var json = await JsonDocument.ParseAsync(item.ContentStream);
|
|
|
|
+ if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
|
|
|
|
+ {
|
|
|
|
+ foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
|
|
|
|
+ {
|
|
|
|
+ examClassResults.Add(obj.ToObject<ExamClassResult>());
|
|
|
|
+ }
|
|
|
|
+ }*/
|
|
|
|
+ }
|
|
|
|
+ //获取进线标准
|
|
|
|
+ int touch = 0;
|
|
|
|
+ foreach (Period period in school.period) {
|
|
|
|
+ if (info.period.id.Equals(period.id)) {
|
|
|
|
+ touch = period.analysis.touch;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //获取进线人数
|
|
|
|
+ int personCount = (int)System.Math.Round( (double)info.stuCount * (touch / 100), 1 ,MidpointRounding.AwayFromZero);
|
|
|
|
+
|
|
|
|
+ StudentAnalysis analysis = new StudentAnalysis();
|
|
|
|
+ List<ClassAnalysis> classAnalyses = new List<ClassAnalysis>();
|
|
|
|
+ //以班级为单位
|
|
|
|
+ List<double> stuTotals = new List<double>();
|
|
|
|
+ foreach (string s in info.targetClassIds) {
|
|
|
|
+ //声明班级所有科目总分
|
|
|
|
+ double total = 0;
|
|
|
|
+ //存放每个班级学生总分
|
|
|
|
+ List<double> totalClass = new List<double>();
|
|
|
|
+ ClassAnalysis classAnalysis = new ClassAnalysis();
|
|
|
|
+ classAnalysis.classId = s;
|
|
|
|
+ var sresponse = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(s, new PartitionKey($"Class-{code}"));
|
|
|
|
+ if (sresponse.Status == 200)
|
|
|
|
+ {
|
|
|
|
+ using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
|
|
|
|
+ Class classroom = json.ToObject<Class>();
|
|
|
|
+ classAnalysis.stuCount = classroom.students.Count;
|
|
|
|
+ foreach (StudentSimple stu in classroom.students)
|
|
|
|
+ {
|
|
|
|
+ analysis.ids.Add(stu.id);
|
|
|
|
+ //计算学生多科考试成绩总分
|
|
|
|
+ double stuTotal = 0;
|
|
|
|
+ foreach (ExamResult examResult in examResults)
|
|
|
|
+ {
|
|
|
|
+ int index = examResult.studentIds.IndexOf(stu.id);
|
|
|
|
+ stuTotal = stuTotal + examResult.studentScores[index].Sum();
|
|
|
|
+ }
|
|
|
|
+ classAnalysis.total.Add(stuTotal);
|
|
|
|
+ analysis.total.Add(stuTotal);
|
|
|
|
+ stuTotals.Add(stuTotal);
|
|
|
|
+ totalClass.Add(stuTotal);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ /* //声明单个班级单科总分
|
|
|
|
+ double subjectTotal = 0;*/
|
|
|
|
+ info.subjects.ForEach(sub => {
|
|
|
|
+ //初始化及格人数
|
|
|
|
+ int i = 0;
|
|
|
|
+ //初始化单科总分
|
|
|
|
+ double sumClass = 0;
|
|
|
|
+ //记录每个科目数据
|
|
|
|
+ SubjectScore subjectScore = new SubjectScore();
|
|
|
|
+ subjectScore.id = sub.id;
|
|
|
|
+ double subjectSum = 0;
|
|
|
|
+ double passScore = 0;
|
|
|
|
+ //计算单科评测总分
|
|
|
|
+ foreach (ExamResult examResult in examResults)
|
|
|
|
+ {
|
|
|
|
+ if (sub.id.Equals(examResult.subjectId))
|
|
|
|
+ {
|
|
|
|
+ subjectSum = examResult.paper.point.Sum();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //单科及格率分数
|
|
|
|
+ passScore = subjectSum * 0.6;
|
|
|
|
+ //存放学生单科记录
|
|
|
|
+ Score score = new Score();
|
|
|
|
+ score.subjectId = sub.id;
|
|
|
|
+ List<double> subjectTotal = new List<double>();
|
|
|
|
+ //处理每个班级各个学生各科总分
|
|
|
|
+ foreach (ExamClassResult result in examClassResults)
|
|
|
|
+ {
|
|
|
|
+ if (sub.id.Equals(result.subjectId) && s.Equals(result.info.id))
|
|
|
|
+ {
|
|
|
|
+ foreach (List<double> scores in result.studentScores)
|
|
|
|
+ {
|
|
|
|
+ //添加每个学生各科总分
|
|
|
|
+ score.sc.Add(scores.Sum());
|
|
|
|
+ //计算大于及格分数的人数
|
|
|
|
+ if (scores.Sum() >= passScore)
|
|
|
|
+ {
|
|
|
|
+ i++;
|
|
|
|
+ }
|
|
|
|
+ //totalClass.Add(scores.Sum());
|
|
|
|
+ subjectTotal.Add(scores.Sum());
|
|
|
|
+ sumClass = sumClass + scores.Sum();
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ //处理班级及格率以及均分
|
|
|
|
+ double persentClass = i / result.studentIds.Count;
|
|
|
|
+ double averageClass = sumClass / result.studentIds.Count;
|
|
|
|
+ total += averageClass;
|
|
|
|
+ subjectScore.passPersent.Add(persentClass);
|
|
|
|
+ subjectScore.averageScore.Add(averageClass);
|
|
|
|
+ classAnalysis.subjects.Add(subjectScore);
|
|
|
|
+ //analysis.scores.Add(score);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //处理单科科班级PR
|
|
|
|
+ subjectTotal.Sort(delegate (double s1, double s2) { return s2.CompareTo(s1); });
|
|
|
|
+ foreach (double sc in score.sc)
|
|
|
|
+ {
|
|
|
|
+ int index = subjectTotal.IndexOf(sc);
|
|
|
|
+ double CPR = 100 - (100 * (index + 1) - 50) / score.sc.Count;
|
|
|
|
+ score.cdpr.Add(CPR);
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ analysis.scores.Add(score);
|
|
|
|
+ });
|
|
|
|
+ //处理全科班级PR
|
|
|
|
+ totalClass.Sort(delegate (double s1, double s2) { return s2.CompareTo(s1); });
|
|
|
|
+ foreach (double pr in classAnalysis.total)
|
|
|
|
+ {
|
|
|
|
+ int index = totalClass.IndexOf(pr);
|
|
|
|
+ double CPR = 100 - (100 * (index + 1) - 50) / classAnalysis.total.Count;
|
|
|
|
+ analysis.cpr.Add(CPR);
|
|
|
|
+ }
|
|
|
|
+ classAnalyses.Add(classAnalysis);
|
|
|
|
+ }
|
|
|
|
+ /*info.targetClassIds.ForEach( async s => {
|
|
|
|
+
|
|
|
|
+ });*/
|
|
|
|
+ //初始化进线分数
|
|
|
|
+ double ipoint = 0;
|
|
|
|
+ stuTotals.Sort(delegate (double s1, double s2) { return s2.CompareTo(s1); });
|
|
|
|
+ ipoint = stuTotals[personCount];
|
|
|
|
+ //补充班级总平均分/进行人数/标准差
|
|
|
|
+ foreach (ClassAnalysis classAnalysis in classAnalyses) {
|
|
|
|
+ //初始化进线人数
|
|
|
|
+ int i = 0;
|
|
|
|
+ //初始化班级总分
|
|
|
|
+ double score = 0;
|
|
|
|
+ //标准差
|
|
|
|
+ double powSum = 0;
|
|
|
|
+ foreach (double sc in classAnalysis.total) {
|
|
|
|
+ if (sc > ipoint) {
|
|
|
|
+ i++;
|
|
|
|
+ }
|
|
|
|
+ score = score + sc;
|
|
|
|
+ }
|
|
|
|
+ //总平均分
|
|
|
|
+ double totalAverage = 0;
|
|
|
|
+ totalAverage = score / classAnalysis.stuCount;
|
|
|
|
+ //计算标准差
|
|
|
|
+ foreach (double sc in classAnalysis.total)
|
|
|
|
+ {
|
|
|
|
+ powSum += Math.Pow(sc - totalAverage, 2);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var pow = Math.Pow(powSum / classAnalysis.stuCount, 0.5);
|
|
|
|
+
|
|
|
|
+ classAnalysis.standardDeviation = pow;
|
|
|
|
+ classAnalysis.totalAverage = totalAverage;
|
|
|
|
+ classAnalysis.lineCount = i;
|
|
|
|
+ }
|
|
|
|
+ //处理全科年级PR值
|
|
|
|
+ foreach (double no in analysis.total) {
|
|
|
|
+ int index = stuTotals.IndexOf(no);
|
|
|
|
+ int GPR = 100 - (100 * (index+1) - 50) / analysis.total.Count;
|
|
|
|
+ analysis.gpr.Add(GPR);
|
|
|
|
+ }
|
|
|
|
+ List<GradeAnalysis> gradeAnalyses = new List<GradeAnalysis>();
|
|
|
|
+ if (info.grades.Count > 0) {
|
|
|
|
+ gradeAnalyses = GetGradeAnalyses(info, examResults, examClassResults, analysis);
|
|
|
|
+ }
|
|
|
|
+ return Ok(new { analysis, classAnalyses, gradeAnalyses });
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ await _dingDing.SendBotMsg($"OS,{_option.Location},analysis/getAnalysis()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
|
|
|
|
+ return BadRequest();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ private List<GradeAnalysis> GetGradeAnalyses(ExamInfo info, List<ExamResult> examResults, List<ExamClassResult> examClassResults,StudentAnalysis analysis) {
|
|
|
|
+ List<GradeAnalysis> gradeAnalyses = new List<GradeAnalysis>();
|
|
|
|
+ info.grades.ForEach(g => {
|
|
|
|
+ GradeAnalysis gradeAnalysis = new GradeAnalysis();
|
|
|
|
+ gradeAnalysis.gradeId = g.id;
|
|
|
|
+ //初始化单个年级总分
|
|
|
|
+ double gradeScore = 0;
|
|
|
|
+ info.subjects.ForEach(sub =>
|
|
|
|
+ {
|
|
|
|
+ //初始化及格人数
|
|
|
|
+ int i = 0;
|
|
|
|
+ //初始化年级人数
|
|
|
|
+ int count = 0;
|
|
|
|
+ //初始化单科总分
|
|
|
|
+ double sumClass = 0;
|
|
|
|
+ //记录每个科目数据
|
|
|
|
+ GradeSubjectScore subjectScore = new GradeSubjectScore();
|
|
|
|
+ subjectScore.id = sub.id;
|
|
|
|
+ double subjectSum = 0;
|
|
|
|
+ double passScore = 0;
|
|
|
|
+ //计算单科评测总分
|
|
|
|
+ foreach (ExamResult examResult in examResults)
|
|
|
|
+ {
|
|
|
|
+ if (sub.id.Equals(examResult.subjectId))
|
|
|
|
+ {
|
|
|
|
+ subjectSum = examResult.paper.point.Sum();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //单科及格率分数
|
|
|
|
+ passScore = subjectSum * 0.6;
|
|
|
|
+ //存放学生单科记录
|
|
|
|
+ Score score = new Score();
|
|
|
|
+ List<double> subjectTotal = new List<double>();
|
|
|
|
+ //存放单科每个班级学生总分
|
|
|
|
+ List<double> totalClass = new List<double>();
|
|
|
|
+ //处理每个班级各个学生各科总分
|
|
|
|
+ foreach (ExamClassResult result in examClassResults)
|
|
|
|
+ {
|
|
|
|
+ if (sub.id.Equals(result.subjectId) && g.id.Equals(result.gradeId))
|
|
|
|
+ {
|
|
|
|
+ foreach (List<double> scores in result.studentScores)
|
|
|
|
+ {
|
|
|
|
+ //添加每个学生各科总分
|
|
|
|
+ score.sc.Add(scores.Sum());
|
|
|
|
+ //计算大于及格分数的人数
|
|
|
|
+ if (scores.Sum() >= passScore)
|
|
|
|
+ {
|
|
|
|
+ i++;
|
|
|
|
+ }
|
|
|
|
+ subjectTotal.Add(scores.Sum());
|
|
|
|
+ sumClass = sumClass + scores.Sum();
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ count += result.studentIds.Count;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //处理班级及格率以及均分
|
|
|
|
+ double persentClass = i / count;
|
|
|
|
+ double averageClass = sumClass / count;
|
|
|
|
+ gradeScore += averageClass;
|
|
|
|
+ subjectScore.passPersent.Add(persentClass);
|
|
|
|
+ subjectScore.averageScore.Add(averageClass);
|
|
|
|
+ gradeAnalysis.subjects.Add(subjectScore);
|
|
|
|
+ gradeAnalyses.Add(gradeAnalysis);
|
|
|
|
+ //处理单科科年级PR
|
|
|
|
+ subjectTotal.Sort(delegate (double s1, double s2) { return s2.CompareTo(s1); });
|
|
|
|
+ foreach (double sc in score.sc)
|
|
|
|
+ {
|
|
|
|
+ int index = subjectTotal.IndexOf(sc);
|
|
|
|
+ double GPR = 100 - (100 * (index + 1) - 50) / score.sc.Count;
|
|
|
|
+ score.gdpr.Add(GPR);
|
|
|
|
+ //analysis.gpr.Add(GPR);
|
|
|
|
+ }
|
|
|
|
+ analysis.scores.Add(score);
|
|
|
|
+
|
|
|
|
+ });
|
|
|
|
+ foreach (GradeAnalysis grade in gradeAnalyses) {
|
|
|
|
+ grade.GradeaverageScore = gradeScore / grade.subjects.Count;
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ return gradeAnalyses;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|