Browse Source

Merge branch 'develop5.0-tmd' of http://52.130.252.100:10000/TEAMMODEL/TEAMModelOS into develop5.0-tmd

zhouj1203@hotmail.com 3 years ago
parent
commit
b57f37ce2b

+ 5 - 1
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/Attachment.cs

@@ -42,6 +42,10 @@ namespace TEAMModelOS.SDK.Models
         /// 设置为主要提交文档。
         /// </summary>
         public bool prime { get; set; } = false;
-
+        public string hash { get; set; }
+        /// <summary>
+        /// 视频播放时长
+        /// </summary>
+        public long duration { get; set; }
     }
 }

+ 9 - 0
TEAMModelOS.SDK/Models/Cosmos/Research/AbilityRecord.cs

@@ -87,6 +87,15 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public long selfTime { get; set; }
 
+        /// <summary>
+        ///automatic,自动分配系统设置的=0,manual手动挑选的=1
+        /// </summary>
+        public int from { get; set; } = 0;
+        /// <summary>
+        ///默认未设置0 必修1 通识2 选修3
+        /// </summary>
+        public int currency { get; set; }
+
     }
     public class SubUpload {
         public int score { get; set; } = -1;

+ 66 - 0
TEAMModelOS.SDK/Models/Cosmos/Research/TeacherFile.cs

@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models
+{
+    public class TeacherFile : CosmosEntity
+    {
+        /// <summary>
+        /// id="tmdid",code":"VideoRecord:hbcn"
+        /// </summary>
+        public TeacherFile() { 
+        }
+        public List<FileRecord> fileRecords { get; set; } = new List<FileRecord>();
+    }
+
+    public class FileRecord {
+        /// <summary>
+        /// 文件hash值
+        /// </summary>
+        public string hash { get; set; }
+        /// <summary>
+        /// 文件大小
+        /// </summary>
+        public long size { get; set; }
+        /// <summary>
+        /// 视频的时长
+        /// </summary>
+        public long duration { get; set; }
+        /// <summary>
+        /// 观看时长
+        /// </summary>
+        public long view { get; set; }
+        /// <summary>
+        /// video ,doc,
+        /// </summary>
+        public string type { get; set; }
+        /// <summary>
+        /// 文件位置
+        /// </summary>
+        public List<FileAbility> files { get; set; }= new List<FileAbility> { };
+    }
+    public class FileAbility { 
+        /// <summary>
+        /// 文件地址
+        /// </summary>
+        public string url { get; set; }
+        /// <summary>
+        /// 能力点id,章节id,分支节点id,资源节点id
+        /// </summary>
+        public string abilityId { get; set; }
+        public bool done { get; set; }
+        /// <summary>
+        /// 章节id
+        /// </summary>
+        public string taskId { get; set; }
+        /// <summary>
+        /// 分支节点id
+        /// </summary>
+        public string nodeId { get; set; }
+        /// <summary>
+        /// 资源节点id
+        /// </summary>
+        //public string rnodeId { get; set; }
+    }
+}

+ 209 - 13
TEAMModelOS.SDK/Models/Cosmos/Research/TeacherTrain.cs

@@ -2,57 +2,245 @@
 using System.Collections.Generic;
 using System.Text;
 
-namespace TEAMModelOS.SDK.Models.Cosmos.Research
+namespace TEAMModelOS.SDK.Models
 {
-    public class TeacherTrain
+    public class TeacherTrain : CosmosEntity
     {
         /// <summary>
         /// 总学时
         /// </summary>
         public int totalTime { get; set; }
+        ///id= "tmdid"
+        ///code= "TeacherTrain-hbcn"
+        /// <summary>
+        /// 被统计的教师
+        /// </summary>
+        public string tmdid { get; set; }
+        /// <summary>
+        /// 学校编码
+        /// </summary>
+        public string school { get; set; }
+        //code:"TeacherTrain:hbcn-tmdid"
+       
         /// <summary>
         /// 线上观看视频的学时
         /// </summary>
         public int onlineTime { get; set; }
+       
         /// <summary>
         /// 线下研修学时
         /// </summary>
         public int offlineTime { get; set; }
+        
         /// <summary>
-        /// 认证材料学时
+        /// 课堂实录学时
         /// </summary>
-        public int submitTime { get; set; }
+        public int classTime { get; set; }
+       
         /// <summary>
-        /// 认证材料学时
+        /// 必修的
         /// </summary>
-        public int classTime { get; set; }
+        public Currency currency { get; set; }= new Currency();
         /// <summary>
-        /// 教师能力点情况
+        /// 包含选修的
         /// </summary>
-        public List<TeacherAility> teacherAilities { get; set; }= new List<TeacherAility>();
+        public Currency currencyAll { get; set; }= new Currency();
+        public List<OfflineRecord> offlineRecords { get; set; } = new List<OfflineRecord>();
         /// <summary>
         /// 教师课堂实录
         /// </summary>
-        public List<TeacherClass> teacherClasses { get; set; }= new List<TeacherClass>();
+        public List<TeacherClass> teacherClasses { get; set; } = new List<TeacherClass>();
+
+        /// <summary>
+        /// 300字以内的总结
+        /// </summary>
         public string summary { get; set; }
+       
+        /// <summary>
+        /// 校级问卷参与数
+        /// </summary>
+        public int surveyJoin { get; set; } = 0;
+        /// <summary>
+        /// 校级投票参与数
+        /// </summary>
+        public int voteJoin { get; set; } = 0;
+        /// <summary>
+        /// 校级评测参与数
+        /// </summary>
+        public int examJoin { get; set; } = 0;
+        /// <summary>
+        /// 校级问卷完成数
+        /// </summary>
+        public int surveyDone { get; set; } = 0;
+        /// <summary>
+        /// 校级投票完成数
+        /// </summary>
+        public int voteDone { get; set; } = 0;
+        /// <summary>
+        /// 校级评测完成数
+        /// </summary>
+        public int examDone { get; set; } = 0;
+        /// <summary>
+        /// 区级问卷参与数
+        /// </summary>
+        public int surveyAreaJoin { get; set; } = 0;
+        /// <summary>
+        /// 区级问卷参与数
+        /// </summary>
+        public int voteAreaJoin { get; set; } = 0;
+        /// <summary>
+        /// 区级评测参与数
+        /// </summary>
+        public int examAreaJoin { get; set; } = 0;
+        /// <summary>
+        /// 区级问卷完成数
+        /// </summary>
+        public int surveyAreaDone { get; set; } = 0;
+        /// <summary>
+        /// 区级投票完成数
+        /// </summary>
+        public int voteAreaDone { get; set; } = 0;
+        /// <summary>
+        /// 区级评测完成数
+        /// </summary>
+        public int examAreaDone { get; set; } = 0;
+
+        /// <summary>
+        /// 待更新的属性
+        /// </summary>
+        public HashSet<string>updateProperty{get;set;}
     }
 
-    public class TeacherAility { 
+    public class Currency {
+        /// <summary>
+        /// 线上观看视频的学时
+        /// </summary>
+        public long videoTime { get; set; }
+        /// <summary>
+        /// 认证材料学时
+        /// </summary>
+        public int submitTime { get; set; }
+        /// <summary>
+        /// 教师能力点情况
+        /// </summary>
+        public List<TeacherAility> teacherAilities { get; set; } = new List<TeacherAility>();
+        /// <summary>
+        /// 已学能力点, 是勾选了,还是有观看视频的,还是
+        /// </summary>
+        public int learnAbility { get; set; }
+        /// <summary>
+        /// 已通过自测的能力点数量
+        /// </summary>
+        public int exerciseAbility { get; set; }
+        /// <summary>
+        /// 需要上传的总数
+        /// </summary>
+        public int uploadTotal { get; set; }
+        /// <summary>
+        /// 完成上传的数量
+        /// </summary>
+        public int uploadDone { get; set; }
+        /// <summary>
+        /// 订阅数量
+        /// </summary>
+        public int subCount { get; set; }
+    }
+    public class TeacherAility {
+        /// <summary>
+        /// 线上观看视频的学时
+        /// </summary>
+        public long videoTime { get; set; }
+        /// <summary>
+        /// 默认未设置0 必修1 通识2 选修3
+        /// </summary>
+        public int currency  { get; set; }
+        /// <summary>
+        /// 能力点id
+        /// </summary>
         public string id { get; set; }
+        /// <summary>
+        /// 能力点编号
+        /// </summary>
         public string no { get; set; }
+        /// <summary>
+        /// 能力点维度
+        /// </summary>
         public string dimension { get; set; }
+        /// <summary>
+        /// 自评
+        /// </summary>
         public int zpscore { get; set; }
-        public int hpscore { get; set; }
+        /// <summary>
+        /// 互评结果
+        /// </summary>
+        public int hpscore { get; set; } = -1;
+        /// <summary>
+        /// 校评结果
+        /// </summary>
         public int xzscore { get; set; }
+        /// <summary>
+        /// 已提交数量
+        /// </summary>
+        public int uploadHas { get; set; }
+        /// <summary>
+        /// 互评记录
+        /// </summary>
         public List<TeacherHprecord> hprecord { get; set; } = new List<TeacherHprecord>();
     }
-    
+    /// <summary>
+    /// 线下研修记录
+    /// </summary>
+    public class OfflineRecord
+    {
+        /// <summary>
+        /// 打分的人
+        /// </summary>
+        //public string tmdid { get; set; }
+        /// <summary>
+        ///-1未评分 0 未通过 1通过 
+        /// </summary>
+        public int score { get; set; } = -1;
+        /// <summary>
+        /// 线下研修的pdf地址
+        /// </summary>
+        public string url { get; set; }
+        /// <summary>
+        /// 线下研修的pdf大小
+        /// </summary>
+        public long size { get; set; }
+        /// <summary>
+        /// 线下研修名称
+        /// </summary>
+        public string name { get; set; }
+        public string id { get; set; }
+        /// <summary>
+        /// school校级, area区级
+        /// </summary>
+        public string owner { get; set; }
+        /// <summary>
+        /// 获取的学时
+        /// </summary>
+        public int hour { get; set; }
+        /// <summary>
+        ///线下研修的pdf文件的 md5值
+        /// </summary>
+        public string hash { get; set; }
+        /// <summary>
+        ///-1 未参与,0,未完成, 1已完成
+        /// </summary>
+        public int done { get; set; }
+        /// <summary>
+        /// 0未提交,1已提交。
+        /// </summary>
+        public int upload { get; set; } = 0;
+    }
     /// <summary>
     /// 互评记录
     /// </summary>
     public class TeacherHprecord
     {
         public string tmdid { get; set; }
+        public string tmdname { get; set; }
         public int score { get; set; }
     }
     /// <summary>
@@ -60,7 +248,15 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Research
     /// </summary>
     public class TeacherClass
     {
-        public string file { get; set; }
+        public string url { get; set; }
         public int score { get; set; }
+        /// <summary>
+        /// 打分的人
+        /// </summary>
+        //public string tmdid { get; set; }
+        public string hash { get; set; }
+        public string name { get; set; }
+        public long size { get; set; }
+        //public string fileType { get; set; }
     }
 }

+ 3 - 1
TEAMModelOS.SDK/Models/Cosmos/Teacher/StudyRecord.cs

@@ -13,7 +13,9 @@ namespace TEAMModelOS.SDK.Models
         public string school { get; set; }
         public string sign { get; set; }
         public long signTime { get; set; }
-        //0未审核 1 通过 2 未通过
+        /// <summary>
+        /// 0未审核 1 通过 2 未通过
+        /// </summary>
         public int status { get; set; } = 0;
         public long aTime { get; set; }
     }

+ 486 - 0
TEAMModelOS.SDK/Models/Service/StatisticsService.cs

@@ -0,0 +1,486 @@
+using Azure.Cosmos;
+using HTEXLib.COMM.Helpers;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Models;
+
+namespace TEAMModelOS.SDK
+{
+    public static class StatisticsService
+    {
+        /// <summary>
+        /// 视频观看记录
+        /// </summary>
+        public const string VideoRecord= "VideoRecord";
+        /// <summary>
+        /// 教师能力点操作
+        /// </summary>
+        public const string TeacherAility = "TeacherAility";
+        /// <summary>
+        /// 课堂实录
+        /// </summary>
+        public const string TeacherClass = "TeacherClass";
+        /// <summary>
+        /// 线下研修
+        /// </summary>
+        public const string OfflineRecord = "OfflineRecord";
+        public static async Task<List<TeacherTrain> > StatisticsArea(AreaSetting setting, Area area, CosmosClient client, DingDing _dingDing)
+        {
+            List<TeacherTrain> teacherTrains = new List<TeacherTrain>();
+            List<School> schools = new List<School>();
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School")
+            .GetItemQueryIterator<School>(queryText: $"select value(c) from c where c.areaId='{area.id}'  ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
+            {
+                schools.Add(item);
+            }
+            await foreach (var tarain in GetStatisticsSchool(schools, setting, area, client,_dingDing))
+            {
+                teacherTrains.AddRange(tarain);
+            }
+            return teacherTrains;
+        }
+        private static async IAsyncEnumerable<List<TeacherTrain>> GetStatisticsSchool(List<School> schools, AreaSetting setting, Area area, CosmosClient client, DingDing _dingDing)
+        {
+            foreach (var school in schools)
+            {
+                yield return await StatisticsSchool(school.id, setting, area, client,_dingDing);
+            }
+        }
+        public static async Task<List<TeacherTrain>> StatisticsSchool(string school, AreaSetting setting, Area area, CosmosClient client,DingDing _dingDing) {
+            List<RGroupList> yxtrain = await GroupListService.GetGroupListMemberByType(client, "yxtrain", new List<string> { "school" }, $"{school}", _dingDing);
+            List<TeacherTrain> trains = new List<TeacherTrain>();
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher")
+             .GetItemQueryIterator<TeacherTrain>(queryText: $"select value(c) from c  ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"TeacherTrain-{school}") })) {
+                trains.Add(item);
+            }
+            var update = trains.FindAll(x => x.updateProperty.Count() > 0);
+            var noupdate = trains.FindAll(x => x.updateProperty.Count() <=0);
+            var members= yxtrain.SelectMany(x => x.members);
+            var unStatistics = members.Select(x => x.id).Except(trains.Select(x => x.id));
+            List<TeacherTrain> teacherTrains = new List<TeacherTrain>();
+            List<TeacherTrain> returnTrains = new List<TeacherTrain>();
+            if (update.IsNotEmpty()) {
+                teacherTrains.AddRange(update);
+            }
+            if (unStatistics != null) {
+                foreach (string x in unStatistics) {
+                    teacherTrains.Add(new TeacherTrain
+                    {
+                        id = x,
+                        code = $"TeacherTrain-{school}",
+                        tmdid = x,
+                        school = school,
+                        updateProperty = new HashSet<string> { VideoRecord,TeacherAility,TeacherClass,OfflineRecord }
+                    });
+                }
+            }
+
+            await foreach (var tarain in GetStatisticsTeacher(teacherTrains, setting, area, client))
+            {
+                returnTrains.Add(tarain);
+            }
+            if (noupdate.IsNotEmpty()) {
+                returnTrains.AddRange(noupdate);
+            }
+            return returnTrains; 
+        }
+        private static async IAsyncEnumerable<TeacherTrain> GetStatisticsTeacher(List<TeacherTrain> trains, AreaSetting setting, Area area, CosmosClient client)
+        {
+            foreach (var train in trains)
+            {
+                yield return await  StatisticsTeacher(  train,   setting,   area,   client);
+            }
+        }
+        public static async Task<TeacherTrain> StatisticsTeacher(TeacherTrain train,  AreaSetting setting, Area area, CosmosClient client) {
+            string _school = train.school;
+            string _tmdid = train.tmdid;
+            TeacherTrain teacher_train = null; 
+            if (train.updateProperty.Count > 0) {
+                await foreach (var tarain in DoProperty(train.updateProperty, setting, area, client, train)){
+                    teacher_train=tarain;
+                }
+            }
+            //每次都统计活动相关的数据。
+            train= await DoActivity(train, setting, area, client, _school, _tmdid);
+            train.totalTime = train.onlineTime + train.classTime + train.currency.submitTime + train.offlineTime;
+            return train;
+        }
+        private static async IAsyncEnumerable<TeacherTrain> DoProperty(HashSet<string> updateProperty, AreaSetting setting, Area area, CosmosClient client, TeacherTrain train  )
+        {
+            string _school = train.school;
+            string _tmdid = train.tmdid;
+            foreach (var property in  updateProperty)
+            {
+                //视频观看更新
+                if (property.Equals(VideoRecord, StringComparison.OrdinalIgnoreCase))
+                {
+                    train = await DoVideoRecord(train, setting, area, client, _school, _tmdid);
+                    train.updateProperty.Remove(VideoRecord);
+                    yield return train;
+                }
+                //认证材料更新
+                if (property.Equals(TeacherAility, StringComparison.OrdinalIgnoreCase))
+                {
+                    train = await DoTeacherAility(train, setting, area, client, _school, _tmdid);
+                    train.updateProperty.Remove(TeacherAility);
+                    yield return train;
+                }
+                //课堂实录更新
+                if (property.Equals(TeacherClass, StringComparison.OrdinalIgnoreCase))
+                {
+                    train = await DoTeacherClass(train, setting, area, client, _school, _tmdid);
+                    train.updateProperty.Remove(TeacherClass);
+                    yield return train;
+                }
+                //线下研修
+                if (property.Equals(OfflineRecord, StringComparison.OrdinalIgnoreCase))
+                {
+                    train = await DoOfflineRecord(train, setting, area, client, _school, _tmdid);
+                    train.updateProperty.Remove(OfflineRecord);
+                    yield return train;
+                }
+            }
+        }
+        public static async Task<TeacherTrain> DoActivity(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid) {
+            //问卷调查
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher")
+             .GetItemQueryIterator<StuActivity>(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"))
+                    {
+                        train.surveyJoin += 1;
+                        if (item.taskStatus > 0)
+                        {
+                            train.surveyDone += 1;
+                        }
+                    }
+                    else if (item.owner.Equals("area"))
+                    {
+                        train.surveyAreaJoin += 1;
+                        if (item.taskStatus > 0)
+                        {
+                            train.surveyAreaDone += 1;
+                        }
+                    }
+                }
+            }
+            //评量检测
+            await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
+              .GetItemQueryIterator<StuActivity>(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"))
+                    {
+                        train.examJoin += 1;
+                        if (item.taskStatus > 0)
+                        {
+                            train.examDone += 1;
+                        }
+                    }
+                    else if (item.owner.Equals("area"))
+                    {
+                        train.examAreaJoin += 1;
+                        if (item.taskStatus > 0)
+                        {
+                            train.examAreaDone += 1;
+                        }
+                    }
+                }
+            }
+            //投票活动
+            await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
+             .GetItemQueryIterator<StuActivity>(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"))
+                    {
+                        train.voteJoin += 1;
+                        if (item.taskStatus > 0)
+                        {
+                            train.voteDone += 1;
+                        }
+                    }
+                    else if (item.owner.Equals("area"))
+                    {
+                        train.voteAreaJoin += 1;
+                        if (item.taskStatus > 0)
+                        {
+                            train.voteAreaDone += 1;
+                        }
+                    }
+                }
+            }
+            return train;
+        }
+        
+        /// <summary>
+        /// 课堂实录更新
+        /// </summary>
+        /// <param name="train"></param>
+        /// <param name="setting"></param>
+        /// <param name="area"></param>
+        /// <param name="client"></param>
+        /// <param name="_school"></param>
+        /// <param name="_tmdid"></param>
+        /// <returns></returns>
+        public static async Task<TeacherTrain> DoOfflineRecord(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid) {
+            //owner:  school  area
+            //线下 学校研修活动
+            await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
+            .GetItemQueryIterator<StuActivity>(queryText: $"select value(c) from c where  c.type = 'Study' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{_tmdid}") }))
+            {
+                Study study = null;
+                try
+                {
+                     study = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Study>(item.id, new PartitionKey(item.scode));
+                }
+                catch (CosmosException ex) {
+                    continue;
+                }
+                StudyRecord studyRecord;
+
+                Attachment attachment = null;
+                try {
+                    studyRecord= await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<StudyRecord>(item.id, new PartitionKey($"StudyRecord-{_tmdid}"));
+                }
+                catch (CosmosException ) {
+                    studyRecord = null;
+                }
+                try
+                {
+                    if (!string.IsNullOrEmpty(study.workId)) {
+                        HomeworkRecord homeworkRecord = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<HomeworkRecord>(study.workId, new PartitionKey($"HomeworkRecord-{_tmdid}"));
+                        attachment= homeworkRecord.content.Find(x => x.prime);
+                    }
+                }
+                catch (CosmosException)
+                {
+                    attachment = null;
+                }
+                if (!string.IsNullOrEmpty(item.owner))
+                {
+                    OfflineRecord record = new OfflineRecord
+                    {
+                        id = item.id,
+                        name = item.name,
+                        done = item.taskStatus,
+                        owner = item.owner
+                    };
+                    if (null != studyRecord)
+                    {
+                        //通过获得学时
+                        record.hour = studyRecord.status == 1 ? study.hour : 0;
+                        train.offlineTime = record.hour;
+                        if (studyRecord.status == 1)
+                        {
+                            record.score = 1;
+                            record.done = 1;
+                        }
+                        if (studyRecord.status == 0)
+                        {
+                            record.score = -1;
+                        }
+                        if (studyRecord.status == 2)
+                        {
+                            record.score = 0;
+                            record.done = 1;
+                        }
+                    }
+                    if (null != attachment)
+                    {
+                        record.url = attachment.url;
+                        record.upload = 1;
+                        record.hash = attachment.hash;
+                        record.size = attachment.size;
+                    }
+                    train.offlineRecords.Add(record);
+                }
+            }
+            return train;
+        }
+        /// <summary>
+        /// 课堂实录更新
+        /// </summary>
+        /// <param name="train"></param>
+        /// <param name="setting"></param>
+        /// <param name="area"></param>
+        /// <param name="client"></param>
+        /// <param name="_school"></param>
+        /// <param name="_tmdid"></param>
+        /// <returns></returns>
+        public static async Task<TeacherTrain> DoTeacherClass(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid)
+        {
+            string code = $"ClassVideo-{_school}";
+            ClassVideo classVideo = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<ClassVideo>($"{_tmdid}", new PartitionKey(code));
+            if (classVideo != null && classVideo.files.IsNotEmpty())
+            {
+                //2021.11.17 15:05,与J哥确认,取课堂实录第一个。前端也只show第一个视频。
+                var files = classVideo.files[0];
+                if (files.score > 0)
+                {
+                    train.classTime += 5;
+                }
+                train.teacherClasses.Add(new Models.TeacherClass {url=files.url,score=files.score,hash=files.hash,name=files.name,size=files.size });
+            }
+            return train;
+        }
+        public static async Task<TeacherTrain> DoVideoRecord(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid) {
+            TeacherFile file = null;
+            try
+            {
+                file = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<TeacherFile>(_tmdid, new PartitionKey($"VideoRecord-{_school}"));
+            }
+            catch (CosmosException ex)
+            {
+                file = new TeacherFile
+                {
+                    id = _tmdid,
+                    code = $"VideoRecord-{_school}" ,
+                    pk = "TeacherFile",
+                    ttl = -1,
+
+                };
+                await client.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<TeacherFile>(file, new PartitionKey($"VideoRecord-{_school}"));
+            }
+            if (file != null)
+            {
+                train.currency.videoTime = file.fileRecords.Where(x => x.type.Equals("video")).Select(y => y.view).Sum();
+            }
+            train.onlineTime = (int)train.currency.videoTime / setting.lessonMinutes;
+            return train;
+        }
+        public static async Task<TeacherTrain> DoTeacherAility(TeacherTrain train, AreaSetting setting,Area area ,  CosmosClient client,string _school,string _tmdid) {
+            await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
+                     .GetItemQueryIterator<AbilitySub>(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"AbilitySub-{_school}-{_tmdid}") }))
+            {
+                int currency = item.from == 1 ? 1 : 0;
+                Ability ability = null;
+                try
+                {
+                    ability = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<Ability>(item.id, new PartitionKey($"Ability-{area.standard}"));
+                    if (item.from == 0)
+                    {
+                        currency = ability.currency;
+
+                    }
+                    else
+                    {
+                        currency = 1;
+                    }
+                }
+                catch (CosmosException ex)
+                {
+                    currency = 0;
+                    continue;
+                }
+               
+                if (currency == 1) {
+                    train.currency.subCount += 1;
+                    train.currency.uploadTotal += ability.stds.FindAll(x => x.task.IsNotEmpty()).Select(y => y.task).Count();
+                }
+                train.currencyAll.subCount += 1;
+                train.currencyAll.uploadTotal += ability.stds.FindAll(x => x.task.IsNotEmpty()).Select(y => y.task).Count();
+
+                if (item.uploads.IsNotEmpty())
+                {
+                    if (currency == 1)
+                    {
+                        train.currency.uploadDone += item.uploads.Count;
+                    }
+                    train.currencyAll.uploadDone += item.uploads.Count;
+                }
+               
+
+                if (item.exerciseScore > 0)
+                {
+                    if (currency == 1) {
+                        train.currency.exerciseAbility += 1;
+                        train.currency.learnAbility += item.abilityCount;
+                    }
+                    train.currencyAll.exerciseAbility += 1;
+                    train.currencyAll.learnAbility += item.abilityCount;
+                }
+                List<TeacherHprecord> hprecords = new List<TeacherHprecord>();
+                TeacherAility teacherAility = new Models.TeacherAility
+                {
+                    id = ability.id,
+                    currency = currency,
+                    no = ability.no,
+                    dimension = ability.dimension,
+                    zpscore = item.self,
+                    hprecord = hprecords,
+                    uploadHas = item.uploads.Count
+                };
+                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;
+
+                    }
+                    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<int> arr = new List<int>() { 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 (currency == 1)
+                {
+                    train.currency.teacherAilities.Add(teacherAility);
+                }
+                train.currencyAll.teacherAilities.Add(teacherAility);
+            }
+            var bhg = train.currency.teacherAilities.FindAll(x => x.xzscore <= 0);
+            if (bhg.IsEmpty())
+            {
+                ///要全部合格才能获得学时。
+                train.currency.submitTime = setting.submitTime;
+                train.currencyAll.submitTime = setting.submitTime;
+            }
+            return train;
+        }
+
+         
+    }
+}

