using Azure.Cosmos; using Azure.Messaging.ServiceBus; using HTEXLib.COMM.Helpers; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using TEAMModelOS.SDK.DI; using TEAMModelOS.SDK.Extension; using TEAMModelOS.SDK.Models; namespace TEAMModelOS.SDK { public static class StatisticsService { /// /// 教师能力点操作 /// public const string TeacherAility = "TeacherAility"; /// /// 课堂实录 /// public const string TeacherClass = "TeacherClass"; /// /// 线下研修 /// public const string OfflineRecord = "OfflineRecord"; /// /// 教师投票活动 /// public const string TeacherVote = "TeacherVote"; /// /// 教师作业活动 /// public const string TeacherHomework = "TeacherHomework"; /// /// 教师问卷活动 /// public const string TeacherSurvey = "TeacherSurvey"; /// /// 教师评测活动 /// public const string TeacherExamLite = "TeacherExamLite"; public static async Task SendServiceBus(string standard,string tmdid,string school,string update,int statistics, IConfiguration _configuration, AzureServiceBusFactory _serviceBus) { TeacherTrainChange change = new TeacherTrainChange { standard = standard, tmdid =tmdid, school =school, update = new HashSet(new List { update }), statistics = statistics }; var messageChange = new ServiceBusMessage(change.ToJsonString()); messageChange.ApplicationProperties.Add("name", "TeacherTrainChange"); var ActiveTask = _configuration.GetValue("Azure:ServiceBus:ActiveTask"); await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChange); } public static async Task GetAreaAndAreaSetting( string schoolId, string _standard, CosmosClient client, HttpContext httpContext) { School school = null; AreaSetting setting = null; string standard = ""; if (string.IsNullOrEmpty(_standard)) { standard = _standard; } else if(!string.IsNullOrEmpty(schoolId)) { //优先找校级 setting = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync(schoolId, new PartitionKey("AreaSetting")); //优先找校级 school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync(schoolId, new PartitionKey("Base")); } } public static async Task trains, List yxtrain)>> StatisticsArea(AreaSetting setting, Area area, CosmosClient client, DingDing _dingDing, HashSet updates) { List<(List trains, List yxtrain)> teacherTrains = new List<(List trains, List yxtrain)>() ; List schools = new List(); await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School") .GetItemQueryIterator(queryText: $"select value(c) from c where c.areaId='{area.id}' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") })) { schools.Add(item); } await foreach ((List trains, List yxtrain) tarain in GetStatisticsSchool(schools, setting, area, client,_dingDing,updates)) { teacherTrains.Add(tarain); } return teacherTrains; } private static async IAsyncEnumerable<(List trains, List yxtrain)> GetStatisticsSchool(List schools, AreaSetting setting, Area area, CosmosClient client, DingDing _dingDing, HashSet updates) { foreach (var school in schools) { yield return await StatisticsSchool(school.id, setting, area, client,_dingDing,updates); } } public static async Task<(List trains, List yxtrain)> StatisticsSchool(string school, AreaSetting setting, Area area, CosmosClient client,DingDing _dingDing,HashSet updates) { List yxtrain = await GroupListService.GetGroupListMemberByType(client, "yxtrain", new List { "school" }, $"{school}", _dingDing); List trains = new List(); var members = yxtrain.SelectMany(x => x.members).ToList(); if (members.Count <= 0) { return (trains, yxtrain); } await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher") .GetItemQueryIterator(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"TeacherTrain-{school}") })) { trains.Add(item); } if (updates != null) { foreach (var up in updates) { trains.ForEach(x => x.updateProperty.Add(up)); } } var update = trains.FindAll(x => x.updateProperty.Count() > 0); var noupdate = trains.FindAll(x => x.updateProperty.Count() <=0); var unStatistics = members.Select(x => x.id).Except(trains.Select(x => x.id)); List teacherTrains = new List(); List returnTrains = new List(); if (update.IsNotEmpty()) { teacherTrains.AddRange(update); } if (unStatistics != null) { foreach (string x in unStatistics) { var member = members.Find(y => y.id.Equals(x)); teacherTrains.Add(new TeacherTrain { pk = "TeacherTrain", id = x, code = $"TeacherTrain-{school}", tmdid = x, name = member.name, picture=member.picture, school = school, updateProperty = new HashSet { TeacherAility,TeacherClass,OfflineRecord } }); } } List studies = new List(); await foreach (var item in client.GetContainer("TEAMModelOS", "Common") .GetItemQueryIterator(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Study-{school}") })) { studies.Add(item); } returnTrains = await GetStatisticsTeacher(teacherTrains, setting, area, client,studies); //await foreach (var tarain in GetStatisticsTeacher(teacherTrains, setting, area, client)) //{ // returnTrains.Add(tarain); //} if (noupdate.IsNotEmpty()) { returnTrains.AddRange(noupdate); } returnTrains.ForEach(x => { var mbm= members.Find(y => y.id.Equals(x.id)); x.groupName = mbm?.groupName; x.name = mbm?.name; x.picture = mbm?.picture; }); return (returnTrains, yxtrain); } private static async Task> GetStatisticsTeacher(List trains, AreaSetting setting, Area area, CosmosClient client, List studies) { List> teachers = new List>(); foreach (var train in trains) { teachers.Add(StatisticsTeacher(train, setting, area, client,studies)); //yield return await StatisticsTeacher( train, setting, area, client); } int pagesize = 50; if (teachers.Count <= pagesize) { await Task.WhenAll(teachers); } else { int pages = (teachers.Count + pagesize) / pagesize; //256是批量操作最大值,pages = (total + max -1) / max; for (int i = 0; i < pages; i++) { var lists = teachers.Skip((i) * pagesize).Take(pagesize).ToList(); await Task.WhenAll(lists); } } return trains; } public static async Task StatisticsTeacher(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client,List studies) { string _school = train.school; string _tmdid = train.tmdid; // TeacherTrain teacher_train = null; List> teachers = new List>(); if (train.updateProperty.Count > 0) { foreach (string property in train.updateProperty) { teachers.Add(DoProperty(train.updateProperty, property, setting, area, client, train,studies)); } int pagesize = 50; if (teachers.Count <= pagesize) { await Task.WhenAll(teachers); } else { int pages = (teachers.Count + pagesize) / pagesize; //256是批量操作最大值,pages = (total + max -1) / max; for (int i = 0; i < pages; i++) { var lists = teachers.Skip((i) * pagesize).Take(pagesize).ToList(); await Task.WhenAll(lists); } } } //每次都统计活动相关的数据。 // train= await DoActivity(train, setting, area, client, _school, _tmdid); train.totalTime = train.onlineTime + train.classTime + train.currency.submitTime + train.offlineTime; if (train.totalTime >= setting.allTime) { //如果总学生超过50 且不是优秀则至少是合格。 if (train.finalScore != 2) { train.finalScore = 1; } } // 50> 学时>0 是不合格 else if (train.totalTime < setting.allTime && train.totalTime > 0) { train.finalScore = 0; } else { //学时<=0 则是为 train.finalScore = -1; } await client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync(train, new PartitionKey($"TeacherTrain-{_school}")); return train; } private static async Task DoProperty(HashSet updateProperty,string property, AreaSetting setting, Area area, CosmosClient client, TeacherTrain train ,List studies ) { string _school = train.school; string _tmdid = train.tmdid; switch (property) { case TeacherAility: train = await DoTeacherAility(train, setting, area, client, _school, _tmdid); train.updateProperty.Remove(TeacherAility); break; //课堂实录更新 case TeacherClass: train = await DoTeacherClass(train, setting, area, client, _school, _tmdid); train.updateProperty.Remove(TeacherClass); break; //线下研修 case OfflineRecord: train = await DoOfflineRecord(train, setting, area, client, _school, _tmdid,studies); train.updateProperty.Remove(OfflineRecord); break; //投票 case TeacherVote: train = await DoTeacherVote(train, setting, area, client, _school, _tmdid); train.updateProperty.Remove(TeacherVote); break; //问卷 case TeacherSurvey: train = await DoTeacherSurvey(train, setting, area, client, _school, _tmdid); train.updateProperty.Remove(TeacherSurvey); break; //作业 //case TeacherHomework: // train = await DoTeacherHomework(train, setting, area, client, _school, _tmdid); // train.updateProperty.Remove(TeacherHomework); // break; //评测 case TeacherExamLite: train = await DoTeacherExamLite(train, setting, area, client, _school, _tmdid); train.updateProperty.Remove(TeacherExamLite); break; default: train.updateProperty.Remove(property); break; } return train; } public static async Task DoTeacherVote(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid) { int voteJoin = 0; int voteDone = 0; int voteAreaJoin = 0; int voteAreaDone = 0; //投票活动 await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher") .GetItemQueryIterator(queryText: $"select c.owner, c.taskStatus from c where c.type = 'Vote' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{_tmdid}") })) { if (!string.IsNullOrEmpty(item.owner)) { if (item.owner.Equals("school")) { voteJoin += 1; if (item.taskStatus > 0) { voteDone += 1; } } else if (item.owner.Equals("area")) { voteAreaJoin += 1; if (item.taskStatus > 0) { voteAreaDone += 1; } } } } train.voteJoin = voteJoin; train.voteDone = voteDone; train.voteAreaJoin = voteAreaJoin; train.voteAreaDone = voteAreaDone; return train; } public static async Task DoTeacherSurvey(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid) { //问卷调查 int surveyJoin = 0; int surveyDone = 0; int surveyAreaJoin = 0; int surveyAreaDone = 0; await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher") .GetItemQueryIterator(queryText: $"select c.owner, c.taskStatus from c where c.type = 'Survey' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{_tmdid}") })) { if (!string.IsNullOrEmpty(item.owner)) { if (item.owner.Equals("school")) { surveyJoin += 1; if (item.taskStatus > 0) { surveyDone += 1; } } else if (item.owner.Equals("area")) { surveyAreaJoin += 1; if (item.taskStatus > 0) { surveyAreaDone += 1; } } } } train.surveyJoin = surveyJoin; train.surveyDone = surveyDone; train.surveyAreaJoin = surveyAreaJoin; train.surveyAreaDone = surveyAreaDone; return train; } public static async Task DoTeacherExamLite(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid) { //问卷调查 int examJoin = 0; int examDone = 0; int examAreaJoin = 0; int examAreaDone = 0; //评量检测 await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher") .GetItemQueryIterator(queryText: $"select c.owner, c.taskStatus from c where c.type = 'ExamLite' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{_tmdid}") })) { if (!string.IsNullOrEmpty(item.owner)) { if (item.owner.Equals("school")) { examJoin += 1; if (item.taskStatus > 0) { examDone += 1; } } else if (item.owner.Equals("area")) { examAreaJoin += 1; if (item.taskStatus > 0) { examAreaDone += 1; } } } } train.examJoin = examJoin; train.examDone = examDone; train.examAreaJoin = examAreaJoin; train.examAreaDone = examAreaDone; return train; } /// /// 课堂实录更新 /// /// /// /// /// /// /// /// public static async Task DoOfflineRecord(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid, List studies) { //owner: school area //线下 学校研修活动 List activities = new List(); await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher") .GetItemQueryIterator(queryText: $"select value(c) from c where c.type = 'Study' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{_tmdid}") })) { activities.Add(item); } string insql = ""; if (studies.IsEmpty()) { studies = new List(); if (activities.IsNotEmpty()) { insql = $" where c.id in ({string.Join(",", activities.Select(o => $"'{o.id}'"))})"; } await foreach (var item in client.GetContainer("TEAMModelOS", "Common") .GetItemQueryIterator(queryText: $"select value(c) from c {insql} ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Study-{_school}") })) { studies.Add(item); } } List studyRecords = new List(); await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher") .GetItemQueryIterator(queryText: $"select value(c) from c {insql} ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"StudyRecord-{_tmdid}") })) { studyRecords.Add(item); } string rcdsql = $" where c.id in ({string.Join(",", studies.FindAll(x=>!string.IsNullOrEmpty(x.workId)).Select(o => $"'{o.workId}'"))})"; List homeworkRecords = new List(); await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher") .GetItemQueryIterator(queryText: $"select value(c) from c {rcdsql} ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"HomeworkRecord-{_tmdid}") })) { homeworkRecords.Add(item); } List offlines = new List(); activities.ForEach(item => { Study study = studies.Find(y=>y.id.Equals(item.id)); if (!string.IsNullOrEmpty(item.owner) && study != null && !string.IsNullOrEmpty(study.workId) && !item.owner.Equals("area") ) { StudyRecord studyRecord = studyRecords.Find(y => y.id.Equals(item.id)); HomeworkRecord homeworkRecord = homeworkRecords.Find(y => y.id.Equals(study.workId)); Attachment attachment = homeworkRecord != null ? homeworkRecord.content.Find(x => x.prime) : null; OfflineRecord record = new OfflineRecord { id = item.id, name = item.name, done = item.taskStatus, owner = item.owner }; record.sethour = study.hour; if (!string.IsNullOrEmpty(study.workId) ) { record.haswork = 1; } if (null != studyRecord) { //通过获得学时 record.hour = studyRecord.status == 1 ? study.hour : 0; record.score = studyRecord.status; if (record.score >= 0) { record.done = 1; } else { record.score = -1; } } if (null != attachment) { record.url = attachment.url; record.upload = 1; record.hash = attachment.hash; record.size = attachment.size; } offlines.Add(record); } }); int sum = offlines.Select(x => x.hour).Sum(); train.offlineTime =sum >setting.offlineTime?setting.offlineTime: sum; train.offlineRecords= offlines; return train; } /// /// 课堂实录更新 /// /// /// /// /// /// /// /// public static async Task DoTeacherClass(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid) { string code = $"ClassVideo-{_school}"; ClassVideo classVideo = null; try { classVideo = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync($"{_tmdid}", new PartitionKey(code)); } catch (Exception ex) { classVideo = null; } if (classVideo != null && classVideo.files.IsNotEmpty()) { //2021.11.17 15:05,与J哥确认,取课堂实录第一个。前端也只show第一个视频。 var files = classVideo.files[0]; if (files.score > 0) { train.classTime = setting.classTime; } else { train.classTime = 0; } train.teacherClasses = new List { new Models.TeacherClass { url = files.url, score = files.score, hash = files.hash, name = files.name, size = files.size } }; } else { train.classTime = 0; } return train; } public static async Task DoTeacherAility(TeacherTrain train, AreaSetting setting,Area area , CosmosClient client,string _school,string _tmdid) { //视频播放 List abilityIds = new List (); TeacherFile file = null; try { file = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync(_tmdid, new PartitionKey($"TeacherFile-{_school}")); } catch (CosmosException ) { file = new TeacherFile { id = _tmdid, code = $"TeacherFile-{_school}", pk = "TeacherFile", ttl = -1, }; await client.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync(file, new PartitionKey($"TeacherFile-{_school}")); } List abilitySubs= new List (); //认证材料 await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher") .GetItemQueryIterator(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"AbilitySub-{_school}-{_tmdid}") })) { abilitySubs.Add(item); } List abilities = new List(); string insql = ""; if (abilitySubs.IsNotEmpty()) { insql =$" where c.id in ({string.Join(",", abilitySubs.Select(o => $"'{o.id}'"))})"; } await foreach (var item in client.GetContainer("TEAMModelOS", "Normal") .GetItemQueryIterator(queryText: $"select c.id,c.name,c.currency,c.no,c.dimension,c.hour,c.stds from c {insql} ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Ability-{area.standard}") })) { abilities.Add(item); } Currency currency= new Currency(); Currency currencyAll = new Currency(); abilitySubs.ForEach(item => { int currencyInt = item.from == 1 ? 1 : 0; Ability ability = abilities.Find(x=>x.id.Equals(item.id)); if (ability != null) { if (ability != null) { currencyInt = item.from == 0 ? ability.currency : 1; } else { currencyInt = 0; } if (item.uploads.IsNotEmpty()) { if (currencyInt == 1) { currency.uploadDone += item.uploads.Count; } currencyAll.uploadDone += item.uploads.Count; } if (item.exerciseScore > 0) { if (currencyInt == 1) { currency.exerciseAbility += 1; currency.learnAbility += item.abilityCount; } currencyAll.exerciseAbility += 1; currencyAll.learnAbility += item.abilityCount; } List hprecords = new List(); TeacherAility teacherAility = new Models.TeacherAility { id = ability.id, currency = currencyInt, no = ability.no, name = ability.name, dimension = ability.dimension, zpscore = item.self, hprecord = hprecords, uploadHas = item.uploads.Count }; if (file != null) { long view = 0; file.fileRecords.ForEach(record => { var abilityVideo = record.files.FindAll(x => x.abilityId.Equals(item.id)); if (abilityVideo.IsNotEmpty()) { view += record.view; } }); //能力点学时限制 int limit = ability.hour * setting.lessonMinutes; //如果超过 8* 45分钟学时,则直接赋值360(limit)分钟。 view = view / 60; view = view > limit ? limit : view; teacherAility.videoTime = view; teacherAility.limitTime = ability.hour; teacherAility.onlineTime = view / setting.lessonMinutes; } if (item.otherScore.IsNotEmpty()) { var schoolScore = item.otherScore.Where(x => x.roleType.Equals("school")).FirstOrDefault(); if (schoolScore != null && schoolScore.score >= 0) { teacherAility.xzscore = schoolScore.score; teacherAility.xztime = schoolScore.time; teacherAility.xztmdid = schoolScore.tmdid; teacherAility.xztmdname = schoolScore.tmdname; } var hprecord = item.otherScore.FindAll(x => x.roleType.Equals("member")).Select(y => new TeacherHprecord { tmdid = y.tmdid, tmdname = y.tmdname, score = y.score }); if (hprecord != null) { var no = hprecord.Where(x => x.score == 0) != null ? hprecord.Where(x => x.score == 0).Count() : 0; var hg = hprecord.Where(x => x.score == 1) != null ? hprecord.Where(x => x.score == 1).Count() : 0; var yx = hprecord.Where(x => x.score == 2) != null ? hprecord.Where(x => x.score == 2).Count() : 0; if (no == hg && hg == yx && no == 0) { teacherAility.hpscore = -1; } else if (no == hg && hg == yx && no != 0) { teacherAility.hpscore = 2; } else { bool ok = false; List arr = new List() { yx, hg, no }; int max = arr.Max(); if (max == yx && !ok) { teacherAility.hpscore = 2; ok = true; } if (max == hg && !ok) { teacherAility.hpscore = 1; ok = true; } if (max == no && !ok) { teacherAility.hpscore = 0; ok = true; } } teacherAility.hprecord.AddRange(hprecord); } } if (currencyInt == 1) { currency.subCount += 1; currency.uploadTotal += ability.stds.FindAll(x => x.task.IsNotEmpty()).Select(y => y.task).Count(); currency.teacherAilities.Add(teacherAility); } currencyAll.subCount += 1; currencyAll.uploadTotal += ability.stds.FindAll(x => x.task.IsNotEmpty()).Select(y => y.task).Count(); currencyAll.teacherAilities.Add(teacherAility); } }); train.currency = currency; train.currencyAll = currencyAll; train.currency.videoTime = train.currency.teacherAilities.Select(x => x.videoTime).Sum(); train.currencyAll.videoTime= train.currencyAll.teacherAilities.Select(x => x.videoTime).Sum(); //如果总分钟数超过20学时,则直接复制20学时。 var videoTime = (int)train.currency.videoTime / setting.lessonMinutes; train.onlineTime = videoTime > setting.onlineTime ? setting.onlineTime:videoTime; var bhg = train.currency.teacherAilities.FindAll(x => x.xzscore > 0); if (bhg.IsNotEmpty()&& bhg.Count == train.currency.subCount) { ///要全部合格才能获得学时。 train.currency.submitTime = setting.submitTime; train.currencyAll.submitTime = setting.submitTime; } return train; } } }