Forráskód Böngészése

教师统计页面。

CrazyIter_Bin 3 éve
szülő
commit
0084c845c4

+ 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;

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

@@ -0,0 +1,57 @@
+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 cost { get; set; }
+        public long size { get; set; }
+        public long duration { get; set; }
+        /// <summary>
+        /// video ,doc,
+        /// </summary>
+        public string type { get; set; }
+        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; }
+    }
+}

+ 188 - 10
TEAMModelOS.SDK/Models/Cosmos/Research/TeacherTrain.cs

@@ -2,10 +2,21 @@
 using System.Collections.Generic;
 using System.Text;
 
-namespace TEAMModelOS.SDK.Models.Cosmos.Research
+namespace TEAMModelOS.SDK.Models
 {
-    public class TeacherTrain
+    public class TeacherTrain : CosmosEntity
     {
+        ///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>
@@ -15,6 +26,10 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Research
         /// </summary>
         public int onlineTime { get; set; }
         /// <summary>
+        /// 线上观看视频的学时
+        /// </summary>
+        public long videoTime { get; set; }
+        /// <summary>
         /// 线下研修学时
         /// </summary>
         public int offlineTime { get; set; }
@@ -23,36 +38,191 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Research
         /// </summary>
         public int submitTime { get; set; }
         /// <summary>
-        /// 认证材料学时
+        /// 课堂实录学时
         /// </summary>
         public int classTime { get; set; }
         /// <summary>
         /// 教师能力点情况
         /// </summary>
-        public List<TeacherAility> teacherAilities { get; set; }= new List<TeacherAility>();
+        public List<TeacherAility> teacherAilities { get; set; } = new List<TeacherAility>();
+
+        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 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; }
+        /// <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;
 
-    public class TeacherAility { 
+        /// <summary>
+        /// 待更新的属性
+        /// </summary>
+        public HashSet<string>updateProperty{get;set;}
+    }
+     
+    public class TeacherAility {
+        /// <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 +230,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; }
     }

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

@@ -0,0 +1,462 @@
+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.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.videoTime = file.fileRecords.Where(x => x.type.Equals("video")).Select(y => y.duration).Sum();
+            }
+            train.onlineTime = (int)train.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.uploadTotal += ability.stds.FindAll(x=> x.task.IsNotEmpty()).Select(y=>y.task).Count();
+                    if (item.uploads.IsNotEmpty())
+                    {
+                        train.uploadDone += item.uploads.Count;
+                    }
+                    train.subCount += 1;
+                    if (item.exerciseScore > 0)
+                    {
+                        train.exerciseAbility += 1;
+                    }
+                    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 
+                    };
+                    //train.learnAbility += item.abilityCount;
+                    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);
+                        }
+                    }
+                    train.teacherAilities.Add(teacherAility);
+                }
+            }
+            var bhg = train.teacherAilities.FindAll(x => x.xzscore <= 0);
+            if (bhg.IsEmpty()) {
+                ///要全部合格才能获得学时。
+                train.submitTime = setting.submitTime;
+            }
+            return train;
+        }
+    }
+}

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

@@ -43,6 +43,82 @@ 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) {
+            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>