Просмотр исходного кода

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

chenmy 3 лет назад
Родитель
Сommit
de3025ddd9
23 измененных файлов с 577 добавлено и 232 удалено
  1. 181 0
      TEAMModelAPI/Controllers/School/CourseController.cs
  2. 28 4
      TEAMModelAPI/Controllers/School/ExamController.cs
  3. 57 43
      TEAMModelAPI/Controllers/School/GroupListController.cs
  4. 7 74
      TEAMModelAPI/Controllers/School/SchoolController.cs
  5. 14 9
      TEAMModelOS.SDK/Models/Cosmos/School/Course.cs
  6. BIN
      TEAMModelOS/ClientApp/src/assets/image/none.png
  7. 6 5
      TEAMModelOS/ClientApp/src/common/BaseLayout.vue
  8. 5 1
      TEAMModelOS/ClientApp/src/components/research-dashboard/RightBotR.vue
  9. 4 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/cusMgt.js
  10. 4 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/cusMgt.js
  11. 4 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/cusMgt.js
  12. 8 0
      TEAMModelOS/ClientApp/src/view/classrecord/ClassRecord.less
  13. 47 26
      TEAMModelOS/ClientApp/src/view/classrecord/ClassRecord.vue
  14. 10 6
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/DataCount.vue
  15. 1 1
      TEAMModelOS/ClientApp/src/view/newcourse/EvDetail.vue
  16. 1 0
      TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.less
  17. 26 22
      TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue
  18. 6 2
      TEAMModelOS/ClientApp/src/view/research-center/ResearchCenter.vue
  19. 32 9
      TEAMModelOS/ClientApp/src/view/research-center/ResearchMgt.less
  20. 122 24
      TEAMModelOS/ClientApp/src/view/research-center/ResearchMgt.vue
  21. 2 1
      TEAMModelOS/Controllers/Student/TmdUserController.cs
  22. 12 1
      TEAMModelOS/Controllers/Teacher/TeacherCommonController.cs
  23. 0 1
      TEAMModelOS/appsettings.Development.json

+ 181 - 0
TEAMModelAPI/Controllers/School/CourseController.cs