+ 11 - 5
TEAMModelOS/ClientApp/src/view/jyzx/offline.vue

@@ -494,6 +494,7 @@ export default {
         },
         // 删除不存在的投票
         delActivity(item) {
+            this.isLoading = true
             let param = {
                 code: item.code,
                 id: item.id,
@@ -512,7 +513,8 @@ export default {
                         }
                     }
                 }
-            }).finally(()=>{
+            }).finally(() => {
+                this.isLoading = false
             })
         },
         //处理创建者name和参与人name
@@ -525,7 +527,7 @@ export default {
                     detailsDatas.createdName = allteachs[i].name
                 }
             }
-            var teachArr = this.resource.teachers
+            /* var teachArr = this.resource.teachers
             var teachnameArr = []
             for(var i = 0; i < teachArr.length; i++) {
                 var teachId = teachArr[i].id
@@ -534,7 +536,7 @@ export default {
                     teachnameArr.push(crew)
                 }
                 //console.log(allteachs.find((n)=>n.id===teachId),'添加到数据的人')   
-            }
+            } */
             /* for(var r = 0; r < allteachs.length; r++) {
                 if(allteachs[r].id === '1528783259') {
                     console.log(allteachs[r],'找到了')
@@ -542,7 +544,7 @@ export default {
                     console.log('没有找到这个人')
                 }
             } */
