소스 검색

Merge branch 'develop' of http://52.130.252.100:10000/TEAMMODEL/TEAMModelOS into develop

zhouj1203@hotmail.com 2 년 전
부모
커밋
d8d5913eac

+ 77 - 18
TEAMModelBI/Controllers/Census/SchoolController.cs

@@ -26,6 +26,7 @@ using TEAMModelOS.SDK.Models.Cosmos.BI.BISchool;
 using TEAMModelOS.SDK.Models.Service.BI;
 using TEAMModelOS.SDK.Models.Service.BIStatsWay;
 using static TEAMModelBI.Controllers.Census.SchoolController;
+using LessonStats = TEAMModelOS.SDK.Models.Cosmos.BI.LessonStats;
 
 namespace TEAMModelBI.Controllers.Census
 {
@@ -538,6 +539,7 @@ namespace TEAMModelBI.Controllers.Census
                 if (!string.IsNullOrEmpty(statsInfo.id))
                 {
                     scStats.id = statsInfo.id;
+                    scStats.schoolId = statsInfo.schoolId;
                     scStats.name = statsInfo.name;
                     scStats.picture = statsInfo.picture;
                     scStats.areaId = statsInfo.areaId;
@@ -569,7 +571,7 @@ namespace TEAMModelBI.Controllers.Census
                     scStats.lessStats.monthInter = statsInfo.lesson.monthInter;
                     scStats.lessStats.lastYearInter = statsInfo.lesson.lastYearInter;
                     scStats.lessStats.yearInter = statsInfo.lesson.yearInter;
-                    //scStats.lessStats.LastYear = TimeHelper.GetYearMonth(statsInfo.lesson.LastYear, dateTime.Year, dateTime.Month);
+                    scStats.lessStats.yearInters = TimeHelper.GetYearMonth(statsInfo.lesson.yearInters, dateTime.Year, dateTime.Month);
                     scStats.lessStats.year = TimeHelper.GetYearMonth(statsInfo.lesson.year, dateTime.Year, dateTime.Month);
                     scStats.actStats.all = statsInfo.activity.all;
                     scStats.actStats.exam = statsInfo.activity.exam;
@@ -640,25 +642,52 @@ namespace TEAMModelBI.Controllers.Census
         [HttpPost("get-areastats")]
         public async Task<IActionResult> GetAreaStats(JsonElement jsonElement)
         {
-            if (!jsonElement.TryGetProperty("areaId", out JsonElement areaId)) return BadRequest();
+            jsonElement.TryGetProperty("areaId", out JsonElement areaId);
+            jsonElement.TryGetProperty("tmdId", out JsonElement tmdId);
+            jsonElement.TryGetProperty("role", out JsonElement role);
 
-            var cosmosClient = _azureCosmos.GetCosmosClient();
+            if (string.IsNullOrEmpty($"{areaId}") && string.IsNullOrEmpty($"{tmdId}"))
+                return Ok(new { stats = RespondCode.ParamsError, msg = "areaId/tmdId两者参数不能都为空!" });
 
-            Area area = new();
+            var cosmosClient = _azureCosmos.GetCosmosClient();
+            Area area = null;
             ScStats areaScStats = new();
+            List<string> scIds = new();
 
-            var respSc = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemStreamAsync($"{areaId}", new PartitionKey($"Base-Area"));
-            if (respSc.Status == 200)
+            StringBuilder scSql = new("select value(c.id) from c");
+            StringBuilder lastScSql = new("select value(c.id) from c");
+            if (!string.IsNullOrEmpty($"{areaId}"))
             {
-                using var fileJson = await JsonDocument.ParseAsync(respSc.ContentStream);
-                area = fileJson.ToObject<Area>();
+                scSql.Append($" where c.areaId='{areaId}'");
+                lastScSql.Append($" where c.areaId='{areaId}'");
+                var respSc = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemStreamAsync($"{areaId}", new PartitionKey($"Base-Area"));
+                if (respSc.Status == 200)
+                {
+                    using var fileJson = await JsonDocument.ParseAsync(respSc.ContentStream);
+                    area = fileJson.ToObject<Area>();
+                }
+                else
+                    return Ok(new { state = RespondCode.NotFound, msg = $"未找到id:{areaId};相关的学区,请检查!" });
             }
-            else
-                return Ok(new { state = RespondCode.NotFound, msg = $"未找到id:{areaId};相关的学区,请检查!" });
 
-            List<string> scIds = new();
-            string scSql = $"select value(c.id) from c where c.areaId='{areaId}'";
-            scIds = await CommonFind.FindScIds(cosmosClient, scSql, "Base");
+            if (!string.IsNullOrEmpty($"{tmdId}")) 
+            {
+                switch ($"{role}")
+                {
+                    case "assists":
+                        scSql.Append($" join a in c.assists where a.id='{tmdId}'");
+                        lastScSql.Append($" join a in c.assists where a.id='{tmdId}'");
+                        break;
+                    case "sales":
+                        scSql.Append($" join a in c.sales where a.id='{tmdId}'");
+                        lastScSql.Append($" join a in c.sales where a.id='{tmdId}'");
+                        break;
+                    default:
+                        return Ok(new { state = RespondCode.ParamsError, msg = "role参数错误" });
+                }
+            }
+
+            scIds = await CommonFind.FindScIds(cosmosClient, scSql.ToString(), "BIRel");
             StringBuilder statsSql = new("select value(c) from c");
             if (scIds.Count > 0)
             {
@@ -673,11 +702,24 @@ namespace TEAMModelBI.Controllers.Census
                 statsInfos.Add(item);
             }
 
-            StatsInfo statsInfo = new();
+            StringBuilder lastStsSql = new("select c.lesson,c.activity from c");
+            if (scIds.Count > 0)
+            {
+                lastStsSql.Append($" where {BICommonWay.ManyScSql("c.id", scIds, $"{DateTimeOffset.UtcNow.Year - 1}-")}");
+            }
+            List<LastYearLessAndAct> lastYear = new();
+
+            await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<LastYearLessAndAct>(queryText: lastStsSql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Statistics") }))
+            {
+                lastYear.Add(item);
+            }
+
+            StatsInfo statsInfo = null;
             statsInfo = SchoolStatsWay.GetAreaStats(cosmosClient, _httpTrigger, _option, statsInfos, scIds, area);
-            if (!string.IsNullOrEmpty(statsInfo.id))
+            if (statsInfo != null)
             {
                 areaScStats.id = statsInfo.id;
+                areaScStats.schoolId = statsInfo.schoolId;
                 areaScStats.name = statsInfo.name;
                 areaScStats.picture = statsInfo.picture;
                 areaScStats.areaId = statsInfo.areaId;
@@ -709,7 +751,8 @@ namespace TEAMModelBI.Controllers.Census
                 areaScStats.lessStats.monthInter = statsInfo.lesson.monthInter;
                 areaScStats.lessStats.lastYearInter = statsInfo.lesson.lastYearInter;
                 areaScStats.lessStats.yearInter = statsInfo.lesson.yearInter;
-                //areaScStats.lessStats.LastYear = TimeHelper.GetYearMonth(statsInfo.lesson.LastYear, dateTime.Year, dateTime.Month);
+                areaScStats.lessStats.yearInters = TimeHelper.GetYearMonth(statsInfo.lesson.yearInters, dateTime.Year, dateTime.Month);
+                areaScStats.lessStats.LastYear = TimeHelper.GetYearMonth(BICommonWay.ManyDoubleMerge(lastYear.Select(s => s.lesson.year).Where(w => w.Count > 0).ToList()), dateTime.Year, dateTime.Month);
                 areaScStats.lessStats.year = TimeHelper.GetYearMonth(statsInfo.lesson.year, dateTime.Year, dateTime.Month);
                 areaScStats.actStats.all = statsInfo.activity.all;
                 areaScStats.actStats.exam = statsInfo.activity.exam;
@@ -722,7 +765,7 @@ namespace TEAMModelBI.Controllers.Census
                 areaScStats.actStats.week = statsInfo.activity.week;
                 areaScStats.actStats.lastTerm = statsInfo.activity.lastTerm;
                 areaScStats.actStats.term = statsInfo.activity.term;
-                //areaScStats.actStats.LastYear = TimeHelper.GetYearMonth(statsInfo.activity.LastYear, dateTime.Year, dateTime.Month);
+                areaScStats.actStats.LastYear = TimeHelper.GetYearMonth(BICommonWay.ManyDoubleMerge(lastYear.Select(s => s.lesson.year).Where(w => w.Count > 0).ToList()), dateTime.Year, dateTime.Month);
                 areaScStats.actStats.year = TimeHelper.GetYearMonth(statsInfo.activity.year, dateTime.Year, dateTime.Month);
                 if (statsInfo.study != null)
                 {
@@ -828,6 +871,7 @@ namespace TEAMModelBI.Controllers.Census
         public record ScStats
         {
             public string id { get; set; }
+            public string schoolId { get; set; }
             public string name { get; set; }
             public string picture { get; set; }
             public string areaId { get; set; }
@@ -871,7 +915,7 @@ namespace TEAMModelBI.Controllers.Census
             public int monthInter { get; set; }
             public int lastYearInter { get; set; }
             public int yearInter { get; set; }
-            //public List<YearMonth> yearInter { get; set; } = new List<YearMonth>();//12个月
+            public List<YearMonth> yearInters { get; set; } = new List<YearMonth>();//12个月
             public List<YearMonth> LastYear { get; set; } = new List<YearMonth>();//12个月
             public List<YearMonth> year { get; set; } = new List<YearMonth>();    //12个月
         }
@@ -911,5 +955,20 @@ namespace TEAMModelBI.Controllers.Census
             public int finish { get; set; }
         }
 
+        /// <summary>
+        /// 查询去年的统计
+        /// </summary>
+        public record LastYearLessAndAct
+        {
+            /// <summary>
+            /// 课例活动
+            /// </summary>
+            public LessonStats lesson { get; set; } = new LessonStats();
+
+            /// <summary>
+            /// 活动
+            /// </summary>
+            public ActivityStats activity { get; set; } = new ActivityStats();
+        }
     }
 }

+ 8 - 4
TEAMModelBI/Controllers/RepairApi/SchoolRepController.cs

@@ -500,6 +500,7 @@ namespace TEAMModelBI.Controllers.RepairApi
         public async Task<IActionResult> SetAllScStats(JsonElement jsonElement) 
         {
             jsonElement.TryGetProperty("scId", out JsonElement scId);
+            jsonElement.TryGetProperty("year", out JsonElement _year);
             var cosmosClient = _azureCosmos.GetCosmosClient();
             
             List<string> scIds = new();
@@ -509,13 +510,16 @@ namespace TEAMModelBI.Controllers.RepairApi
                 scIds = await CommonFind.FindScIds(cosmosClient, "select value(c.id) from c ", "Base");
 
             DateTimeOffset dateTime = DateTimeOffset.UtcNow;
+            int year = dateTime.Year;
+            if (!string.IsNullOrEmpty($"{_year}"))
+                year = _year.GetInt32();
 
             List<StatsInfo> statsInfos = new();
             List<Task<ItemResponse<StatsInfo>>> taskStss = new();
             foreach (var sc in scIds) 
             {
                 StatsInfo statsInfo = new();
-                var scDataStats = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync($"{dateTime.Year}-{sc}", new PartitionKey("Statistics"));
+                var scDataStats = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync($"{year}-{sc}", new PartitionKey("Statistics"));
                 if (scDataStats.Status == 200)
                 {
                     using var fileJson = await JsonDocument.ParseAsync(scDataStats.ContentStream);
@@ -523,13 +527,13 @@ namespace TEAMModelBI.Controllers.RepairApi
                 }
                 else
                 {
-                    statsInfo.id = $"{dateTime.Year}-{sc}";
+                    statsInfo.id = $"{year}-{sc}";
                 }
 
-                statsInfo = await SchoolStatsWay.GetSingleSc(cosmosClient, sc);
+                statsInfo = await SchoolStatsWay.GetSingleSc(cosmosClient, sc, year);
 
                 if (scDataStats.Status == 200)
-                    taskStss.Add(cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<StatsInfo>(statsInfo, $"{dateTime.Year}-{sc}", new PartitionKey("Statistics")));
+                    taskStss.Add(cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<StatsInfo>(statsInfo, $"{year}-{sc}", new PartitionKey("Statistics")));
                 else
                     taskStss.Add(cosmosClient.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync<StatsInfo>(statsInfo, new PartitionKey("Statistics")));
 

+ 4 - 1
TEAMModelOS.SDK/Models/Cosmos/BI/StatsInfo.cs

@@ -201,7 +201,10 @@ namespace TEAMModelOS.SDK.Models.Cosmos.BI
         /// 今年互动
         /// </summary>
         public int yearInter { get; set; }
-        //public List<double> yearInter { get; set; } = new List<double>();
+        /// <summary>
+        /// 今年互动
+        /// </summary>
+        public List<double> yearInters { get; set; } = new List<double>();
 
         /// <summary>
         /// 去年每天的数据  366天

+ 232 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/VRARLessonRecord.cs

@@ -0,0 +1,232 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.Json;
+
+namespace TEAMModelOS.SDK.Models
+{
+    /// <summary>
+    /// 课堂记录简要信息。
+    /// </summary>
+    public class VRARLessonRecord : CosmosEntity
+    {
+        /// <summary>
+        ///必填 教师醍摩豆id
+        /// </summary>
+        public string tmdid { get; set; }
+        /// <summary>
+        /// 教师醍摩豆id名称
+        /// </summary>
+        public string tmdname { get; set; }
+        /// <summary>
+        /// 教师醍摩豆id名称
+        /// </summary>
+        public string tmdpicture { get; set; }
+        /// <summary>
+        ///必填 课堂名称
+        /// </summary>
+        public string name { get; set; }
+        /// <summary>
+        ///必填 scope==school必填 | string | 学校id
+        /// </summary>
+        public string school { get; set; }
+        /// <summary>
+        ///必填  private/school|
+        /// </summary>
+        public string scope { get; set; }
+        /// <summary>
+        ///必填  视频封面地址
+        /// </summary>
+       // public string poster { get; set; }
+        /// <summary>
+        ///必填 开始时间(时间戳) 1606393763434
+        /// </summary>
+        public long startTime { get; set; }
+        /// <summary>
+        ///必填 上课时长,最后更新
+        /// </summary>
+        public double duration { get; set; }
+        /// <summary>
+        ///选填  t分,科技应用 ,最后更新
+        /// </summary>
+        public int tScore { get; set; }
+        /// <summary>
+        ///选填   p分,教法应用 ,最后更新
+        /// </summary>
+        public int pScore { get; set; }
+        /// <summary>
+        ///选填  t灯,科技应用 0红灯,1 黄灯,2绿灯
+        /// </summary>
+        public int tLevel { get; set; } = -1;
+        /// <summary>
+        ///选填   p灯,教法应用 0红灯,1 黄灯,2绿灯
+        /// </summary>
+        public int pLevel { get; set; } = -1;
+        /// <summary>
+        ///选填  选用IES5的课程id 
+        /// </summary>
+        public string courseId { get; set; }
+        /// <summary>
+        /// 选填   课程名称  是因支持VR/AR那边课例
+        /// </summary>
+        public string courseName { get; set; }
+        /// <summary>
+        ///选填 选用IES5固定名单的id
+        /// </summary>
+        public List<string> groupIds { get; set; } = new List<string>();
+        public List<string> groupNames { get; set; } = new List<string>();
+        /// <summary>
+        ///选填  学生人数 ,最后更新
+        /// </summary>
+        public int mCount { get; set; }
+        /// <summary>
+        ///选填  议课次数,大于1则是优课,苏格拉底获取
+        /// </summary>
+        public int discuss { get; set; }
+        /// <summary>
+        ///选填  科技互动次数, 
+        /// </summary>
+        public int techCount { get; set; }
+        /// <summary>
+        /// 学 不填 段id,由课程或者名单获取 
+        /// </summary>
+        public string periodId { get; set; }
+        /// <summary>
+        /// 选填 学段名称  是因支持VR/AR那边课例
+        /// </summary>
+        public string periodName { get; set; }
+        /// <summary>
+        ///  不填 科目id,由课程id获取
+        /// </summary>
+        public string subjectId { get; set; }
+        /// <summary>
+        /// 选填   科目名称  是因支持VR/AR那边课例
+        /// </summary>
+        public string subjecName { get; set; }
+        /// <summary>
+        /// 不填 年级id,由名单id获取
+        /// </summary>
+        public List<string> grade { get; set; } = new List<string>();
+        public List<string> gradeName { get; set; } = new List<string>();
+        /// <summary>
+        /// 不填  收藏次数,IES5更新 
+        /// </summary>
+        public int favorite { get; set; }
+        /// <summary>
+        /// 不填 点赞数
+        /// </summary>
+        public int like { get; set; }
+        /// <summary>
+        /// 不填 分享转发数
+        /// </summary>
+        public int share { get; set; }
+        /// <summary>
+        /// 不填  ["混合学习","语文教研"]课例类别,tag标签,IES5维护
+        /// </summary>
+        public List<string> category { get; set; } = new List<string>();
+        /// <summary>
+        /// 0 是否包含视频,1包含视频
+        /// </summary>
+        public int hasVideo { get; set; }
+        //public long videoSize { get; set; }
+        /// <summary>
+        /// 
+        /// 科技互动详细次数。[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49]
+        /// </summary>
+        public List<int> tech { get; set; } = new List<int>();
+        public int status { get; set; } = 0;
+        /// <summary>
+        /// 专家好课,默认0, 1 是好课
+        /// </summary>
+        public int excellent { get; set; } = 0;
+        /// <summary>
+        /// 出席人数
+        /// </summary>
+        public int attendCount { get; set; } = 0;
+        /// <summary>
+        /// 总人数
+        /// </summary>
+        public int clientCount { get; set; } = 0;
+        /// <summary>
+        ///出席率
+        /// </summary>
+        public double attendRate { get; set; } = 0;
+        /// <summary>
+        /// 小组数
+        /// </summary>
+        public int groupCount { get; set; } = 0;
+        /// <summary>
+        /// 任务总数,作品收集任务数
+        /// </summary>
+        public int collateTaskCount { get; set; } = 0;
+        /// <summary>
+        /// 作品总数
+        /// </summary>
+        public int collateCount { get; set; } = 0;
+        /// <summary>
+        /// 推送总数(页面,资源,讯息,差异化)
+        /// </summary>
+        public int pushCount { get; set; } = 0;
+        /// <summary>
+        /// 总计分
+        /// </summary>
+        public double totalPoint { get; set; } = 0;
+        /// <summary>
+        /// 测验总题数
+        /// </summary>
+        public int examQuizCount { get; set; } = 0;
+        /// <summary>
+        /// 互动题数
+        /// </summary>
+        public int interactionCount { get; set; } = 0;
+        /// <summary>
+        /// 测验得分率
+        /// </summary>
+        public double examPointRate { get; set; } = 0;
+        /// <summary>
+        /// 学生互动总数
+        /// </summary>
+        public int clientInteractionCount { get; set; } = 0;
+        /// <summary>
+        /// 学生互动率
+        /// </summary>
+        public double clientInteractionAverge { get; set; } = 0;
+
+        public int examCount { get; set; }
+        /// <summary>
+        /// 总互动分
+        /// </summary>
+        public double totalInteractPoint { get; set; } = 0;
+        /// <summary>
+        /// 过期时间,-1永不过期, 1577808000000 2020-01-01
+        /// </summary>
+        public long expire { get; set; } = -1;
+        /// <summary>
+        /// 先使用这种模式,["all","student"], 暂不 开放 school【开放给部分学校查看】,teacher【开放给部分教师查看】   ["all","school","teacher","student"]
+        /// </summary>
+        public List<string> show { get; set; } = new List<string>();
+        /// <summary>
+        /// 暂不 开放 school【开放给部分学校查看】学校编码
+        /// </summary>
+        public List<string> showSchs { get; set; } = new List<string>();
+        /// <summary>
+        /// 暂不 开放 teacher【开放给部分教师查看】醍摩豆id 
+        /// </summary>
+        public List<string> showTchs { get; set; } = new List<string>();
+        /// <summary>
+        /// 设置强制保留的 =1 ,不会被自动清理的。但是可以被手动清理。
+        /// </summary>
+        public int save { get; set; } = -1;
+        /// <summary>
+        /// 默认未上传
+        /// </summary>
+        public int upload { get; set; }
+
+        public LearningCategory learningCategory { get; set; } = new LearningCategory();
+        public int hitaClientCmpCount { get; set; }
+        /// <summary>
+        /// 课例来源 0 本公司  1 第三方公司    是因支持VR/AR那边课例
+        /// </summary>
+        public int source { get; set; } = 0;
+    }
+}

+ 18 - 12
TEAMModelOS.SDK/Models/Service/BIStatsWay/LessonRecordStatsWay.cs

@@ -46,7 +46,7 @@ namespace TEAMModelOS.SDK.Models.Service.BIStatsWay
             lessStats.less = await JointlySingleQuery.GetValueInt(cosmosClient, "School", $"{currSql} and c.upload = 1", $"LessonRecord-{id}");
 
             List<LessRelStats> lessRelStats = new();
-            string sql = $"select c.id,c.code,c.startTime,c.clientInteractionCount from c where c.pk='LessonRecord' and c.startTime >= {lastYearS} and c.startTime <= {yearE}";
+            string sql = $"select c.id,c.code,c.startTime,c.clientInteractionCount from c where c.pk='LessonRecord' and c.startTime >= {yearS} and c.startTime <= {yearE}";
             await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<LessRelStats>(queryText: sql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonRecord-{id}") }))
             {
                 lessRelStats.Add(item);
@@ -61,22 +61,28 @@ namespace TEAMModelOS.SDK.Models.Service.BIStatsWay
 
             lessStats.lastDayInter = lessRelStats.FindAll(f => f.startTime >= lastDayS && f.startTime <= lastdayE).ToList().Select(s => s.clientInteractionCount).Sum();
             lessStats.dayInter = lessRelStats.FindAll(f => f.startTime >= dayS && f.startTime <= dayS).ToList().Select(s => s.clientInteractionCount).Sum();
-            lessStats.lastMonthInter = lessRelStats.FindAll(f => f.startTime >= lastWeekS && f.startTime <= lastWeekE).ToList().Select(s => s.clientInteractionCount).Sum();
-            lessStats.monthInter = lessRelStats.FindAll(f => f.startTime >= weekS && f.startTime <= weekS).ToList().Select(s => s.clientInteractionCount).Sum();
-            lessStats.lastYearInter = lessRelStats.FindAll(f => f.startTime >= lastTermS && f.startTime <= lastTermE).ToList().Select(s => s.clientInteractionCount).Sum();
-            lessStats.yearInter = lessRelStats.FindAll(f => f.startTime >= termS && f.startTime <= termE).ToList().Select(s => s.clientInteractionCount).Sum();
+            lessStats.lastMonthInter = lessRelStats.FindAll(f => f.startTime >= lastMthS && f.startTime <= LastmthE).ToList().Select(s => s.clientInteractionCount).Sum();
+            lessStats.monthInter = lessRelStats.FindAll(f => f.startTime >= mthS && f.startTime <= mthE).ToList().Select(s => s.clientInteractionCount).Sum();
+            //lessStats.lastYearInter = lessRelStats.FindAll(f => f.startTime >= lastYearS && f.startTime <= lastYearE).ToList().Select(s => s.clientInteractionCount).Sum();
+            lessStats.lastYearInter = await JointlySingleQuery.GetValueInt(cosmosClient, "School", $"select value(sum(c.clientInteractionCount)) from c where c.startTime >= {lastYearS} and c.startTime <= {lastYearE}", $"LessonRecord-{id}");
+            lessStats.yearInter = lessRelStats.FindAll(f => f.startTime >= yearS && f.startTime <= yearE).ToList().Select(s => s.clientInteractionCount).Sum();
 
             DateTimeOffset lyearDay = new(DateTimeOffset.UtcNow.Year - 1, DateTimeOffset.UtcNow.Month, DateTimeOffset.UtcNow.Day, DateTimeOffset.UtcNow.Hour, DateTimeOffset.UtcNow.Minute, DateTimeOffset.UtcNow.Second, TimeSpan.Zero);
             List<StartEndTime> leveryDay = TimeHelper.GetYearEveryDay(lyearDay);
             List<StartEndTime> everyDay = TimeHelper.GetYearEveryDay(DateTimeOffset.UtcNow);
 
-            //for (int i = 0; i < leveryDay.Count; i++)
-            //{
-            //    if (lessStats.LastYear.Count == 366)
-            //        lessStats.LastYear[i] = (double)lessRelStats.FindAll(f => (f.startTime >= leveryDay[i].start && f.startTime <= leveryDay[i].end)).Count;
-            //    else
-            //        lessStats.LastYear.Add((double)lessRelStats.FindAll(f => (f.startTime >= leveryDay[i].start && f.startTime <= leveryDay[i].end)).Count);
-            //}
+            List<double> doubles = new();
+            List<object> list = new();
+            List<object> list1 = new();
+
+            for (int i = 0; i < everyDay.Count; i++)
+            {
+                if (lessStats.yearInters.Count == 366)
+                    lessStats.yearInters[i] = (double)lessRelStats.FindAll(f => (f.startTime >= everyDay[i].start && f.startTime <= everyDay[i].end)).Select(s => s.clientInteractionCount).Sum();
+                else
+                    lessStats.yearInters.Add((double)lessRelStats.FindAll(f => (f.startTime >= everyDay[i].start && f.startTime <= everyDay[i].end)).Select(s => s.clientInteractionCount).Sum());
+                
+            }
 
             for (int i = 0; i < everyDay.Count; i++)
             {

+ 28 - 4
TEAMModelOS.SDK/Models/Service/BIStatsWay/SchoolStatsWay.cs

@@ -26,10 +26,12 @@ namespace TEAMModelOS.SDK.Models.Service.BIStatsWay
         /// <param name="cosmosClient"></param>
         /// <param name="scId"></param>
         /// <returns></returns>
-        public static async Task<StatsInfo> GetSingleSc(CosmosClient cosmosClient, string scId)
+        public static async Task<StatsInfo> GetSingleSc(CosmosClient cosmosClient, string scId, int year = 0)
         {
             DateTimeOffset dateTime = DateTimeOffset.UtcNow;
-            StatsInfo statsInfo = new() { id = $"{dateTime.Year}-{scId}" };
+            if (year == 0)
+                year = dateTime.Year;
+            StatsInfo statsInfo = new() { id = $"{year}-{scId}" };
             var (dayS, dayE) = TimeHelper.GetStartOrEnd(dateTime);  //今天开始时间    13位
             var (lastWeekS, lastWeekE) = TimeHelper.GetStartOrEnd(dateTime, "lastweek");   //计算上周开始/结束时间
             var (weekS, weekE) = TimeHelper.GetStartOrEnd(dateTime, "week");             //计算本周开始/结束时间
@@ -55,6 +57,7 @@ namespace TEAMModelOS.SDK.Models.Service.BIStatsWay
             statsInfo.size = scBase.size;
             statsInfo.scCreateTime = scBase.createTime;
             statsInfo.areaId = scBase.areaId;
+            statsInfo.year = year;
 
             string tchSql = $"{currSql} where ARRAY_CONTAINS(c.roles, 'teacher', true) AND c.status = 'join'";
             statsInfo.tch = await JointlySingleQuery.GetValueInt(cosmosClient, "School", tchSql, code: $"Teacher-{scBase.id}");
@@ -92,7 +95,7 @@ namespace TEAMModelOS.SDK.Models.Service.BIStatsWay
         /// <param name="_option"></param>
         /// <param name="area"></param>
         /// <returns></returns>
-        public static StatsInfo GetAreaStats(CosmosClient cosmosClient, HttpTrigger _httpTrigger, Option _option, List<StatsInfo> statsInfos, List<string> scIds = null, Area area = null) 
+        public static StatsInfo GetAreaStats(CosmosClient cosmosClient, HttpTrigger _httpTrigger, Option _option, List<StatsInfo> statsInfos, List<string> scIds = null, Area area = null)
         {
             StatsInfo areaInfo = new()
             {
@@ -129,7 +132,7 @@ namespace TEAMModelOS.SDK.Models.Service.BIStatsWay
             areaInfo.lesson.monthInter = statsInfos.Select(s => s.lesson.monthInter).Sum();
             areaInfo.lesson.lastYearInter = statsInfos.Select(s => s.lesson.lastYearInter).Sum();
             areaInfo.lesson.yearInter = statsInfos.Select(s => s.lesson.yearInter).Sum();
-            //areaInfo.lesson.LastYear = BICommonWay.ManyDoubleMerge(statsInfos.Select(s => s.lesson.LastYear).ToList());
+            areaInfo.lesson.yearInters = BICommonWay.ManyDoubleMerge(statsInfos.Select(s => s.lesson.yearInters).ToList());
             areaInfo.lesson.year = BICommonWay.ManyDoubleMerge(statsInfos.Select(s => s.lesson.year).Where(w => w.Count > 0).ToList());
 
 
@@ -210,5 +213,26 @@ namespace TEAMModelOS.SDK.Models.Service.BIStatsWay
             return areaInfo;
         }
 
+        public static async Task<List<T>> GetLastYearType<T>(CosmosClient cosmosClient, List<string> scIds)
+        {
+            List<T> list = new();
+            StringBuilder statsSql = new("select value(c) from c");
+            if (scIds.Count > 0)
+            {
+                statsSql.Append($" where {BICommonWay.ManyScSql("c.id", scIds, $"{DateTimeOffset.UtcNow.Year - 1}-")}");
+            }
+
+
+            await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<T>(queryText: statsSql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Statistics") }))
+            {
+                list.Add(item);
+
+            }
+
+            return list;
+        }
+
+
+       
     }
 }

+ 4 - 0
TEAMModelOS/ClientApp/src/api/lessonRecord.js

@@ -1,5 +1,9 @@
 import { post } from '@/api/http'
 export default {
+    /* 上传课堂记录报告截图 */
+    uploadReportImg: function (data) {
+        return post('/blob/public-upload-lesson-report', data)
+    },
     /* 获取课例统计数量 */
     getLessonCount: function (data) {
         return post('/common/lesson-record/get-lesson-record-count', data)

+ 1 - 1
TEAMModelOS/ClientApp/src/view/login/page/Student.vue

@@ -515,7 +515,7 @@ export default {
             if (data.sid) {
               let qrcodeURL = url + '/qrcode/login?sid=' + encodeURIComponent(data.sid,
                 "utf-8") + '&info=' + encodeURIComponent(_this.$t('login.sse.text1'),
-                  "utf-8") + `&m=${encodeURIComponent(_this.$t('qrCode.tip2'), "utf-8")}IES5&o=0`
+                  "utf-8") + `&m=${encodeURIComponent(_this.$t('qrCode.tip2'), "utf-8")}IES5`
               _this.crtQrcode(qrcodeURL)
             } else if (data.code) {
               closeSSE()

+ 1 - 1
TEAMModelOS/ClientApp/src/view/login/page/Teacher.vue

@@ -388,7 +388,7 @@ export default {
           if (e.data) {
             let data = JSON.parse(e.data)
             if (data.sid) {
-              let qrcodeURL = url + '/qrcode/login?sid=' + encodeURIComponent(data.sid, "utf-8") + '&info=' + encodeURIComponent(_this.$t('login.sse.text1'), "utf-8") + `&m=${encodeURIComponent(_this.$t('qrCode.tip2'), "utf-8")}IES5&o=0`
+              let qrcodeURL = url + '/qrcode/login?sid=' + encodeURIComponent(data.sid, "utf-8") + '&info=' + encodeURIComponent(_this.$t('login.sse.text1'), "utf-8") + `&m=${encodeURIComponent(_this.$t('qrCode.tip2'), "utf-8")}IES5`
               _this.crtQrcode(qrcodeURL)
             } else if (data.code) {
               closeSSE()

+ 62 - 2
TEAMModelOS/ClientApp/src/view/research-center/ResearchMgt.vue

@@ -263,7 +263,8 @@
       <div slot="header">
         <p style="text-align: center;font-weight: bold">【{{ curLessonRecord.name }}】 {{ $t('lessonRecord.mgt.report') }}</p>
       </div>
-      <div>
+      <div ref="reportBox">
+        <p style="text-align: center;font-weight: bold;font-size: 18px;margin:20px 0" v-if="isShowTitle">【{{ curLessonRecord.name }}】 {{ $t('lessonRecord.mgt.report') }}</p>
         <div style="display: flex;justify-content: center;font-weight: bold">
           <span style="display: flex;justify-content: center;flex-direction: column;align-items: center">
             <span :style="{ backgroundColor: getLevelColor(curLessonRecord.tLevel),boxShadow:'0 0 6px ' + getLevelColor(curLessonRecord.tLevel) }" class="level-light"></span>
@@ -327,6 +328,11 @@
         <!-- <BaseReportPie v-if="reportModal" :lessonInfo="curLessonRecord"></BaseReportPie> -->
         <BaseReportRadar v-if="reportModal" :lessonInfo="curLessonRecord"></BaseReportRadar>
       </div>
+      <span class="iconfont icon-qr-code" style="color: #3fa8ff;font-size: 22px;margin:0 auto;text-align: center;display: inline-block;cursor: pointer;" :title="$t('syllabus.share')" @click.stop="doShareQrCode" />
+    </Modal>
+    <Modal v-model="qrModal" transfer width="450" footer-hide class="research-modal">
+      <div id="lessonCode" ref="qrcode" style="padding:25px 25px 20px 25px;background-color:white;width:330px;margin:auto;"></div>
+      <p style="text-align:center;color: #3fa8ff;font-size:16px">扫描二维码,查看智慧课堂报告</p>
     </Modal>
   </div>
 </template>
@@ -337,6 +343,8 @@ import BaseCleanCond from './BaseCleanCond.vue'
 import BaseReportPie from './BaseReportPie.vue'
 import BaseReportRadar from './BaseReportRadar.vue'
 import excel from '@/utils/excel.js'
+import domtoimage from '@/utils/dom_to_image';
+import QRCode from 'qrcodejs2'
 export default {
   components: {
     BaseTypeMgmt,
@@ -347,6 +355,8 @@ export default {
   },
   data(vm) {
     return {
+      isShowTitle: false,
+      qrModal: false,
       batchDelArr: [],
       classTotalCount: 0,
       filterClassIds: [],
@@ -753,7 +763,8 @@ export default {
           width: 180
         }
       ],
-      originList: []
+      originList: [],
+      joinQRcode: null
     }
   },
   created() {
@@ -762,6 +773,55 @@ export default {
     // this.getAnalysisCount()
   },
   methods: {
+    // dataurl 为传进来的base64格式的图片地址, return 返回的为file格式
+    base64ImgtoFile(dataurl, filename = 'file') {
+      let arr = dataurl.split(',')
+      let mime = arr[0].match(/:(.*?);/)[1]
+      let suffix = mime.split('/')[1]
+      let bstr = atob(arr[1])
+      let n = bstr.length
+      let u8arr = new Uint8Array(n)
+      while (n--) {
+        u8arr[n] = bstr.charCodeAt(n)
+      }
+      return new File([u8arr], `${filename}.${suffix}`, {
+        type: mime
+      })
+    },
+    doShareQrCode() {
+      console.log(this.$refs.reportBox)
+      this.isShowTitle = true
+      this.qrModal = true
+      domtoimage.toJpeg(this.$refs.reportBox, {
+        bgcolor: '#fff'
+      }).then(res => {
+        this.isShowTitle = false
+        console.log(this.curLessonRecord)
+        let { id } = this.curLessonRecord
+        let imgFile = this.base64ImgtoFile(res, id)
+        console.log(imgFile)
+        const formData = new FormData()
+        formData.append('file', imgFile)
+        this.$api.lessonRecord.uploadReportImg(formData).then(result => {
+          let imgUrl = result.url
+          setTimeout(() => {
+            if (this.joinQRcode == undefined) {
+              let qrcode = new QRCode('lessonCode', {
+                width: 280, // 设置宽度,单位像素
+                height: 280, // 设置高度,单位像素
+                text: encodeURI(imgUrl), // 编码处理
+                correctLevel: QRCode.CorrectLevel.Q //解决编码后网址太长的问题
+              })
+              this.joinQRcode = qrcode
+            } else {
+              this.joinQRcode.clear()
+              this.joinQRcode.makeCode(encodeURI(imgUrl))
+            }
+          }, 500)
+        })
+
+      })
+    },
     doShowRadar(item) {
       this.curLessonRecord = item
       this.reportModal = true

+ 1 - 1
TEAMModelOS/ClientApp/src/view/teachermgmt/components/personnel/Index.vue

@@ -428,7 +428,7 @@ export default {
               // data.code = this.$store.state.userInfo.schoolCode
               // data.name = this.$store.state.user?.schoolProfile?.school_base?.name
               // data.random = '123456'
-              let url = `${window.location.origin}/hita/join-school?ts=${res.nowtime}&school=${this.$store.state.userInfo.schoolCode}&sname=${this.$store.state.user?.schoolProfile?.school_base?.name}&m=${this.$t('qrCode.tip1')}${this.$store.state.user?.schoolProfile?.school_base?.name}&o=0`
+              let url = `${window.location.origin}/hita/join-school?ts=${res.nowtime}&school=${this.$store.state.userInfo.schoolCode}&sname=${this.$store.state.user?.schoolProfile?.school_base?.name}&m=${this.$t('qrCode.tip1')}${this.$store.state.user?.schoolProfile?.school_base?.name}`
               // let shortUrl = await this.$api.getShortUrl(encodeURI(url))
               let qrcode = new QRCode('teacher-qr-code', {
                 width: 280, // 设置宽度,单位像素

+ 1 - 1
TEAMModelOS/Controllers/Client/HiScanController.cs

@@ -35,7 +35,7 @@ namespace TEAMModelOS.Controllers.Core
 {
     [ProducesResponseType(StatusCodes.Status200OK)]
     [ProducesResponseType(StatusCodes.Status400BadRequest)]
-    //[Authorize(Roles = "HiTool")]
+    [Authorize(Roles = "HiTool")]
     [Route("hiscan")]
     [ApiController]
     public class HiScanController : ControllerBase

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 445 - 0
TEAMModelOS/Controllers/OpenApi/Business/BizCustomizeController.cs


+ 1 - 10
TEAMModelOS/Controllers/OpenApi/Business/BizOverallEducationController.cs

@@ -11,25 +11,17 @@ using TEAMModelOS.SDK.Context.Constant;
 using System.Collections.Generic;
 using System.Text.Json;
 using TEAMModelOS.SDK.Extension;
-using Top.Api;
-using TEAMModelOS.SDK.Models.Cosmos.Student;
-using DocumentFormat.OpenXml.Math;
-using DocumentFormat.OpenXml.Wordprocessing;
 using TEAMModelOS.Filter;
 using TEAMModelOS.SDK.Models;
 using Azure.Cosmos;
 using TEAMModelOS.SDK.Models.Cosmos.OpenEntity;
 using System;
-using Newtonsoft.Json.Linq;
 using System.Text;
-using DocumentFormat.OpenXml.Spreadsheet;
-using OpenXmlPowerTools;
-using Microsoft.VisualBasic;
 
 namespace TEAMModelOS.Controllers
 {
     /// <summary>
-    /// 企业定制接口
+    /// 五育并举接口
     /// </summary>
     [Route("business")]
     [ApiController]
@@ -90,7 +82,6 @@ namespace TEAMModelOS.Controllers
         }
 
         #region  杉达公司
-
         /// <summary>
         /// 开课或者上传课例信息  是因支持VR/AR的公司(杉达)
         /// </summary>

+ 23 - 1
TEAMModelOS/Controllers/System/BlobController.cs

@@ -83,7 +83,29 @@ namespace TEAMModelOS.Controllers
             else {
                 return BadRequest();
             }
-            
+        }
+        /// <summary>
+        /// 上传文件到指定的0-public  课例报告
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [HttpPost("public-upload-lesson-report")]
+        [Authorize(Roles = "IES")]
+        [AuthToken(Roles = "teacher,admin")]
+        [RequestSizeLimit(102_400_000_00)] //最大10000m左右
+        public async Task<IActionResult> PublicUploadLessonReport([FromForm] IFormFile file)
+        {
+            var (id, _, _, school) = HttpContext.GetAuthTokenInfo();
+            string fileExt = FileType.GetExtention(file.FileName).ToLower();
+            if (ContentTypeDict.dict.ContainsKey($".{fileExt}"))
+            {
+                var url = await _azureStorage.GetBlobContainerClient("0-public").UploadFileByContainer(file.OpenReadStream(), $"lesson-report/{school}", $"{file.FileName}", false);
+                return Ok(new { url });
+            }
+            else
+            {
+                return BadRequest();
+            }
         }
         /// <summary>
         /// 获取某个容器的只读权限

+ 4 - 2
TEAMModelOS/Controllers/Third/Sc/ScDataPushController.cs

@@ -982,7 +982,7 @@ namespace TEAMModelOS.Controllers
                     }
                     if (!pushAll)
                     {
-                        if (pushData.Any()) {
+                        if (pushData.Any() && !pushDatas.ContainsKey(t.tmdid)) {
                             pushDatas.Add(t.tmdid, pushData);
                         }
                     }
@@ -1007,7 +1007,9 @@ namespace TEAMModelOS.Controllers
                     }
                     if (pushData.Any())
                     {
-                        pushDatas.Add(t.tmdid,pushData);
+                        if (!pushDatas.ContainsKey(t.tmdid)) {
+                            pushDatas.Add(t.tmdid, pushData);
+                        }
                         failse.AddRange(fails);
                     }
                 }