@@ -0,0 +1,181 @@
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK;
+using TEAMModelOS.SDK.DI;
+using System.Text.Json;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Extension;
+using Azure.Cosmos;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+using System.IO;
+using System.Dynamic;
+using System.Net.Http;
+using System.Net;
+using Newtonsoft.Json;
+using System.Linq;
+using StackExchange.Redis;
+using static TEAMModelOS.SDK.Models.Teacher;
+using Microsoft.Extensions.Configuration;
+using TEAMModelOS.Filter;
+using Microsoft.AspNetCore.Authorization;
+using HTEXLib.COMM.Helpers;
+using TEAMModelOS.SDK.Models.Service;
+namespace TEAMModelAPI.Controllers
+{
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+    [ApiController]
+    [Route("school")]
+    public class CourseController : ControllerBase
+    {
+        public AzureCosmosFactory _azureCosmos;
+        private readonly AzureStorageFactory _azureStorage;
+        private readonly AzureRedisFactory _azureRedis;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+        private readonly IConfiguration _configuration;
+        private readonly CoreAPIHttpService _coreAPIHttpService;
+        private readonly AzureServiceBusFactory _serviceBus;
+        public CourseController(CoreAPIHttpService coreAPIHttpService, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration, AzureServiceBusFactory serviceBus)
+        {
+            _azureCosmos = azureCosmos;
+            _azureStorage = azureStorage;
+            _azureRedis = azureRedis;
+            _dingDing = dingDing;
+            _option = option?.Value;
+            _configuration = configuration;
+            _coreAPIHttpService = coreAPIHttpService;
+            _serviceBus = serviceBus;
+        }
+        /// <summary>
+        ///  获取指定学段作息
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-period-timetable")]
+        [ApiToken(Auth = "1301", Name = "试卷和评测的条件信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetPaperExamCondition(JsonElement json)
+        {
+            json.TryGetProperty("periodId", out JsonElement _periodId);
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+            var period = data.period.Find(x => x.id.Equals($"{_periodId}"));
+            if (period != null)
+            {
+                return Ok(new { period.subjects, period.timetable, period.grades, period.majors });
+            }
+            else
+            {
+                return Ok(new { error = 1, msg = "学段不存在!" });
+            }
+        }
+       
+
+        [ProducesDefaultResponseType]
+        [HttpPost("upsert-course-info")]
+        [ApiToken(Auth = "1302", Name = "课程详细信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> UpsertCourseInfo(JsonElement json)
+        {
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            if (!json.TryGetProperty("course", out JsonElement _course)) { return Ok(new { error = 1, msg = "课程对象不存在" }); }
+            var courseDto = _course.ToObject<CourseDto>();
+            Course course = null;
+            if (courseDto != null && courseDto.Valid().isVaild) {
+                School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+                var period = data.period.Find(x => x.id.Equals($"{courseDto.periodId}"));
+                if (period != null)
+                {
+                    var subject = period.subjects.Find(x => x.id.Equals($"{courseDto.subjectId}"));
+                    if (subject != null)
+                    {
+                        if (string.IsNullOrWhiteSpace(courseDto?.id))
+                        {
+                            course = new Course
+                            {
+                                pk = "Course",
+                                id = Guid.NewGuid().ToString(),
+                                code = $"Course-{school}",
+                                name = courseDto.name,
+                                subject = new SubjectSimple { id = subject.id, name = subject.name  },
+                                period= new PeriodSimple { id = period.id, name = period.name },
+
+                            };
+                        }
+                        else
+                        {
+
+                        }
+                        return Ok(new { period.subjects, period.timetable, period.grades, period.majors });
+                    }
+                    else {
+                        return Ok(new { error = 2, msg = "科目不存在!" });
+                    }
+                }
+                else
+                {
+                    return Ok(new { error = 2, msg = "学段不存在!" });
+                }
+            }
+            else
+            {
+                return Ok(new { error = 3, msg = courseDto.Valid() });
+            }
+            
+        }
+        [ProducesDefaultResponseType]
+        [HttpPost("get-course-list")]
+        [ApiToken(Auth = "1303", Name = "获取课程列表信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetCourseList(JsonElement json)
+        {
+            var client = _azureCosmos.GetCosmosClient();
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            json.TryGetProperty("periodId", out JsonElement periodId);
+            json.TryGetProperty("subjectId", out JsonElement subjectId);
+            StringBuilder sql = new StringBuilder($"SELECT c.id,c.name,c.subject,c.period,c.scope,c.no,c.school FROM c where 1=1 ");
+            if (!string.IsNullOrWhiteSpace($"{periodId}"))
+            {
+                sql.Append($" and c.period.id='{periodId}'");
+            }
+            if (!string.IsNullOrWhiteSpace($"{subjectId}"))
+            {
+                sql.Append($" and c.subject.id='{subjectId}'");
+            }
+            List<dynamic> courses = new List<dynamic>();
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").
+                    GetItemQueryIterator<dynamic>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{school}") }))
+            {
+                courses.Add(item);
+            }
+            return Ok(new { courses });
+        }
+
+        [ProducesDefaultResponseType]
+        [HttpPost("get-course-info")]
+        [ApiToken(Auth = "1304", Name = "课程详细信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetCourseInfo(JsonElement json)
+        {
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            json.TryGetProperty("courseId", out JsonElement courseId);
+            Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School")
+               .ReadItemStreamAsync($"{courseId}", new PartitionKey($"Course-{school}"));
+            if (response.Status == 200)
+            {
+                JsonDocument document = JsonDocument.Parse(response.Content);
+                Course course = document.RootElement.Deserialize<Course>();
+                return Ok(new { course.name, course.id, course.subject, course.period, course.scope, course.school, course.no, course.desc, course.schedule });
+            }
+            else
+            {
+                return Ok(new { error = 1, msg = "课程不存在!" });
+            }
+        }
+
+
+    }
+}

+ 28 - 4
TEAMModelAPI/Controllers/School/ExamController.cs

@@ -53,10 +53,34 @@ namespace TEAMModelAPI.Controllers
             _option = option?.Value;
             _configuration = configuration;
         }
-
+        /// <summary>
+        ///  获取试卷和评测的条件信息
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-paper-exam-condition")]
+        [ApiToken(Auth = "1101", Name = "试卷和评测的条件信息", RW = "R", Limit = false)]
+        public async Task<IActionResult> GetPaperExamCondition(JsonElement json)
+        {
+            json.TryGetProperty("periodId", out JsonElement _periodId);
+            var (id, school) = HttpContext.GetApiTokenInfo();
+            School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+            var exmaType = new { type = new List<string> { "regular", "simulation", "normal" } };//regula ,正规考,  simulation 模拟靠考,normal 普通考
+            var exmaMode = new { type = new List<string> { "0", "1", "2" } };//0 线上评测,  1 课中评测 ,2 阅卷评测
+            var period = data.period.Find(x => x.id.Equals($"{_periodId}"));
+            if (period != null)
+            {
+                return Ok(new { period.subjects, period.analysis, period.grades, exmaType, exmaMode });
+            }
+            else
+            {
+                return Ok(new { error = 1, msg = "学段不存在!" });
+            }
+        }
         [ProducesDefaultResponseType]
         [HttpGet("import-exam")]
-        [ApiToken(Auth = "201", Name = "汇入评测基础数据", Limit = false)]
+        [ApiToken(Auth = "1102", Name = "汇入评测基础数据", Limit = false)]
         public async Task<IActionResult> importExam(JsonElement request)
         {
             //获取评测的ID
@@ -78,7 +102,7 @@ namespace TEAMModelAPI.Controllers
         }
         [ProducesDefaultResponseType]
         [HttpGet("upsert-record")]
-        [ApiToken(Auth = "202", Name = "批量汇入作答数据", Limit = false)]
+        [ApiToken(Auth = "1103", Name = "批量汇入作答数据", Limit = false)]
         public async Task<IActionResult> upsertRecord(JsonElement request)
         {
 
@@ -341,7 +365,7 @@ namespace TEAMModelAPI.Controllers
         }
         [ProducesDefaultResponseType]
         [HttpGet("parse-word")]
-        [ApiToken(Auth = "203", Name = "录入试卷数据", Limit = false)]
+        [ApiToken(Auth = "1104", Name = "录入试卷数据", Limit = false)]
         public async Task<IActionResult> ParseWord([FromForm] FileDto fileDto)
         {
             if (!FileType.GetExtention(fileDto.file.FileName).ToLower().Equals("docx"))

+ 57 - 43
TEAMModelAPI/Controllers/School/GroupListController.cs

@@ -63,7 +63,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-group-list")]
-        [ApiToken(Auth = "109", Name = "学校名单列表", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1201", Name = "学校名单列表", RW = "R", Limit = false)]
         public async Task<IActionResult> GetGroupList(JsonElement json)
         {
             var client = _azureCosmos.GetCosmosClient();
@@ -157,10 +157,9 @@ namespace TEAMModelAPI.Controllers
                 groupLists = groupLists.Select(x => new { x.id, x.type, x.name, x.periodId, x.school, x.scope, x.year })
             });
         }
-
         [ProducesDefaultResponseType]
         [HttpPost("get-group-members")]
-        [ApiToken(Auth = "110", Name = "获取名单详细信息和成员信息", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1202", Name = "获取名单详细信息和成员信息", RW = "R", Limit = false)]
         public async Task<IActionResult> GetGroupMembers(JsonElement json)
         {
             var client = _azureCosmos.GetCosmosClient();
@@ -170,8 +169,6 @@ namespace TEAMModelAPI.Controllers
             (List<RMember> members, List<RGroupList> groups) = await GroupListService.GetStutmdidListids(_coreAPIHttpService, client, _dingDing, listids, $"{school}");
             return Ok(new { groups = groups.Select(x => new { x.name, x.no, x.periodId, x.school, x.type, x.year, x.tcount, x.scount, x.leader, x.members, x.id }), members });
         }
-
-
         /// <summary>
         /// 导入行政班学生
         /// </summary>
@@ -179,7 +176,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("import-class-members")]
-        [ApiToken(Auth = "111", Name = "导入行政班学生", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1203", Name = "导入行政班学生", RW = "W", Limit = false)]
         public async Task<IActionResult> ImportClassMembers(JsonElement json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -213,7 +210,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("update-class-members")]
-        [ApiToken(Auth = "112", Name = "更新行政班学生", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1204", Name = "更新行政班学生", RW = "W", Limit = false)]
         public async Task<IActionResult> UpdateClassMembers(JsonElement json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -249,7 +246,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("remove-class-members")]
-        [ApiToken(Auth = "113", Name = "移除行政班学生", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1205", Name = "移除行政班学生", RW = "W", Limit = false)]
         public async Task<IActionResult> RemoveClassMembers(JsonElement json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -291,46 +288,24 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("upsert-teach-group")]
-        [ApiToken(Auth = "114", Name = "创建或更新教学班", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1206", Name = "创建或更新教学班", RW = "W", Limit = false)]
         public async Task<IActionResult> UpsertTeachGroup(JsonElement json) {
             var (id, school) = HttpContext.GetApiTokenInfo();
             if (!json.TryGetProperty("groupList", out JsonElement _groupList)) { return Ok(new { error=1,msg="名单对象不存在"}); }
             var list= _groupList.ToObject<GroupListDto>();
             GroupList groupList = null;
-            if (list != null  && list.Valid().isVaild) {
-                if (string.IsNullOrWhiteSpace(list.id))
+          
+            if (list != null && list.Valid().isVaild)
+            {
+                School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+                Period period = data.period.Find(x => x.id.Equals($"{list.periodId}"));
+                if (period != null)
                 {
-                      groupList = new GroupList()
+                    if (string.IsNullOrWhiteSpace(list.id))
                     {
-                        id=Guid.NewGuid ().ToString(),
-                        code=$"GroupList-{school}",
-                        name=list.name,
-                        periodId=list.periodId,
-                        scope="school",
-                        school=school,
-                        type="teach",
-                        year=list.year,
-                        froms=3
-                    };
-                    groupList = await GroupListService.CheckListNo(groupList, _azureCosmos, _dingDing, _option);
-                    await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(groupList,new PartitionKey(groupList.code));
-                }
-                else {
-                    Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync($"{list.id}", new PartitionKey($"GroupList-{school}"));
-                    if (response.Status==200)
-                    {
-                        JsonDocument jsonDocument = JsonDocument.Parse(response.Content);
-                        groupList = jsonDocument.RootElement.ToObject<GroupList>();
-                        groupList.name=string.IsNullOrWhiteSpace(list.name)?groupList.name: list.name;
-                        groupList.periodId = string.IsNullOrWhiteSpace(list.periodId) ? groupList.periodId : list.periodId;
-                        groupList.school=school;
-                        groupList.scope = "school";
-                        groupList.froms=3;
-                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(groupList, groupList.id, new PartitionKey(groupList.code));
-                    }
-                    else {
-                          groupList = new GroupList()
+                        groupList = new GroupList()
                         {
+                            pk = "GroupList",
                             id = Guid.NewGuid().ToString(),
                             code = $"GroupList-{school}",
                             name = list.name,
@@ -344,8 +319,47 @@ namespace TEAMModelAPI.Controllers
                         groupList = await GroupListService.CheckListNo(groupList, _azureCosmos, _dingDing, _option);
                         await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(groupList, new PartitionKey(groupList.code));
                     }
+                    else
+                    {
+                        Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync($"{list.id}", new PartitionKey($"GroupList-{school}"));
+                        if (response.Status == 200)
+                        {
+                            JsonDocument jsonDocument = JsonDocument.Parse(response.Content);
+                            groupList = jsonDocument.RootElement.ToObject<GroupList>();
+                            groupList.name = string.IsNullOrWhiteSpace(list.name) ? groupList.name : list.name;
+                            groupList.periodId = string.IsNullOrWhiteSpace(list.periodId) ? groupList.periodId : list.periodId;
+                            groupList.school = school;
+                            groupList.scope = "school";
+                            groupList.froms = 3;
+                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(groupList, groupList.id, new PartitionKey(groupList.code));
+                        }
+                        else
+                        {
+                            groupList = new GroupList()
+                            {
+                                id = Guid.NewGuid().ToString(),
+                                code = $"GroupList-{school}",
+                                name = list.name,
+                                periodId = list.periodId,
+                                scope = "school",
+                                school = school,
+                                type = "teach",
+                                year = list.year,
+                                froms = 3
+                            };
+                            groupList = await GroupListService.CheckListNo(groupList, _azureCosmos, _dingDing, _option);
+                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(groupList, new PartitionKey(groupList.code));
+                        }
+                    }
+                }
+                else {
+                    return Ok(new { error = 2, msg ="学段不存在!" });
                 }
             }
+            else
+            {
+                return Ok(new { error = 3, msg = list.Valid() });
+            }
             return Ok(new { groupList });
         }
 
@@ -356,7 +370,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("import-teach-members")]
-        [ApiToken(Auth = "115", Name = "导入教学班学生", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1207", Name = "导入教学班学生", RW = "W", Limit = false)]
         public async Task<IActionResult> ImportTeachMembers(JsonElement json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -426,7 +440,7 @@ namespace TEAMModelAPI.Controllers
                 }
                 else
                 {
-                    return Ok(new { error = valid, msg = "名单列表格式错误!" });
+                    return Ok(new { error = 3, msg = valid });
                 }
             }
             else
@@ -442,7 +456,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("remove-teach-members")]
-        [ApiToken(Auth = "116", Name = "移除教学班学生", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1208", Name = "移除教学班学生", RW = "W", Limit = false)]
         public async Task<IActionResult> RemoveTeachMembers(JsonElement json) {
             var (id, school) = HttpContext.GetApiTokenInfo();
             json.TryGetProperty("stuids", out JsonElement _stuids);

+ 7 - 74
TEAMModelAPI/Controllers/School/SchoolController.cs

@@ -59,7 +59,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpGet("get-school-info")]
-        [ApiToken(Auth = "101",Name = "学校基础信息", RW = "R", Limit =false)]
+        [ApiToken(Auth = "1001",Name = "学校基础信息", RW = "R", Limit =false)]
         public async Task<IActionResult> GetSchoolInfo()
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -81,7 +81,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpGet("get-teacher-list")]
-        [ApiToken(Auth = "102", Name = "学校教师列表", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1002", Name = "学校教师列表", RW = "R", Limit = false)]
         public async Task<IActionResult> GetTeacherList()
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -102,7 +102,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-teacher-info")]
-        [ApiToken(Auth = "103", Name = "学校教师信息", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1003", Name = "学校教师信息", RW = "R", Limit = false)]
         public async Task<IActionResult> GetTeacherInfo(JsonElement json )
         {
             json.TryGetProperty("tmdid", out JsonElement _tmdid);
@@ -138,50 +138,7 @@ namespace TEAMModelAPI.Controllers
             }
         }
        
-        [ProducesDefaultResponseType]
-        [HttpPost("get-course-list")]
-        [ApiToken(Auth = "104", Name = "获取课程列表信息",RW ="R", Limit = false)]
-        public async Task<IActionResult> GetCourseList(JsonElement json) {
-            var client = _azureCosmos.GetCosmosClient();
-            var (id, school) = HttpContext.GetApiTokenInfo();
-            json.TryGetProperty("periodId", out JsonElement periodId);
-            json.TryGetProperty("subjectId", out JsonElement subjectId);
-            StringBuilder sql = new StringBuilder($"SELECT c.id,c.name,c.subject,c.period,c.scope,c.no,c.school FROM c where 1=1 ");
-            if (!string.IsNullOrWhiteSpace($"{periodId}")) {
-                sql.Append($" and c.period.id='{periodId}'");
-            }
-            if (!string.IsNullOrWhiteSpace($"{subjectId}"))
-            {
-                sql.Append($" and c.subject.id='{subjectId}'");
-            }
-            List<dynamic> courses = new List<dynamic>();
-            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").
-                    GetItemQueryIterator<dynamic>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{school}") }))
-            {
-                courses.Add(item);
-            }
-            return Ok(new { courses });
-        }
-       
-        [ProducesDefaultResponseType]
-        [HttpPost("get-course-info")]
-        [ApiToken(Auth = "105", Name = "课程详细信息", RW = "R", Limit = false)]
-        public async Task<IActionResult> GetCourseInfo(JsonElement json)
-        {
-            var (id, school) = HttpContext.GetApiTokenInfo();
-            json.TryGetProperty("courseId", out JsonElement courseId);
-            Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School")
-               .ReadItemStreamAsync($"{courseId}", new PartitionKey($"Course-{school}"));
-            if (response.Status == 200)
-            {
-                JsonDocument document= JsonDocument.Parse(response.Content);
-                Course course= document.RootElement.Deserialize<Course>();
-                return Ok(new { course.name,course.id, course.subject, course .period, course .scope, course.school, course .no, course .desc, course.schedule});
-            }
-            else {
-                return Ok(new { error=1,msg="课程不存在!"});
-            }
-        }
+      
         /// <summary>
         /// 获取物理教室列表
         /// </summary>
@@ -189,7 +146,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-room-list")]
-        [ApiToken(Auth = "106", Name = "获取物理教室列表", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1004", Name = "获取物理教室列表", RW = "R", Limit = false)]
         public async Task<IActionResult> GetRoomList(JsonElement json)
         {
             var client = _azureCosmos.GetCosmosClient();
@@ -216,7 +173,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-room-info")]
-        [ApiToken(Auth = "107", Name = "获取物理教室详细信息", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1005", Name = "获取物理教室详细信息", RW = "R", Limit = false)]
         public async Task<IActionResult> GetRoomInfo(JsonElement json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -235,30 +192,6 @@ namespace TEAMModelAPI.Controllers
             }
         }
 
-        /// <summary>
-        ///  获取试卷和评测的条件信息
-        /// </summary>
-        /// <param name="request"></param>
-        /// <returns></returns>
-        [ProducesDefaultResponseType]
-        [HttpPost("get-paper-exam-condition")]
-        [ApiToken(Auth = "108", Name = "试卷和评测的条件信息", RW = "R", Limit = false)]
-        public async Task<IActionResult> GetPaperExamCondition(JsonElement json)
-        {
-            json.TryGetProperty("periodId", out JsonElement _periodId);
-            var (id, school) = HttpContext.GetApiTokenInfo();
-            School data = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
-            var exmaType = new { type = new List<string> { "regular", "simulation", "normal" } };//regula ,正规考,  simulation 模拟靠考,normal 普通考
-            var exmaMode = new { type = new List<string> { "0", "1", "2" } };//0 线上评测,  1 课中评测 ,2 阅卷评测
-            var period = data.period.Find(x => x.id.Equals($"{_periodId}"));
-            if (period != null)
-            {
-                return Ok(new { period.subjects, period.analysis, period.grades, exmaType, exmaMode });
-            }
-            else
-            {
-                return Ok(new { error = 1, msg = "学段不存在!" });
-            }
-        }
+        
     }
 }

+ 14 - 9
TEAMModelOS.SDK/Models/Cosmos/School/Course.cs

@@ -83,15 +83,7 @@ namespace TEAMModelOS.SDK.Models
 
     }
 
-    public class Customize
-    {
-        public string id { get; set; }
-        public string name { get; set; }
-        public Teachers teacher { get; set; } = new Teachers();
-        public string scope { get; set; }
-        public string code { get; set; }
-
-    }
+    
     public class TimeInfo
     {
         public string id { get; set; }
@@ -122,4 +114,17 @@ namespace TEAMModelOS.SDK.Models
         public string id { get; set; }
         public string name { get; set; }
     }
+
+    public class CourseDto
+    {
+        public string id { get; set; }
+        [Required(ErrorMessage = "{0} 课程的名称必须填写")]
+        public string name { get; set; }
+        public string desc { get; set; }
+        public string no { get; set; }
+        [Required(ErrorMessage = "{0} 课程的科目id必须填写")]
+        public string subjectId { get; set; }
+        [Required(ErrorMessage = "{0} 课程的学段id必须填写")]
+        public string periodId { get; set; }
+    }
 }

BIN
TEAMModelOS/ClientApp/src/assets/image/none.png


+ 6 - 5
TEAMModelOS/ClientApp/src/common/BaseLayout.vue

@@ -167,12 +167,13 @@ export default {
                     icon: 'iconfont icon-data-count',
                     name: this.$t('system.menu.researchBoard'),
                     router: '/home/Dashboard',
-                    tag: this.$t('system.preview'),
+                    tag: '',
                     role: 'teacher|admin',
                     permission: '',
                     menuName: 'Dashboard',
                     child: [],
-                    isShow: this.$store.state.config.srvAdrType != 'product' && this.checkHost()
+                    // isShow: this.$store.state.config.srvAdrType != 'product' && this.checkHost()
+                    isShow: true
                 },
                 // 学校管理
                 {
@@ -371,7 +372,7 @@ export default {
                     tag: this.$t('system.preview'),
                     permission: '',
                     subName: 'research',
-                    isShow: this.$store.state.config.srvAdrType != 'product' && this.checkHost(),
+                    isShow: this.checkHost(),
                     child: [
                         {
                             icon: 'iconfont icon-course-videos',
@@ -381,13 +382,13 @@ export default {
                             role: 'teacher|admin',
                             permission: '',
                             menuName: 'courseCenter',
-                            isShow: true
+                            isShow: this.$store.state.config.srvAdrType != 'product'
                         },
                         {
                             icon: 'iconfont icon-data-count',
                             name: this.$t('system.menu.cusVideoMgt'),
                             router: '/home/ResearchMgt',
-                            tag: this.$t('system.preview'),
+                            tag: '',
                             role: 'teacher|admin',
                             permission: '',
                             menuName: 'ResearchMgt',

+ 5 - 1
TEAMModelOS/ClientApp/src/components/research-dashboard/RightBotR.vue

@@ -6,7 +6,11 @@
 			<dv-decoration-3 class="dv-dec-3" />
 		</p>
 		<div class="bg-color-black">
-			<TechBar></TechBar>
+			<!-- <TechBar></TechBar> -->
+			<div style="width: 100%;display: flex;flex-direction: column;justify-content: center;align-items: center;margin-top: 50px;">
+				<img src="../../assets/image/none.png" width="200px">
+				<span>暂无数据</span>
+			</div>
 		</div>
 	</div>
 </template>

+ 4 - 1
TEAMModelOS/ClientApp/src/locale/lang/en-US/cusMgt.js

@@ -363,7 +363,10 @@ export default {
         rcdLabel: 'Interaction Records',
         enote: 'E-Note',
         sokrateRpt: 'Sokrates Report',
-        dataCount: 'Data Statistics',
+        dataCount:'统计数据',
+        videoData:'視頻數據',
+        exportData:'導出數據',
+        noVideo:'當前課堂記錄沒有視頻數據',
         allRcd: 'All Records',
         qustion: 'Pop Quiz',
         message: 'HiMessage',

+ 4 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/cusMgt.js

@@ -363,7 +363,10 @@ export default {
         rcdLabel:'互动记录',
         enote:'电子笔记',
         sokrateRpt:'苏格拉底报告',
-        dataCount:'数据统计',
+        dataCount:'统计数据',
+        videoData:'视频数据',
+        exportData:'导出数据',
+        noVideo:'当前课堂记录没有视频数据',
         allRcd:'所有记录',
         qustion:'即问即答',
         message:'飞讯',

+ 4 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/cusMgt.js

@@ -363,7 +363,10 @@ export default {
         rcdLabel: '互動記錄',
         enote: '電子筆記',
         sokrateRpt: '蘇格拉底報告',
-        dataCount: '數據統計',
+        dataCount: '統計數據',
+        videoData:'視頻數據',
+        exportData:'導出數據',
+        noVideo:'當前課堂記錄沒有視頻數據',
         allRcd: '所有記錄',
         qustion: '即問即答',
         message: '飛訊',

+ 8 - 0
TEAMModelOS/ClientApp/src/view/classrecord/ClassRecord.less

@@ -67,6 +67,7 @@
     box-shadow: 0px 0px 10px 2px #d8d8d8;
     height: 450px;
     display: flex;
+    position: relative;
     background: #fff;
 }
 .courseware-wrap {
@@ -398,4 +399,11 @@
     right: 5px;
     bottom: 5px;
     z-index: 9999;
+}
+.no-video-tips{
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    color: #ff9900;
+    width: 100%;
 }

+ 47 - 26
TEAMModelOS/ClientApp/src/view/classrecord/ClassRecord.vue

@@ -29,10 +29,15 @@
                         <!-- <span class="e-note-tag" @click="viewReport">
                             {{$t('cusMgt.rcd.sokrateRpt')}}
                         </span> -->
+                        <!-- 表格下载 -->
+                        <span class="e-note-tag" @click="downloadData">
+                            <Icon type="md-download" />
+                            {{$t('cusMgt.rcd.exportData')}}
+                        </span>
                         <!-- 数据统计 -->
-                        <span class="e-note-tag" @click="viewData">
-                            <Icon type="md-podium" />
-                            {{$t('cusMgt.rcd.dataCount')}}
+                        <span class="e-note-tag" v-show="hasVideo" @click="isShowVd = !isShowVd">
+                            <Icon :type="isShowVd ? 'md-podium' : 'logo-youtube'" />
+                            {{isShowVd ? $t('cusMgt.rcd.dataCount') : $t('cusMgt.rcd.videoData')}}
                         </span>
                     </div>
                 </div>
@@ -48,15 +53,18 @@
                             <Page :total="pageList.length" :current="curPage" :page-size="1" size="small" @on-change="getCurHTEX" />
                         </div>
                     </div>
-                    <video-player2 v-if="hasVideo || isShowVd" @on-vd-error="videoError" class="video-player-box" :markers="markers" ref="videoPlayer" :options="playerOptions" :playsinline="true" @getCurPage="getCurPage">
+                    <video-player2 v-if="hasVideo" v-show="isShowVd" @on-vd-error="videoError" class="video-player-box" :markers="markers" ref="videoPlayer" :options="playerOptions" :playsinline="true" @getCurPage="getCurPage">
                     </video-player2>
-                    <div v-else class="video-player-box" style="padding:25px 0px">
-                        <DataCount></DataCount>
+                    <div v-show="!isShowVd" class="video-player-box" style="padding:25px 0px">
+                        <Alert v-show="!hasVideo" class="no-video-tips" type="warning" show-icon>
+                            {{$t('cusMgt.rcd.noVideo')}}
+                        </Alert>
+                        <DataCount :rcdInfo="recordInfo"></DataCount>
                     </div>
-                    <i-switch v-show="hasVideo" v-model="isShowVd" class="toggle-view" true-color="#19be6b" false-color="#2b85e4">
+                    <!-- <i-switch v-show="hasVideo" v-model="isShowVd" class="toggle-view" true-color="#19be6b" false-color="#2b85e4">
                         <Icon type="logo-youtube" slot="open"></Icon>
                         <Icon type="md-podium" slot="close"></Icon>
-                    </i-switch>
+                    </i-switch> -->
                 </div>
 
                 <div class="cus-data-wrap">
@@ -118,9 +126,6 @@
         </div>
         <!--返回顶部-->
         <BackToTop @on-to-top="handleToTop"></BackToTop>
-        <Modal v-model="dataStatus" :title="$t('cusMgt.rcd.dataCount')" :width="800" footer-hide>
-            <DataCount></DataCount>
-        </Modal>
     </div>
 </template>
 <script>
@@ -136,9 +141,8 @@ export default {
     },
     data() {
         return {
-            isShowVd:false,
-            hasVideo:true,
-            dataStatus: false,
+            isShowVd: true,
+            hasVideo: true,
             eventClick: false,
             sokratesRecords: [],
             pageList: [],
@@ -183,8 +187,26 @@ export default {
         }
     },
     methods: {
-        videoError(){
-            this.hasVideo = false 
+        //下载统计表格
+        downloadData() {
+            let blobInfo = this.recordInfo.scope === 'school' ? this.$store.state.user.schoolProfile : this.$store.state.user.userProfile
+            let url = `${blobInfo.blob_uri}/records/${this.recordInfo.id}/IES/summary.xlsx?${blobInfo.blob_sas}`
+
+            const downloadRes = async () => {
+                let response = await fetch(url); // 内容转变成blob地址
+                let blob = await response.blob(); // 创建隐藏的可下载链接
+                let objectUrl = window.URL.createObjectURL(blob);
+                let a = document.createElement('a');
+                a.href = objectUrl;
+                a.download = this.recordInfo.name + '.xlsx';
+                a.click()
+                a.remove();
+            }
+            downloadRes();
+        },
+        videoError() {
+            this.hasVideo = false
+            this.isShowVd = false
         },
         //返回顶部
         handleToTop() {
@@ -212,8 +234,8 @@ export default {
         getPageList() {
             this.pageList = []
             this.markers = []
-            let userProfile = this.$store.state.user.userProfile
-            let url = `${userProfile.blob_uri}/records/${this.recordInfo.id}/Sokrates/SokratesRecords.json?${userProfile.blob_sas}`
+            let blobInfo = this.recordInfo.scope == 'school' ? this.$store.state.user.schoolProfile : this.$store.state.user.userProfile
+            let url = `${blobInfo.blob_uri}/records/${this.recordInfo.id}/Sokrates/SokratesRecords.json?${blobInfo.blob_sas}`
             this.$tools.getFile(url).then(
                 res => {
                     this.sokratesRecords = JSON.parse(res)
@@ -222,7 +244,7 @@ export default {
                     pgids.forEach((item, index) => {
                         let page = {}
                         page.id = item
-                        page.img = `${userProfile.blob_uri}/records/${this.recordInfo.id}/Memo/${item}.jpg?${userProfile.blob_sas}`
+                        page.img = `${blobInfo.blob_uri}/records/${this.recordInfo.id}/Memo/${item}.jpg?${blobInfo.blob_sas}`
                         page.page = index + 1
                         //当前页面对应的sokrates
                         page.pageData = this.sokratesRecords.filter(record => record.Pgid === item && record.Event != 'PgJump' && record.Event != 'PgAdd' && record.Event != 'DiscussStart')
@@ -253,10 +275,6 @@ export default {
                 query: { id: this.recordInfo.id, name: this.recordInfo.name }
             })
         },
-        //查看数据统计
-        viewData() {
-            this.dataStatus = true
-        },
         //查看电子笔记
         viewENote() {
             if (this.recordInfo.eNote) {
@@ -349,9 +367,9 @@ export default {
         } else {
             sessionStorage.setItem('record', JSON.stringify(this.recordInfo))
             //对接Blob数据
-            let userProfile = this.$store.state.user.userProfile
-            this.videoUrl = `${userProfile.blob_uri}/records/${this.recordInfo.id}/Record/CourseRecord.mp4?${userProfile.blob_sas}`
-            this.videoPoster = `${userProfile.blob_uri}/records/${this.recordInfo.id}/Record/CoverImage.jpg?${userProfile.blob_sas}`
+            let blobInfo = this.recordInfo.scope == 'school' ? this.$store.state.user.schoolProfile : this.$store.state.user.userProfile
+            this.videoUrl = `${blobInfo.blob_uri}/records/${this.recordInfo.id}/Record/CourseRecord.mp4?${blobInfo.blob_sas}`
+            this.videoPoster = `${blobInfo.blob_uri}/records/${this.recordInfo.id}/Record/CoverImage.jpg?${blobInfo.blob_sas}`
             this.playerOptions.poster = this.videoPoster
             this.playerOptions.sources.push({
                 src: this.videoUrl
@@ -393,4 +411,7 @@ export default {
 .video-player-box .vjs-volume-panel {
     display: none;
 }
+.video-player-box .ivu-alert {
+    border-radius: 0px;
+}
 </style>

+ 10 - 6
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/DataCount.vue

@@ -10,12 +10,19 @@
 <script>
 import CountTo from 'vue-count-to'
 export default {
+    props: {
+        rcdInfo: {
+            type: Object,
+            default: () => {
+                return undefined
+            }
+        }
+    },
     components: {
         CountTo
     },
     data() {
         return {
-            baseData: {},
             colorList: ['#2d8cf0', '#2d8cf0', '#2db7f5', '#2db7f5', '#2db7f5', '#19be6b', '#2db7f5', '#2db7f5', '#2db7f5', '#ed4014'],
             dataList: [
                 {
@@ -73,11 +80,8 @@ export default {
         }
     },
     created() {
-        //Base.json Blob尚未上传,暂时从本地读取
-        this.baseData = require("../data/Base.json")
-        console.log(this.baseData)
-        if (this.baseData.summary) {
-            const summary = this.baseData.summary
+        if (this.rcdInfo) {
+            const summary = this.rcdInfo
             // 出席人数
             this.dataList[0].value = summary.attendCount
             this.dataList[0].info = `(${summary.attendCount}/${summary.clientCount} ${summary.attendRate}%)`

+ 1 - 1
TEAMModelOS/ClientApp/src/view/newcourse/EvDetail.vue

@@ -88,7 +88,7 @@ export default {
         findExamInfo(examId, code) {
             let requestData = {
                 id: examId,
-                code: code
+                code: code.includes('Exam-') ? code : 'Exam-' + code
             }
             this.isLoading = true
             this.pageLoading = true

+ 1 - 0
TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.less

@@ -249,6 +249,7 @@
     // color:white;
     font-size:14px;
     padding-right:30px;
+    margin-top: -30px;
 }
 .action-icon {
     margin-right: 10px;

+ 26 - 22
TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue

@@ -156,6 +156,7 @@
                                             <p slot="title" class="record-name" style="padding-left:10px">
                                                 {{item.name}}
                                                 <Icon type="md-create" class="edit-ev-name" @click.stop="editRecordName(index)" :title="$t('cusMgt.edRdName')" />
+                                                <Icon type="md-trash" class="edit-ev-name" @click.stop="delRecord(item.id)" :title="$t('cusMgt.delRcd')" />
                                             </p>
                                             <div slot="description" style="padding-left:10px;margin-top:10px">
                                                 <!-- 出席人数 -->
@@ -197,12 +198,21 @@
                                                     <span class="record-info-value">{{handleDuration(item.duration)}}</span>
                                                 </span>
                                                 <!-- 时间 -->
-                                                <span>{{$jsFn.timeFormat(item.startTime)}}</span>
+                                                <span class="record-info" style="float:right">
+                                                    <span>
+                                                        <Icon type="md-time" color="#70B1E7" />
+                                                    </span>
+                                                    <span class="record-info-value">
+                                                        {{$jsFn.timeFormat(item.startTime)}}
+                                                    </span>
+                                                </span>
                                                 <div class="record-action-wrap">
                                                     <!-- <Icon class="action-icon" custom="iconfont icon-video" :title="$t('cusMgt.socrateMv')" @click.stop="viewVideo(item)" />
                                                     <Icon class="action-icon" type="md-share" :title="$t('cusMgt.share')" v-show="$store.state.config.srvAdrType != 'product'" @click.stop="shareRecord" /> -->
                                                     <!-- <Icon class="action-icon" type="md-trash" :size="15" :title="$t('cusMgt.delRcd')" @click.stop="delRecord(item.id)" /> -->
-                                                    <span class="action-text" @click.stop="delRecord(item.id)">删除</span>
+                                                    <!-- <span class="action-text" @click.stop="delRecord(item.id)">
+                                                        <Icon type="md-trash" :size="15" :title="$t('cusMgt.delRcd')"/>
+                                                    </span> -->
                                                 </div>
                                             </div>
                                         </ListItemMeta>
@@ -255,12 +265,12 @@
                                                     <span class="ev-attr-wrap">
                                                         <span class="attr-label">
                                                             <Icon type="md-time" size="16" />
-                                                            {{$t('cusMgt.acTime')}}:
+                                                            <!-- {{$t('cusMgt.acTime')}}: -->
                                                         </span>
                                                         <span class="attr-value">
-                                                            {{dateFormat(item.startTime)}}
-                                                            -
-                                                            {{dateFormat(item.endTime)}}
+                                                            {{$jsFn.timeFormat(item.startTime)}}
+                                                            <!-- -
+                                                            {{dateFormat(item.endTime)}} -->
                                                         </span>
                                                     </span>
                                                 </p>
@@ -1613,12 +1623,7 @@ export default {
             this.$router.push({
                 name: 'classRecord',
                 params: {
-                    record: {
-                        id: this.recordList[index].id,
-                        name: this.recordList[index].name,
-                        startTime: this.recordList[index].startTime,
-                        eNote: this.recordList[index].eNote
-                    }
+                    record: this.recordList[index]
                 }
             })
         },
@@ -1962,18 +1967,17 @@ export default {
                 this.$api.lessonRecord.getLessonList(params).then(
                     res => {
                         this.recordList = res.lessonRecords
-                        let privateSas = {}
-                        let blobInfo = this.$store.state.user.userProfile
-                        privateSas.sas = '?' + blobInfo.blob_sas
-                        privateSas.url = blobInfo.blob_uri.slice(0, blobInfo.blob_uri.lastIndexOf(this.$store.state.userInfo.TEAMModelId) - 1)
-                        privateSas.name = this.$store.state.userInfo.TEAMModelId
+                        let sasInfo = {}
+                        let blobInfo = this.listType === 'school' ? this.$store.state.user.schoolProfile : this.$store.state.user.userProfile
+                        sasInfo.sas = '?' + blobInfo.blob_sas
+                        sasInfo.name = this.listType === 'school' ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId
+                        sasInfo.url = blobInfo.blob_uri.slice(0, blobInfo.blob_uri.lastIndexOf(sasInfo.name) - 1)
                         this.recordList.forEach(item => {
-                            item.sokrateImg = `${privateSas.url}/${privateSas.name}/records/${item.id}/Sokrates/SokratesResults/event.png${privateSas.sas}`
-                            item.eNote = `${privateSas.url}/${privateSas.name}/records/${item.id}/Note.pdf${privateSas.sas}`
-                            item.video = `${privateSas.url}/${privateSas.name}/records/${item.id}/Record/CourseRecord.mp4${privateSas.sas}`
-                            item.poster = `${privateSas.url}/${privateSas.name}/records/${item.id}/Record/CoverImage.jpg${privateSas.sas}`
+                            item.sokrateImg = `${sasInfo.url}/${sasInfo.name}/records/${item.id}/Sokrates/SokratesResults/event.png${sasInfo.sas}`
+                            item.eNote = `${sasInfo.url}/${sasInfo.name}/records/${item.id}/Note.pdf${sasInfo.sas}`
+                            item.video = `${sasInfo.url}/${sasInfo.name}/records/${item.id}/Record/CourseRecord.mp4${sasInfo.sas}`
+                            item.poster = `${sasInfo.url}/${sasInfo.name}/records/${item.id}/Record/CoverImage.jpg${sasInfo.sas}`
                         })
-                        // this.filterRecordList(this.curClassIndex)
                     },
                     err => {
                         this.$Message.error(this.$t('cusMgt.rcdErr'))

+ 6 - 2
TEAMModelOS/ClientApp/src/view/research-center/ResearchCenter.vue

@@ -201,6 +201,7 @@
 				introVideos: [],
 				doubleGreenVideos:[],
 				todayVideos:[],
+				schoolSas:null
 			}
 		},
 		created() {
@@ -211,8 +212,9 @@
 		},
 		methods: {
 			/* 获取最新课例统计数据 */
-			getDashboardData(){
+			async getDashboardData(){
 				let semesterRange = this.$tools.getSemesterTimeRange()
+				this.schoolSas = await this.$tools.getSchoolSas()
 				this.$api.lessonRecord.getDashboardData({
 					"stime": semesterRange.st,
 					"etime": semesterRange.et,
@@ -332,7 +334,8 @@
 				list.forEach(item => {
 					let container = item.scope === 'school' ? item.school : item.tmdid
 					let blobHost = this.$evTools.getBlobHost()
-					item.poster = blobHost + '/' + container + '/records/' + item.id + '/Record/CoverImage.jpg'
+					item.videoPath = blobHost + '/' + container + '/records/' + item.id + '/Record/CourseRecord.mp4'  + this.schoolSas.sas
+					item.poster = blobHost + '/' + container + '/records/' + item.id + '/Record/CoverImage.jpg' + this.schoolSas.sas
 					item.subject = this.curPeriod.subjects.find(i => i.id === item.subjectId).name
 					item.grade = item.grade.map(i => this.curPeriod.grades[+i]).join(',')
 				})
@@ -380,6 +383,7 @@
 						}else{
 							this.isReachBottom = true
 						}
+						console.log(this.listVideos);
 						this.listVideos = this.listVideos.concat(this.getFullInfo(res.lessonRecords))
 						this.continuationToken = res.continuationToken
 					}

+ 32 - 9
TEAMModelOS/ClientApp/src/view/research-center/ResearchMgt.less

@@ -1,20 +1,37 @@
 .research-mgmt-container{
 	padding: 5px 25px;
 	
+	.analysis-box{
+		padding: 10px 0;
+		font-size: 14px;
+		.analysis-item{
+			margin-right: 40px;
+			&-title{
+				&::before{
+					content: "";
+					width: 3px;
+					height: 10px;
+					border-radius: 4px;
+					background-color: #736d6d;
+					display: inline-block;
+					margin-right: 5px;
+				}
+			}
+			
+			&-value{
+				font-size: 24px;
+				font-weight: bold;
+				color: red;
+				margin-left: 10px;
+			}
+		}
+	}
+	
 	.title{
 		font-size: 24px;
 		font-weight: bold;
 		margin-left: -5px;
 		margin-bottom: 10px;
-		// &::before{
-		// 	content: "";
-		// 	width: 5px;
-		// 	height: 15px;
-		// 	border-radius: 4px;
-		// 	background-color: #38b894;
-		// 	display: inline-block;
-		// 	margin-right: 5px;
-		// }
 	}
 	
 	.filter-box{
@@ -41,6 +58,11 @@
 				margin-right: 10px;
 			}
 		}
+		
+		.export-btn{
+			margin-left: 20px;
+			text-decoration: underline;
+		}
 	}
 	
 	.tools-bar{
@@ -59,6 +81,7 @@
 	
 	.table-box{
 		overflow: auto;
+		margin-top: 20px;
 		.action-icon{
 			margin-right: 10px;
 			font-size: 18px;

+ 122 - 24
TEAMModelOS/ClientApp/src/view/research-center/ResearchMgt.vue

@@ -1,6 +1,13 @@
 <template>
 	<div class="research-mgmt-container">
 		<!-- <p class="title">课例管理</p> -->
+		<div class="analysis-box">
+			<span class="analysis-item" v-for="(item,index) in analysisArr" :key="index">
+				<span class="analysis-item-title">{{ item }}</span>
+				<span class="analysis-item-value">0</span>
+			</span>
+			
+		</div>
 		<div class="filter-box">
 			<div style="display: flex;">
 				<div class="filter-item">
@@ -32,26 +39,24 @@
 				</div>
 				<div style="margin-right: 10px;">
 					<span>共查询到 <span style="font-size: 18px;font-weight: bold;color: #28b989;">{{ totalNum.count }}
-						</span>条课例数据</span>
+						</span>条课堂记录</span>
+					<span class="tool-item" style="margin-left: 20px;cursor: pointer;" @click="downloadTable()">
+						<Icon type="md-download" />
+						<span>导出数据</span>
+					</span>	
 				</div>
 			</div>
 
 		</div>
-		<div class="tools-bar">
+		<!-- <div class="tools-bar">
 			<div class="tool-item" @click="onAddVideo">
-				<!-- <Button type="success" icon="md-add">添加课例</Button> -->
 				<Icon type="md-add" />
 				<span>添加课例</span>
 			</div>
 			<div class="tool-item">
-				<!-- <Button type="info" icon="md-download">导出数据</Button> -->
 				<Icon type="md-download" />
 				<span>导出数据</span>
 			</div>
-			<!-- 			<div class="tool-item">
-				<Icon type="ios-trash" />
-				<span>批量删除</span>
-			</div> -->
 			<div class="tool-item" @click="onTagMgClick">
 				<Icon type="md-settings" />
 				<span>类别管理</span>
@@ -60,19 +65,17 @@
 				<Icon type="ios-paper-plane" />
 				<span>分享至公开课</span>
 			</div>
-		</div>
+		</div> -->
 		<div class="table-box">
-			<Scroll :on-reach-bottom="getMore" height="750" :distance-to-edge="[15, 15]">
-				<Table stripe :columns="tableColumn" :data="tableData" :loading="tableLoading">
+			<Scroll :on-reach-bottom="getMore" height="700" :distance-to-edge="[15, 15]">
+				<Table stripe :columns="tableColumnNew" :data="tableData" :loading="tableLoading">
 					<template slot-scope="{ row,index }" slot="tmdname">
 						<span>
-							<!-- <Tag color="#dfa718" v-if="index === 0">公开课</Tag> -->
 							{{ row.tmdname || row.tmdid }}
 						</span>
 					</template>
 					<template slot-scope="{ row,index }" slot="name">
 						<span>
-							<!-- <Tag color="#dfa718" v-if="index === 0">公开课</Tag> -->
 							{{ row.name }}
 						</span>
 					</template>
@@ -85,12 +88,16 @@
 					<template slot-scope="{ row }" slot="grade">
 						<span>{{ row.grade.map(i => curPeriod.grades[+i]).join(',') }}</span>
 					</template>
+					<template slot-scope="{ row }" slot="startTime">
+						<span>{{ $tools.formatTime(row.startTime) }}</span>
+					</template>
 					<template slot-scope="{ row }" slot="action">
-						<Icon class="action-icon" type="ios-paper-plane" color="#27a3cf"/>
+						<!-- <Icon class="action-icon" type="ios-paper-plane" color="#27a3cf"/>
 						<Icon class="action-icon" type="md-play" color="#34cf97" @click="doPlay(row)" />
-						<!-- <Icon class="action-icon" type="md-podium" color="#3197e5" @click="showAnalysis(row)" /> -->
 						<Icon class="action-icon" type="md-create" color="#3197e5" @click="doEdit(row)" />
-						<Icon class="action-icon" type="md-trash" color="#e25255" @click="doDelete(row)" />
+						<Icon class="action-icon" type="md-trash" color="#e25255" @click="doDelete(row)" /> -->
+						<Button size="small" type="success" style="margin-right: 5px;" @click="downloadTable">下载总表</Button>
+						<Button size="small" type="primary" @click="downloadTable">预览笔记</Button>
 					</template>
 				</Table>
 			</Scroll>
@@ -141,6 +148,7 @@
 		},
 		data() {
 			return {
+				analysisArr:['课堂记录总数','教师数','累计任务数','累计作品数','累计互动总数','本学期新增课堂记录数'],
 				isEdit: false,
 				editLoading: false,
 				tagLoading: false,
@@ -151,7 +159,7 @@
 				categoryModal: false,
 				formModal: false,
 				tableLoading: false,
-				tableHeight: document.documentElement.clientHeight * 0.58,
+				tableHeight: document.documentElement.clientHeight * 0.48,
 				curEditTag: '',
 				curEditIndex: -1,
 				curPage: 1,
@@ -220,6 +228,90 @@
 						className: "table-action"
 					}
 				],
+				tableColumnNew:[
+					{
+						title: '班级',
+						key: 'className',
+						ellipsis:true,
+					},
+					{
+						title: '教师名称',
+						key: 'tmdname',
+						ellipsis:true,
+					},
+					{
+						title: '课堂名称',
+						key: 'name',
+						ellipsis:true,
+					},
+					{
+						title: '日期',
+						slot: 'startTime',
+						ellipsis:true,
+						width:200
+					},
+					{
+						title: '出席率',
+						key: 'attendCount',
+						ellipsis:true,
+					},
+					{
+						title: '小组数',
+						key: 'groupCount',
+						ellipsis:true,
+					},
+					{
+						title: '总计分',
+						key: 'totalPoint',
+						ellipsis:true,
+					},
+					{
+						title: '任务总数',
+						key: 'collateTaskCount',
+						ellipsis:true,
+					},
+					{
+						title: '作品总数',
+						key: 'collateCount',
+						ellipsis:true,
+					},
+					{
+						title: '推送总数',
+						key: 'pushCount',
+						ellipsis:true,
+					},
+					{
+						title: '总互动分',
+						key: 'score',
+						ellipsis:true,
+					},
+					{
+						title: '互动题数',
+						key: 'interactionCount',
+						ellipsis:true,
+					},
+					{
+						title: '互动总数',
+						key: 'clientInteractionCount',
+						ellipsis:true,
+					},
+					{
+						title: '测验总题数',
+						key: 'examQuizCount',
+						ellipsis:true,
+					},
+					{
+						title: '测验得分率',
+						key: 'examPointRate',
+						ellipsis:true,
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						className: "table-action",
+						width:200
+					}
+				],
 				originList: []
 			}
 		},
@@ -228,6 +320,9 @@
 			this.initTags()
 		},
 		methods: {
+			downloadTable(){
+				this.$Message.warning('暂未处理')
+			},
 			/* 修改课堂记录基础信息 */
 			onEditLesson() {
 				console.log()
@@ -309,9 +404,10 @@
 			getMore() {
 				this.filterParams.continuationToken = this.continuationToken
 				if (this.continuationToken) {
-					this.$api.lessonRecord.getLessonList(this.filterParams).then(res => {
+					this.$api.lessonRecord.getLessonList(this.filterParams).then(async res => {
 						if (!res.error && res.lessonRecords) {
-							this.tableData = this.tableData.concat(this.getFullInfo(res.lessonRecords))
+							let schoolSas = await this.$tools.getSchoolSas()
+							this.tableData = this.tableData.concat(this.getFullInfo(res.lessonRecords,schoolSas))
 							this.continuationToken = res.continuationToken
 						}
 					})
@@ -320,7 +416,7 @@
 				}
 			},
 			/* 替换课例数据的科目学段等信息 */
-			getFullInfo(list) {
+			getFullInfo(list,schoolSas) {
 				let tchList = []
 				this.$nextTick(() => {
 					tchList = this.$refs.tchSelect.teacherList
@@ -331,8 +427,8 @@
 					}
 					let container = item.scope === 'school' ? item.school : item.tmdid
 					let blobHost = this.$evTools.getBlobHost()
-					item.poster = blobHost + '/' + container + '/records/' + item.id + '/Record/CoverImage.jpg'
-					item.videoPath = blobHost + '/' + container + '/records/' + item.id + '/Record/CourseRecord.mp4'
+					item.poster = blobHost + '/' + container + '/records/' + item.id + '/Record/CoverImage.jpg' + schoolSas.sas
+					item.videoPath = blobHost + '/' + container + '/records/' + item.id + '/Record/CourseRecord.mp4' + schoolSas.sas
 				})
 				return list
 			},
@@ -342,12 +438,14 @@
 				this.isReachBottom = false
 				this.filterParams.continuationToken = null
 				this.totalNum = await this.$api.lessonRecord.getLessonCount(this.filterParams)
-				this.$api.lessonRecord.getLessonList(this.filterParams).then(res => {
+				this.$api.lessonRecord.getLessonList(this.filterParams).then(async res => {
 					if (!res.error && res.lessonRecords) {
-						this.tableData = this.getFullInfo(res.lessonRecords)
+						let schoolSas = await this.$tools.getSchoolSas()
+						this.tableData = this.getFullInfo(res.lessonRecords,schoolSas)
 						this.isReachBottom = true
 						this.continuationToken = res.continuationToken
 						this.tableLoading = false
+						console.log(this.tableData)
 					}
 				})
 				this.filterParams.continuationToken = this.continuationToken

+ 2 - 1
TEAMModelOS/Controllers/Student/TmdUserController.cs

@@ -156,7 +156,8 @@ namespace TEAMModelOS.Controllers
             }
             catch (Exception ex)
             {
-                await _dingDing.SendBotMsg($"IES5,{_option.Location},Teacher/GetTeacherInfo()\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
+                request.TryGetProperty("id_token", out JsonElement id_token);
+                await _dingDing.SendBotMsg($"IES5,{_option.Location},Teacher/GetTeacherInfo()\n{ex.Message}{ex.StackTrace}\n{id_token}", GroupNames.醍摩豆服務運維群組);
                 return BadRequest();
             }
         }

+ 12 - 1
TEAMModelOS/Controllers/Teacher/TeacherCommonController.cs

@@ -197,7 +197,18 @@ namespace TEAMModelOS.Controllers
             {
                 privateSyllabusCount = item;
             }
-            return Ok(new { totalCount = count, goingDatas = datas, privateCourseCount, schoolCourseCount , classIdsCount= classIds.Count(), teachIdsCount= teachIds.Count(),   stulistsCount = stulists.Count(), privateItemCount , privatePaperCount, privateSyllabusCount });
+            List<string> bloblogTypes = new List<string>() ;
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<string>(
+                "select   value( c.type)     from c  "
+                , requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Bloblog-{id}") }))
+            {
+                bloblogTypes.Add(item);
+            }
+            var bloblogTypeCount= bloblogTypes.GroupBy(x => x).Select(y => new { type = y, count = y.ToList().Count });
+            return Ok(new { totalCount = count, goingDatas = datas, privateCourseCount, schoolCourseCount , classIdsCount= classIds.Count(), teachIdsCount= teachIds.Count(),   stulistsCount = stulists.Count(), 
+                privateItemCount , privatePaperCount, privateSyllabusCount, privateBloblogCount= bloblogTypes.Count,
+                bloblogTypeCount
+            });
         }
 
 

+ 0 - 1
TEAMModelOS/appsettings.Development.json

@@ -21,7 +21,6 @@
   },
   "Azure": {
     "Storage": {
-      //"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelstorage;AccountKey=Yq7D4dE6cFuer2d2UZIccTA/i0c3sJ/6ITc8tNOyW+K5f+/lWw9GCos3Mxhj47PyWQgDL8YbVD63B9XcGtrMxQ==;EndpointSuffix=core.chinacloudapi.cn",
       "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodeltest;AccountKey=O2W2vadCqexDxWO+px+QK7y1sHwsYj8f/WwKLdOdG5RwHgW/Dupz9dDUb4c1gi6ojzQaRpFUeAAmOu4N9E+37A==;EndpointSuffix=core.chinacloudapi.cn"
     },
     "Cosmos": {