-            detailsDatas.teachers = teachnameArr
+            // detailsDatas.teachers = teachnameArr
             this.resource = detailsDatas
         },
         getTarget(targets) {
@@ -557,7 +559,10 @@ export default {
                         list.push(item.name)
                     })
                     this.targets = list
-                    this.resource.joinNum = res.groups.tcount
+                    this.resource.joinNum = 0
+                    for (const item of res.groups) {
+                        this.resource.joinNum += item.tcount
+                    }
                 }
                 if(res.members.length) {
                     let id = res.members.find(item => {
@@ -565,6 +570,7 @@ export default {
                     })
                     this.isLeader = id.tag === "leader"
                 }
+                this.$forceUpdate()
             })
         },
         async getSurveyInfo(surveyId) {

+ 1 - 1
TEAMModelOS/ClientApp/src/view/learnactivity/MgtPrivEva.vue

@@ -382,7 +382,7 @@ export default {
                                 let sheetNo = resData.papers[index].sheetNo
                                 resData.papers[index] = await this.$evTools.getFullPaper(resData.papers[index], this.evaListShow[this.curEvaIndex].scope)
                                 resData.papers[index].blob = blob
-                                resData.score += resData.papers[index].score
+                                // resData.score += resData.papers[index].score
                                 resData.papers[index].examScope = this.evaListShow[this.curEvaIndex].scope
                                 resData.papers[index].examCode = this.evaListShow[this.curEvaIndex].code
                                 resData.papers[index].examId = this.evaListShow[this.curEvaIndex].id

+ 2 - 1
TEAMModelOS/ClientApp/src/view/learnactivity/SimpleAnalysis.vue

@@ -248,7 +248,7 @@ export default {
                 for (let i = 0; i < 10; i++) {
                     let endScore = Math.ceil(unit * (i + 1))
                     let s = this.stuTotalScores.filter(item => {
-                        return item >= startScore && item < endScore
+                        return item >= startScore && item <= endScore
                     })
                     segment.push({
                         name: `${startScore}-${endScore}`,
@@ -256,6 +256,7 @@ export default {
                     })
                     startScore = endScore + 1
                 }
+                console.log('分数段统计:', segment)
                 return segment
             } else {
                 return []

+ 2 - 46
TEAMModelOS/ClientApp/src/view/learnactivity/StuReport.vue

@@ -180,51 +180,6 @@
                                     <span v-if="!question.repair.length">{{$t("studentWeb.exam.report.noSource")}}</span>
                                     <div v-if="question.repair && question.repair.length" class="repair-box">
                                         <Collapse style="width:85%" accordion @on-change="getSource(question.repair,question)">
-                                            <!-- 网络资源 -->
-                                            <!-- <Panel name="1">
-                                                {{$t("studentWeb.exam.report.linkSource")}}
-                                                <p slot="content">
-                                                    <List border size="small">
-                                                        <ListItem v-for="(item,normalIndex) in repairSource.normal" :key="normalIndex">
-                                                            <span style="margin-right: 10px;" v-show="item.blobUrl">
-                                                                <Icon color="#0066FF" custom="iconfont icon-share_link" size="20" />
-                                                            </span><a :href="item.blobUrl" target="_blank">{{item.name}}</a>
-                                                        </ListItem>
-                                                        <ListItem v-show="!repairSource.normal.length">
-                                                            <span>{{$t("studentWeb.exam.report.noSource")}}</span>
-                                                        </ListItem>
-                                                    </List>
-                                                </p>
-                                            </Panel> -->
-                                            <!-- 文件资源 -->
-                                            <!-- <Panel name="2">
-                                                {{$t("studentWeb.exam.report.fileSource")}}
-                                                <p slot="content">
-                                                    <List border size="small">
-                                                        <ListItem v-for="(item,fileIndex) in repairSource.file" :key="fileIndex">
-                                                            <div style="width:100%">
-                                                                <span style="margin-right:10px;">
-                                                                    <Icon v-if="item.fileType == 'zip'" custom="iconfont icon-zip" size="20" />
-                                                                    <Icon v-else-if="item.fileType == 'pdf'" color="#FF6464" custom="iconfont icon-pdf" size="20" />
-                                                                    <Icon v-else-if="item.fileType == 'ppt'|| item.fileType == 'pptx'" color="#FF8976" custom="iconfont icon-ppt" size="20" />
-                                                                    <Icon v-else-if="item.fileType == 'mp3'" color="#FF5562" custom="iconfont icon-mp3" size="20" />
-                                                                    <Icon v-else-if="item.fileType == 'mp4'" color="#8E4C9E" custom="iconfont icon-video1" size="20" />
-                                                                    <Icon v-else-if="item.fileType == 'doc'||item.fileType =='docx'" color="#6CCBFF" custom="iconfont icon-word" size="20" />
-                                                                    <Icon v-else-if="item.fileType == 'csv'||item.fileType =='xlsx'||item.fileType =='xls'" color="#25C273" custom="iconfont icon-xlsx" size="20" />
-                                                                    <Icon v-else-if="item.fileType == 'jpg'||item.fileType =='png'||item.fileType =='jpeg'" color="#30D1CA" custom="iconfont icon-jpg" size="20" />
-                                                                    <Icon v-else custom="iconfont icon-V" size="20" />
-                                                                </span><a @click="getItemData(item)">{{item.name}}</a>
-                                                                <span style="display:block;float:right;cursor:pointer">
-                                                                    <Icon type="md-download" size="18" @click="downloadFile(item)" />
-                                                                </span>
-                                                            </div>
-                                                        </ListItem>
-                                                        <ListItem v-show="!repairSource.file.length">
-                                                            <span>{{$t("studentWeb.exam.report.noSource")}}</span>
-                                                        </ListItem>
-                                                    </List>
-                                                </p>
-                                            </Panel> -->
                                         </Collapse>
                                     </div>
                                 </div>
@@ -449,7 +404,8 @@ export default {
         paperInfo() {
             if (this.examInfo && this.examInfo.papers && this.subject) {
                 return this.examInfo.papers.find(item => {
-                    return item.subjectId == this.subject
+                    return item.blob.includes(this.subject)
+                    // return item.subjectId == this.subject
                 })
             } else {
                 return {

+ 13 - 26
TEAMModelOS/ClientApp/src/view/task/mark/ByQu2.vue

@@ -27,7 +27,10 @@
                         <div v-if="item.isLoading" class="answer-loading">
                             <Loading :top="50"></Loading>
                         </div>
-                        <div v-else class="answer-info-wrap" v-html="getCurAnswerData(item.answer)"></div>
+                        <div v-else class="answer-info-wrap" v-html="getCurAnswerData(item.answer)">
+                        <!-- <div v-else class="answer-info-wrap">
+                            1111 -->
+                        </div>
                         <Icon v-show="right.includes(item)" class="mark-tag" type="md-checkmark" />
                         <Icon v-show="wrong.includes(item)" class="mark-tag" type="md-close" />
                         <Icon v-show="half.includes(item)" class="mark-tag" custom="iconfont icon-half-right" />
@@ -139,42 +142,26 @@ export default {
                     if (item.blob) {
                         this.$tools.getFile(`${blobUrl}/exam/${item.blob}?${sas}`).then(
                             res => {
+                                console.log('res',index)
                                 this.$set(this.stusInfoShow[index], 'answer', JSON.parse(res || '[]'))
+                                this.stusInfoShow[index].isLoading = false
                             },
                             err => {
-                                this.$set(this.stusInfoShow[index], 'answer', [])
+                                console.log('err',index)
+                                this.$set(this.stusInfoShow[index], 'answer', []) //数据异常
+                                this.stusInfoShow[index].isLoading = false
                             }
                         ).finally(() => {
-                            console.log(index)
-                            this.$set(this.stusInfoShow[index], 'isLoading', false)
-                            console.log(JSON.stringify(this.stusInfoShow[index]))
+                            console.log('f',index)
+                            //设置修改状态会有问题
+                            // this.stusInfoShow[index].isLoading = false
                         })
                     } else {
-                        this.$set(this.stusInfoShow[index], 'isLoading', false)
                         this.$set(this.stusInfoShow[index], 'answer', 'noAnswer') //未作答
+                        this.stusInfoShow[index].isLoading = false
                     }
                 }
             }
-            // this.stusInfoShow.forEach((item, index) => {
-            //     if (item.isLoading) {
-            //         if (item.blob) {
-            //             this.$tools.getFile(`${blobUrl}/exam/${item.blob}?${sas}`).then(
-            //                 res => {
-            //                     this.$set(this.stusInfoShow[index], 'answer', JSON.parse(res || '[]'))
-            //                 },
-            //                 err => {
-            //                     this.$set(this.stusInfoShow[index], 'answer', [])
-            //                 }
-            //             ).finally(() => {
-            //                 console.log(index)
-            //                 this.$set(this.stusInfoShow[index], 'isLoading', false)
-            //             })
-            //         } else {
-            //             this.$set(this.stusInfoShow[index], 'isLoading', false)
-            //             this.$set(this.stusInfoShow[index], 'answer', 'noAnswer') //未作答
-            //         }
-            //     }
-            // })
         },
         handleReachBottom() {
             this.getPageData()

+ 77 - 0
TEAMModelOS/Controllers/Research/AbilityStatisticsController.cs

@@ -43,6 +43,83 @@ namespace TEAMModelOS.Controllers
         /// <param name="request"></param>
         /// <returns></returns>
         [ProducesDefaultResponseType]
+        [HttpPost("statistics-teacher")]
+        [AuthToken(Roles = "teacher,admin,area")]
+        public async Task<IActionResult> StatisticsTeacher(JsonElement request) {
+            //{"tmdid":"1595321354","school":"hbcn"}
+            var (userid, _, _, school) = HttpContext.GetAuthTokenInfo();
+            if (!HttpContext.Items.TryGetValue("Standard", out object standard)) return BadRequest();
+            var client = _azureCosmos.GetCosmosClient();
+            Area area = null;
+            string sql = $"select value(c) from c where c.standard='{standard}'";
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Area>(queryText: sql,
+                  requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-Area") }))
+            {
+                area = item;
+            }
+            AreaSetting setting = null;
+            if (area != null)
+            {
+                try
+                {
+                    //优先找校级
+                    setting = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<AreaSetting>(school, new PartitionKey("AreaSetting"));
+                }
+                catch (CosmosException)
+                {
+                    try
+                    {
+                        setting = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<AreaSetting>(area.id, new PartitionKey("AreaSetting"));
+                    }
+                    catch (CosmosException)
+                    {
+                        setting = null;
+                    }
+                }
+            }
+            if (setting == null)
+            {
+                setting = new AreaSetting
+                {
+                    allTime = 50,
+                    classTime = 5,
+                    submitTime = 15,
+                    onlineTime = 20,
+                    offlineTime = 10,
+                    lessonMinutes = 45,
+                };
+            }
+            try
+            {
+                TeacherTrain teacherTrain = null;
+                try
+                {
+                    teacherTrain= await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<TeacherTrain>(userid, new PartitionKey($"TeacherTrain-{school}"));
+                }
+                catch (CosmosException) {
+                     teacherTrain = await StatisticsService.StatisticsTeacher(new TeacherTrain
+                    {
+                        id = userid,
+                        code = $"TeacherTrain-{school}",
+                        tmdid = userid,
+                        school = school,
+                        updateProperty = new HashSet<string> { StatisticsService.VideoRecord, StatisticsService.TeacherAility,
+                        StatisticsService.TeacherClass, StatisticsService.OfflineRecord }
+                    }, setting, area, client);
+                    await client.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<TeacherTrain>(teacherTrain, new PartitionKey($"TeacherTrain-{school}"));
+                }
+                return Ok(new { teacherTrain , setting });
+            } catch (Exception ex) { 
+                return BadRequest(new { ex.Message ,ex.StackTrace});
+
+            }
+        }
+        /// <summary>
+        /// 对某个订阅的能力点进行操作
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
         [HttpPost("statistics-self")]
         [AuthToken(Roles = "teacher,admin,area")]
         public async Task<IActionResult> StatisticsSelf(JsonElement request)

+ 9 - 2
TEAMModelOS/Controllers/Research/AbilitySubController.cs

@@ -187,6 +187,8 @@ namespace TEAMModelOS.Controllers
                     return Ok(new { error = 400 });
                 };
                 (string accessConfig, Area area, AreaSetting setting) = await ThirdService.GetAccessConfig(client, $"{standard}");
+                //automatic,自动分配系统设置的=0,manual手动挑选的=1
+                int from = 0;
                 //未对接其他平台。有对接其他平台则必修。
                 if (!string.IsNullOrEmpty(accessConfig))
                 {
@@ -199,6 +201,7 @@ namespace TEAMModelOS.Controllers
                         currencyAb1 = abilitys;
                         //同时处理 原有设置必修的能力点。
                         hadSubs.FindAll(x => x.currency == 1).ForEach(y => { y.currency = 0; });
+                        from = 1;
                     }
                     else
                     {
@@ -221,7 +224,9 @@ namespace TEAMModelOS.Controllers
                             done = false,
                             hour = 0,
                             comid = Guid.NewGuid().ToString(),
-                            pk = "AbilitySub"
+                            pk = "AbilitySub" ,
+                            from = 0,
+                            currency = item.currency
                         };
                         await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Teacher").CreateItemAsync(abilitySub, new PartitionKey(abilitySub.code));
                     }
@@ -244,7 +249,9 @@ namespace TEAMModelOS.Controllers
                                 done = false,
                                 hour = 0,
                                 comid = Guid.NewGuid().ToString(),
-                                pk = "AbilitySub"
+                                pk = "AbilitySub",
+                                from=from,
+                                currency = item.currency
                             };
                             await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Teacher").CreateItemAsync(abilitySub, new PartitionKey(abilitySub.code));
                         }

+ 11 - 1
TEAMModelOS/Startup.cs

@@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http.Features;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.SpaServices;
+using Microsoft.AspNetCore.StaticFiles;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
@@ -165,7 +166,16 @@ namespace TEAMModelOS
             //app.UseMiddleware<HttpGlobalExceptionInvoke>();
 
             //以下需要按照順序載入中間件  如果应用调用 UseStaticFiles,请将 UseStaticFiles 置于 UseRouting之前。
-            app.UseStaticFiles();
+
+
+            var provider = new FileExtensionContentTypeProvider();
+            provider.Mappings[".properties"] = "application/octet-stream";
+            provider.Mappings[".bcmap"] = "application/octet-stream";
+            app.UseStaticFiles(new StaticFileOptions
+            {
+                ContentTypeProvider = provider
+            });
+            //app.UseStaticFiles();
             //PRODUCTION uses webpack static files
             app.UseSpaStaticFiles();            
             

+ 3 - 3
TEAMModelOS/TEAMModelOS.csproj

@@ -37,9 +37,9 @@
     <SpaRoot>ClientApp\</SpaRoot>
     <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
     <UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-    <Version>5.2111.19</Version>
-    <AssemblyVersion>5.2111.19.1</AssemblyVersion>
-    <FileVersion>5.2111.19.1</FileVersion>
+    <Version>5.2111.22</Version>
+    <AssemblyVersion>5.2111.22.1</AssemblyVersion>
+    <FileVersion>5.2111.22.1</FileVersion>
     <Description>TEAMModelOS(IES5)</Description>
     <PackageReleaseNotes>版本说明</PackageReleaseNotes>
   </PropertyGroup>