Jelajahi Sumber

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

zhouj1203@hotmail.com 3 tahun lalu
induk
melakukan
c0b3752a10
36 mengubah file dengan 1011 tambahan dan 162 penghapusan
  1. 100 7
      TEAMModelBI/Controllers/Census/ActivitySticsController.cs
  2. 169 0
      TEAMModelBI/Controllers/Census/BlobLogController.cs
  3. 5 0
      TEAMModelBI/Models/MonthStartEnd.cs
  4. 1 0
      TEAMModelBI/TEAMModelBI.csproj
  5. 41 2
      TEAMModelBI/Tool/CommonFind.cs
  6. 1 1
      TEAMModelOS.SDK/Models/Cosmos/School/Course.cs
  7. 1 1
      TEAMModelOS.SDK/Models/Cosmos/School/Room.cs
  8. 1 0
      TEAMModelOS.SDK/Models/Cosmos/School/TeacherImport.cs
  9. TEMPAT SAMPAH
      TEAMModelOS/ClientApp/src/assets/image/no-poster-cn.png
  10. TEMPAT SAMPAH
      TEAMModelOS/ClientApp/src/assets/image/no-poster-en.png
  11. TEMPAT SAMPAH
      TEAMModelOS/ClientApp/src/assets/image/no-poster-tw.png
  12. 10 4
      TEAMModelOS/ClientApp/src/common/AbilityUpload.vue
  13. 1 1
      TEAMModelOS/ClientApp/src/common/BaseNotification.vue
  14. 7 0
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.less
  15. 3 2
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue
  16. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/home.js
  17. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/studentWeb.js
  18. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/home.js
  19. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/studentWeb.js
  20. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/home.js
  21. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/studentWeb.js
  22. 110 0
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseHiteachPaper.vue
  23. 1 0
      TEAMModelOS/ClientApp/src/view/evaluation/index/CommonExercise.less
  24. 7 2
      TEAMModelOS/ClientApp/src/view/evaluation/index/TestPaper.vue
  25. 18 0
      TEAMModelOS/ClientApp/src/view/homepage/HomePage.less
  26. 47 3
      TEAMModelOS/ClientApp/src/view/homepage/HomePage.vue
  27. 47 0
      TEAMModelOS/ClientApp/src/view/homepage/RcdPoster.vue
  28. 6 2
      TEAMModelOS/ClientApp/src/view/learnactivity/ExamMgt.vue
  29. 4 2
      TEAMModelOS/ClientApp/src/view/learnactivity/markpaper/MarkSetting.vue
  30. 9 1
      TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.less
  31. 71 69
      TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue
  32. 1 1
      TEAMModelOS/Controllers/Both/LessonRecordController.cs
  33. 1 1
      TEAMModelOS/Controllers/Client/HiTeachController.cs
  34. 55 4
      TEAMModelOS/Controllers/School/SchoolController.cs
  35. 253 56
      TEAMModelOS/Controllers/School/SchoolTeacherController.cs
  36. 35 0
      TEAMModelOS/Controllers/Teacher/InitController.cs

+ 100 - 7
TEAMModelBI/Controllers/Census/ActivitySticsController.cs

@@ -258,7 +258,7 @@ namespace TEAMModelBI.Controllers.Census
                 ActivityCount tempCount = new ActivityCount() { id = school.id, name = school.name != null ? school.name : school.id };
                 foreach (var type in types)
                 {
-                    StringBuilder sqlTxt = new StringBuilder($"select COUNT(c.id) AS totals from c where c.pk='{type}' and c.school='{school.id}' ");                
+                    StringBuilder sqlTxt = new($"select COUNT(c.id) AS totals from c where c.pk='{type}' and c.school='{school.id}' ");                
                     long totals = await CommonFind.FindTotals(cosmosClient, sqlTxt.ToString(), new List<string>() { "Common" });
 
                     switch (type)
@@ -299,7 +299,15 @@ namespace TEAMModelBI.Controllers.Census
 
             var cosmosClient = _azureCosmos.GetCosmosClient();
             List<RecSchool> schools = new();
-            await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<RecSchool>(queryText: $"select c.id,c.name,c.picture,c.size,c.scale,c.type from c where c.areaId='{areaId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
+
+
+            StringBuilder scSqlTxt = new("select c.id,c.name,c.picture,c.size,c.scale,c.type from c");
+            if (!string.IsNullOrEmpty($"{areaId}"))
+            {
+                scSqlTxt.Append($" where c.areaId='{areaId}'");
+            }
+
+            await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<RecSchool>(queryText: scSqlTxt.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
             {
                 schools.Add(item);
             }
@@ -331,7 +339,7 @@ namespace TEAMModelBI.Controllers.Census
                     heCount += 1;
                 else if (school.type == 1)
                     geCount += 1;
-                else oeCount += 0;
+                else oeCount += 1;
 
                 areaSize += school.size;
 
@@ -387,8 +395,7 @@ namespace TEAMModelBI.Controllers.Census
                 ActivityCount tempActivity = new ActivityCount() { id = school.id, name = school.name != null ? school.name : school.id };
                 foreach (var type in types)
                 {
-                    string sqlTxt = new string($"select COUNT(c.id) AS totals from c where c.pk='{type}' and c.school='{school.id}' ");
-                    long totals = await CommonFind.FindTotals(cosmosClient, sqlTxt, new List<string>() { "Common" });
+                    long totals = await CommonFind.FindTotals(cosmosClient, $"select COUNT(c.id) AS totals from c where c.pk='{type}' and c.school='{school.id}' ", new List<string>() { "Common" });
 
                     string weekSql= $"select count(c.id) as totals from c where c.pk='{type}' and c.school='{school.id}' and c.createTime>={weekStart}   and c.createTime<={weekEnd}";
                     long weekCount = await CommonFind.FindTotals(cosmosClient, weekSql, new List<string>() { "Common" });
@@ -422,6 +429,76 @@ namespace TEAMModelBI.Controllers.Census
             return Ok(new { state = 200, schoolCount = schools.Count, countArea, weekActivity, termActivity, totalTime, appraiseArea, examAreaCount, surveyAreaCount, voteAreaCount, homeworkAreaCount, schools = schoolInfos, schoolLessons });
         }
 
+        /// <summary>
+        /// 所有区的统计接口
+        /// </summary>
+        /// <returns></returns>
+        [HttpPost("get-all")]
+        public async Task<IActionResult> GetAll() 
+        {
+            var cosmosClient = _azureCosmos.GetCosmosClient();
+
+            List<AreaInfo> areaInfos = new();
+            await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "Normal").GetItemQueryIterator<AreaInfo>(queryText: $"select c.id,c.name,c.standard,c.standardName from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base-Area") }))
+            {
+                areaInfos.Add(item);
+            }
+
+            var (weekStart, weekEnd) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow, "week");
+            var (termStart, termEnd) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow, "term");
+            int heCount = 0;//高教
+            int geCount = 0;//普教
+            int oeCount = 0; //其他教育
+            int allSize = 0;//空间总量
+            Dictionary<string, long> activitys = new(); //活动类型集合
+            long allActivity = 0;  //活动累计
+            long weekActivity = 0;//本周活动
+            long tearActivity = 0;//本学期活动
+            long weekLess = 0;      //本周课例
+            long termLess = 0;     //本学期课例
+            long allLess = 0;     //所有课例
+
+            foreach (var area in areaInfos) 
+            {
+                List<RecSchool> recSchools = new();
+                await foreach (var school in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<RecSchool>(queryText: $"select c.id,c.name,c.picture,c.type,c.size,c.scale from c where c.areaId='{area.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") })) 
+                {
+                    recSchools.Add(school);
+                }
+
+                recSchools.ForEach(x => { if (x.type == 2) heCount += 1; else if (x.type == 1) geCount += 1; else oeCount += 1; });
+                allSize += recSchools.Select(s => s.size).Sum();
+                area.schoolCount = recSchools.Count;
+                //查教师
+                area.techCount = await CommonFind.GetPeopleNumber(cosmosClient,"School",recSchools?.Select(x=>x.id).ToList(), "Teacher");
+                //查询省
+                area.stuCount = await CommonFind.GetPeopleNumber(cosmosClient, "Student", recSchools?.Select(x => x.id).ToList(), "Base");
+            }
+
+            //统计活动
+            foreach (var type in types)
+            {
+                string sqlTxt = $"select COUNT(c.id) AS totals from c where c.pk='{type}'";
+                long totals = await CommonFind.FindTotals(cosmosClient, sqlTxt, new List<string>() { "Common" });
+
+                string weekSql = $"select COUNT(c.id) AS totals from c where c.pk='{type}' and c.createTime>={weekStart} and c.createTime<={weekStart} ";
+                weekActivity  += await CommonFind.FindTotals(cosmosClient, weekSql,new List<string> { "Common" });
+
+                string termSql = $"select COUNT(c.id) AS totals from c where c.pk='{type}' and c.createTime>={termStart} and c.createTime<={termEnd} ";
+                tearActivity += await CommonFind.FindTotals(cosmosClient, termSql, new List<string> { "Common" });
+
+                allActivity += totals;
+                activitys.Add(type, totals);
+            }
+            
+            allLess = await CommonFind.FindTotals(cosmosClient, "select count(c.id) as totals from c where c.pk='LessonRecord'", new List<string>() { "School" });
+            weekLess = await CommonFind.FindTotals(cosmosClient, $"select count(c.id) as totals from c where c.pk='LessonRecord' and c.startTime>={weekStart} and c.startTime <={weekEnd}", new List<string>() { "School", "Teacher" });
+            termLess = await CommonFind.FindTotals(cosmosClient, $"select count(c.id) as totals from c where c.pk='LessonRecord' and c.startTime>={termStart} and c.startTime <={termEnd}", new List<string>() { "School","Teacher" });
+
+            return Ok(new { state = 200, areaCount = areaInfos.Count, allSize, heCount, geCount, oeCount, allLess, termLess, weekLess, allActivity, tearActivity,weekActivity, areaInfos });
+        }
+                
+
         /// <summary>
         /// 依据活动Id查询活动详情信息  数据管理工具——查询工具
         /// </summary>
@@ -467,7 +544,23 @@ namespace TEAMModelBI.Controllers.Census
             return Ok(new { state = 200, infos });
         }
 
+        /// <summary>
+        /// 区级信息
+        /// </summary>
+        public record AreaInfo
+        {
+            public string id { get; set; }
+            public string name { get; set; }
+            public string standard { get; set; }
+            public string standardName { get; set; }
+            public int schoolCount { get; set; }
+            public int techCount { get; set;}
+            public int stuCount { get; set; }
+        }
 
+        /// <summary>
+        /// 区级下学校信息显示
+        /// </summary>
         public record RecSchool
         {
             public string id { get; set; }
@@ -500,10 +593,10 @@ namespace TEAMModelBI.Controllers.Census
             public string id { get; set; }
             public string name { get; set; }
             public string picture { get; set; }
-            public int count{get;set;}
+            public int count { get; set; }
         }
 
-            public record ActivityCount 
+        public record ActivityCount
         {
             public string id { get; set; }
             public string name { get; set; }

+ 169 - 0
TEAMModelBI/Controllers/Census/BlobLogController.cs

@@ -0,0 +1,169 @@
+using Azure.Cosmos;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using StackExchange.Redis;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelBI.Models;
+using TEAMModelBI.Tool;
+using TEAMModelBI.Tool.Cosmos;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Models;
+
+namespace TEAMModelBI.Controllers.Census
+{
+    [Route("bloblog")]
+    [ApiController]
+    public class BlobLogController : ControllerBase
+    {
+        private readonly AzureCosmosFactory _azureCosmos;
+        private readonly AzureStorageFactory _azureStorage;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+        private readonly AzureRedisFactory _azureRedis;
+
+        public BlobLogController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureFactory, DingDing dingDing, IOptionsSnapshot<Option> option, AzureRedisFactory azureRedis)
+        {
+            _azureCosmos = azureCosmos;
+            _azureStorage = azureFactory;
+            _dingDing = dingDing;
+            _option = option?.Value;
+            _azureRedis = azureRedis;
+        }
+
+        /// <summary>
+        /// 空间统计数量统计
+        /// </summary>
+        /// <param name="jsonElement"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-area")]
+        public async Task<IActionResult> GetArea(JsonElement jsonElement) 
+        {
+            jsonElement.TryGetProperty("areaId", out JsonElement areaId);
+            var cosmosClient = _azureCosmos.GetCosmosClient();
+            StringBuilder sqlSize = new($"select sum(c.size) as totals from c ");
+            long useSize = 0;
+            List<RecBlobFile> blobFiles = new();
+
+            if (!string.IsNullOrEmpty($"{areaId}"))
+            {
+                string sqlTxt = $"select c.id from c where c.areaId='{areaId}'";
+                sqlSize.Append($" where c.areaId = '{areaId}'");
+
+                List<string> schools = await CommonFind.FindSchoolIds(cosmosClient, sqlTxt.ToString(), "Base");
+                foreach (var id in schools)
+                {
+                    await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<RecBlobFile>(queryText: "SELECT c.id,c.code,c.name,c.size,c.type FROM c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Bloblog-{id}") }))
+                    {
+                        blobFiles.Add(item);
+                    }
+
+                    List<string> tecId = await CommonFind.FindRolesId(cosmosClient, schools);
+                    List<RecBlobFile> tecBlob = await GetBlobTeache(cosmosClient, tecId);
+                    if (tecBlob.Count > 0) 
+                    {
+                        blobFiles.Concat(tecBlob);
+                    }
+
+                    await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<RecBlobFile>(queryText: $"SELECT c.id,c.code,c.name,c.size,c.type FROM c where c.pk='Bloblog'", requestOptions: new QueryRequestOptions() { }))
+                    {
+                        blobFiles.Add(item);
+                    }
+
+                    long blobsize = 0;
+                    RedisValue value = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", $"{id}");
+                    if (!value.IsNullOrEmpty)
+                    {
+                        JsonElement record = value.ToString().ToObject<JsonElement>();
+                        if (record.TryGetInt64(out blobsize))
+                        {
+                            useSize += blobsize;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<RecBlobFile>(queryText: "SELECT c.id,c.code,c.name,c.size,c.type FROM c where c.pk='Bloblog'", requestOptions: new QueryRequestOptions() { }))
+                {
+                    blobFiles.Add(item);
+                }
+
+                await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<RecBlobFile>(queryText: "SELECT c.id,c.code,c.name,c.size,c.type FROM c where c.pk='Bloblog'", requestOptions: new QueryRequestOptions() { }))
+                {
+                    blobFiles.Add(item);
+                }
+
+                List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"select c.id from c", "Base");
+
+                foreach (var id in schoolIds) 
+                {
+                    long blobsize = 0;
+                    RedisValue value = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", $"{id}");
+                    if (!value.IsNullOrEmpty)
+                    {
+                        JsonElement record = value.ToString().ToObject<JsonElement>();
+                        if (record.TryGetInt64(out blobsize))
+                        {
+                            useSize += blobsize;
+                        }
+                    }
+                }
+            }
+
+            var typeCount = blobFiles.GroupBy(m => new { m.type }).Select(y => new { key = y.Key.type, value = y.Count() }).ToList();
+            var areaSize = await CommonFind.FindTotals(cosmosClient, sqlSize.ToString(), "School", "Base");
+
+            return Ok(new { state = 200, areaSize, useSize, typeCount });
+
+        }
+
+        /// <summary>
+        /// 依据教师获取教师个人的记录
+        /// </summary>
+        /// <param name="cosmosClient"></param>
+        /// <param name="teacherIds"></param>
+        /// <returns></returns>
+        public async static Task<List<RecBlobFile>> GetBlobTeache(CosmosClient cosmosClient, List<string> teacherIds)
+        {
+            List<RecBlobFile> blobFiles = new();
+            if (teacherIds.Count > 0)
+            {
+                foreach (var teacherId in teacherIds)
+                {
+                    await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<RecBlobFile>(queryText: $"SELECT c.id,c.code,c.name,c.size,c.type FROM c where c.pk='Bloblog'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Bloblog-{teacherId}") }))
+                    {
+                        blobFiles.Add(item);
+                    }
+                }
+            }
+
+            return blobFiles;
+        }
+
+
+
+        /// <summary>
+        /// 空间内容信息
+        /// </summary>
+        public record RecBlobFile
+        {
+            public string id { get; set; }
+            public string code { get; set; }
+            public string name { get; set; }
+            public int size { get; set; }
+            public string type { get; set; }
+
+        }
+
+
+    }
+
+}

+ 5 - 0
TEAMModelBI/Models/MonthStartEnd.cs

@@ -10,9 +10,14 @@
 
     }
 
+    /// <summary>
+    /// 教师列表
+    /// </summary>
     public class SchoolTeacherRoles
     {
         public string tmdId { get; set; }
         public string tmdName { get; set; }
     }
+
+
 }

+ 1 - 0
TEAMModelBI/TEAMModelBI.csproj

@@ -27,6 +27,7 @@
 	</ItemGroup>
 
 	<ItemGroup>
+		<Folder Include="Tool\Cosmos\StudentBank\" />
 		<Folder Include="wwwroot\" />
 	</ItemGroup>
 	<PropertyGroup>

+ 41 - 2
TEAMModelBI/Tool/CommonFind.cs

@@ -1,6 +1,7 @@
 using Azure.Cosmos;
 using System;
 using System.Collections.Generic;
+using System.Text;
 using System.Text.Json;
 using System.Threading.Tasks;
 using TEAMModelBI.Models;
@@ -182,12 +183,12 @@ namespace TEAMModelBI.Tool
             return assistSchools;
         }
 
-
         /// <summary>
         /// 依据学校查询教师列表
         /// </summary>
         /// <param name="cosmosClient"></param>
-        /// <param name="schools"></param>
+        /// <param name="schools">学校列表</param>
+        /// <param name="roles">不传默认教师角色</param>
         /// <returns></returns>
         public static async Task<List<string>> FindRolesId(CosmosClient cosmosClient, List<string> schools, string roles = null)
         {
@@ -213,5 +214,43 @@ namespace TEAMModelBI.Tool
             return teachers;
         }
 
+
+        /// <summary>
+        /// 依据学校Id集合查询 学校人数统计
+        /// </summary>
+        /// <param name="cosmosClient"></param>
+        /// <param name="container"></param>
+        /// <param name="schoolId"></param>
+        /// <param name="code"></param>
+        /// <returns></returns>
+        public static async Task<int> GetPeopleNumber(CosmosClient cosmosClient, string container, List<string> schoolId, string code,string sqlWhere = null) 
+        {
+            int totals = 0;
+            StringBuilder sqlTxt = new("select count(c.id) as totals from c ");
+            if (!string.IsNullOrEmpty(sqlWhere)) 
+            {
+                sqlTxt.Append(sqlWhere);
+            }
+
+            if (schoolId.Count > 0)
+            {
+                foreach (var id in schoolId)
+                {
+                    await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", container).GetItemQueryStreamIterator(queryText: sqlTxt.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{code}-{id}") }))
+                    {
+                        using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                        if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetInt32() > 0)
+                        {
+                            foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                            {
+                                totals += obj.GetProperty("totals").GetInt32();
+                            }
+                        }
+                    }
+                }
+            }
+
+            return totals;
+        }
     }
 }

+ 1 - 1
TEAMModelOS.SDK/Models/Cosmos/School/Course.cs

@@ -164,7 +164,7 @@ namespace TEAMModelOS.SDK.Models
         public string name { get; set; }
         public string desc { get; set; }
         public string no { get; set; }
-        [Required(ErrorMessage = "{0} 课程的科目id必须填写"), RegularExpression(@"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}",ErrorMessage ="科目的uuid格式错误!")]
+        [Required(ErrorMessage = "{0} 课程的科目id必须填写"), RegularExpression(@"[0-9a-zA-Z]{8}(-[0-9a-zA-Z]{4}){3}-[0-9a-zA-Z]{12}",ErrorMessage ="科目的uuid格式错误!")]
         public string subjectId { get; set; }
    
         public string subjectName { get; set; }

+ 1 - 1
TEAMModelOS.SDK/Models/Cosmos/School/Room.cs

@@ -47,7 +47,7 @@ namespace TEAMModelOS.SDK.Models
 
     public class RoomDto
     {
-        [Required(ErrorMessage = "物理教室的id必须填写"), RegularExpression(@"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}", ErrorMessage = "物理教室的uuid格式错误!")]
+        [Required(ErrorMessage = "物理教室的id必须填写"), RegularExpression(@"[0-9a-zA-Z]{8}(-[0-9a-zA-Z]{4}){3}-[0-9a-zA-Z]{12}", ErrorMessage = "物理教室的uuid格式错误!")]
         public string id { get; set; }
         [Required(ErrorMessage = "{0} 教室的名称必须填写")]
         public string name { get; set; }

+ 1 - 0
TEAMModelOS.SDK/Models/Cosmos/School/TeacherImport.cs

@@ -17,6 +17,7 @@ namespace TEAMModelOS.SDK.Models
         // 手机号或者醍摩豆id,可以为空,则没正式加入学校的教师 
         public string id { get; set; }
         public string name { get; set; }
+        public string picture { get; set; }
         public string status { get; set; }
         public long time { get; set; }
         public string tmdid { get; set; }

TEMPAT SAMPAH
TEAMModelOS/ClientApp/src/assets/image/no-poster-cn.png


TEMPAT SAMPAH
TEAMModelOS/ClientApp/src/assets/image/no-poster-en.png


TEMPAT SAMPAH
TEAMModelOS/ClientApp/src/assets/image/no-poster-tw.png


+ 10 - 4
TEAMModelOS/ClientApp/src/common/AbilityUpload.vue

@@ -210,15 +210,22 @@
 				for (let i = 0; i < list.length; i++) {
 					let file = list[i]
 					try {
-						let blobFile = await containerClient.upload(file, { path:path,checkSize:true }, {
+						let blobFile = await containerClient.upload(file, { path:path,checkSize:this.auth.name !== 'teammodelos' }, {
 							onProgress: function(e) {
 								that.$set(that.progressArr, i, parseInt(e.loadedBytes * 100 / file.size))
 							}
 						});
+						console.log(blobFile)
 						// 如果上传的是视频文件 则需要获取视频的时长信息和MD5信息
 						if (blobFile.type === 'video') {
-							await this.uploadVideoPoster(blobFile, path, containerClient)
-							blobFile.duration = await this.$tools.getVideoDuration(file)
+							if(blobFile.extension === 'MP4'){
+								await this.uploadVideoPoster(blobFile, path, containerClient)
+								blobFile.duration = await this.$tools.getVideoDuration(file)
+							}else{
+								this.$Message.warning('当前视频可能无法播放,请检查视频编码格式')
+								blobFile.duration = 0
+							}
+							
 						}
 						let fileMD5 = await this.$tools.getFileMD5(file)
 						blobFile.hash = this.$tools.convertFileMD5ToString(fileMD5)
@@ -245,7 +252,6 @@
 						let blobFile = await containerClient.upload(f, { path:path,checkSize:false });
 						r(blobFile)
 					} catch (e) {
-						this.$Message.error('当前视频可能无法播放,请检查视频编码格式')
 						r(e)
 					}
 				})

+ 1 - 1
TEAMModelOS/ClientApp/src/common/BaseNotification.vue

@@ -3,7 +3,7 @@
 		<Badge :count="msgArr.length">
 			<Icon type="md-notifications" size="20"  @click="openDrawer"/>
 		</Badge>
-		<Drawer :title="$t('utils.newNotice')" v-model="isOpen" width="400" class-name="base-notification" transfer>
+		<Drawer :title="$t('utils.newNotice')" v-model="isOpen" width="400" class-name="base-notification" transfer :closable="false">
 			<div class="notice-header" slot="header">
 				<span style="font-size: 18px;font-weight: bold;">{{ $t('utils.newNotice') }}</span>
 				<span style="color:red;font-size: 12px;cursor: pointer;" v-if="msgArr.length"

+ 7 - 0
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.less

@@ -185,6 +185,13 @@
             max-width: 100%;
         }
     }
+
+    .no-img {
+        margin-top: 50px;
+        margin-bottom: 10px;
+        text-align: center;
+        font-size: 18px;
+    }
 }
 
 .qcol {

+ 3 - 2
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue

@@ -362,7 +362,8 @@
                 <div style="display: flex;">
                     <div style="width: 50%;">
                         <template v-if="!imgList.length">
-                            <p style="margin-bottom: 10px; text-align: center;font-size: 18px;">
+                            <p class="no-img">
+                                <Icon type="ios-alert" color="#FA6400" />
                                 {{ $t("studentWeb.exam.message.noQamode") }}
                             </p>
                         </template>
@@ -439,7 +440,7 @@
                                             <div v-for="(answerC, indexCA) in exam.answer" :key="indexCA" v-html="answerC"></div>
                                         </div>
                                         <div v-if="!exam.answer.length" class="item-explain-details">
-                                            <span>{{ $t('studentWeb.exam.report.noAns') }}</span>
+                                            <span>{{ $t('studentWeb.exam.report.noTestAns') }}</span>
                                         </div>
                                     </div>
                                     <!-- 解析 -->

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

@@ -1,7 +1,7 @@
 export default{
     previewStudy:'Previews before class',
     classData:'Lesson Data',
-    recentRecord:'Recent Lesson Record',
+    recentRecord:'近期7日課堂記錄',
     acCount:'Activities Overview',
     goingList:'List Of Ongoing Activities',
     scNotice:'School Announcement',

+ 1 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/studentWeb.js

@@ -545,6 +545,7 @@ export default {
             fileView: 'Preview File',
             noReview: 'This file does not support preview, please download and view! ',
             pdfErr: 'Failed to load PDF',
+            noTestAns: '暫無',
             noMark: 'Not annotated yet',
             noAnalyse: 'No explanation yet',
             noKnowledge: 'No key concept yet',

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

@@ -1,7 +1,7 @@
 export default{
     previewStudy:'课前预习',
     classData:'课堂数据',
-    recentRecord:'近期课堂记录',
+    recentRecord:'近期7日课堂记录',
     acCount:'活动概览',
     goingList:'进行中的活动列表',
     scNotice:'学校公告',

+ 1 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/studentWeb.js

@@ -545,6 +545,7 @@ export default {
             fileView: '文件预览',
             noReview: '该文件暂不支持预览,请下载查看!',
             pdfErr: 'pdf 加载失败',
+            noTestAns: '暂无',
             noMark: '暂无批注',
             noAnalyse: '暂无解析',
             noKnowledge: '暂无知识点',

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

@@ -1,7 +1,7 @@
 export default {
     previewStudy: '課前預習',
     classData: '課堂數據',
-    recentRecord: '近期課堂記錄',
+    recentRecord: '近期7日課堂記錄',
     acCount: '活動概覽',
     goingList: '進行中',
     scNotice: '學校公告',

+ 1 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/studentWeb.js

@@ -545,6 +545,7 @@ export default {
             fileView: '檔案預覽',
             noReview: '該檔案暫不支持預覽,請下載查看! ',
             pdfErr: 'pdf 載入失敗',
+            noTestAns: '暫無',
             noMark: '暫無批註',
             noAnalyse: '暫無解析',
             noKnowledge: '暫無知識點',

+ 110 - 0
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseHiteachPaper.vue

@@ -0,0 +1,110 @@
+<template>
+	<!-- 纸本测验 图片轮播 -->
+	<div class="hiteach-test-container" v-if="isRender">
+		<div v-if="fullImgArr.length">
+			<Carousel v-model="curImgIndex">
+				<CarouselItem v-for="(item,index) in fullImgArr" v-if="isRender">
+					<div class="demo-carousel">
+						<img v-lazy="item">
+					</div>
+				</CarouselItem>
+			</Carousel>
+			<p class="page-footer">{{ $t('answerSheet.tip2') }} {{ curImgIndex + 1 }} {{ $t('answerSheet.tip21') }} / {{ $t('answerSheet.tip9') }} {{ fullImgArr.length }} {{ $t('answerSheet.tip21') }}</p>
+		</div>
+		<div v-else class="empty-box">
+			<img src="@/assets/image/none.png" >
+			<p>{{ $t('vote.noData') }}</p>
+		</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		props:{
+			paper:{
+				type:Object,
+				default:() => {}
+			}
+		},
+		data(){
+			return {
+				isRender:false,
+				curImgIndex:0,
+				fullImgArr:[]
+			}
+		},
+		methods:{
+			async doRender(paper){
+				let curScope = paper.examScope
+				let blobHost = curScope === 'school' ?  JSON.parse(decodeURIComponent(localStorage.school_profile, "utf-8")).blob_uri :  JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8")).blob_uri
+				let sasString = curScope === 'school' ?  await this.$tools.getSchoolSas() : await this.$tools.getPrivateSas()
+				this.fullImgArr = paper.attachments.map(imgName => blobHost + paper.blob + '/' + imgName + sasString.sas)
+			}
+		},
+		mounted() {
+			this.$EventBus.$off('EvBarChange')
+			this.$EventBus.$on('EvBarChange',index => {
+				if(index === 1){
+					this.isRender = true
+					this.doRender(this.paper)
+				}else{
+					this.isRender = false
+				}
+			})
+			
+		},
+		watch: {
+			paper: {
+				handler(newValue, oldValue) {
+					if (newValue.attachments && newValue.attachments.length) {
+						console.error('HiteachPaper > paper', newValue)
+						if(this.isRender){
+							this.doRender(newValue)
+						}
+					}
+				},
+				immediate: true
+			}
+		}
+	}
+</script>
+
+<style lang="less">
+	.hiteach-test-container{
+		width: 100%;
+		
+		// .ivu-carousel-track,.ivu-carousel-item{
+		// 	width: 100% !important;
+		// }
+		
+		.demo-carousel{
+			img{
+				margin-left: 4%;
+				width: 92%;
+			}
+			img[lazy=loading] {
+				width: 40px !important;
+				height: 40px !important;
+			}
+		}
+		
+		.page-footer{
+			text-align: center;
+			padding: 10px 0;
+		}
+		
+		.empty-box{
+			width: 100%;
+			display: flex;
+			flex-direction: column;
+			justify-content: center;
+			align-items: center;
+			font-size: 20px;
+			color: #C0C0C0;
+			font-weight: bold;
+			img{
+				width: 400px;
+			}
+		}
+	}
+</style>

+ 1 - 0
TEAMModelOS/ClientApp/src/view/evaluation/index/CommonExercise.less

@@ -153,6 +153,7 @@
   }
   img {
     vertical-align: middle;
+	max-width: 100%;
   }
   .item-btn-toggle {
     position: absolute;

+ 7 - 2
TEAMModelOS/ClientApp/src/view/evaluation/index/TestPaper.vue

@@ -7,7 +7,7 @@
 		<div class="paper-main-wrap">
 			<!-- 试卷内容 -->
 			<div class="paper-content">
-				<div class="paper-body">
+				<div class="paper-body" v-show="!isHiteachPaper">
 					<!-- 试卷基础信息 -->
 					<div class="paper-base-info" v-show="!isPreview &&  !isPreviewItems">
 						<div style="display: flex;">
@@ -71,6 +71,7 @@
 						ref="exList" :isShowTools="!isPreview" :canFix="canFix" :isExamPaper="isExamPaper || isPreviewItems" @toggleChange="onToggleChange"
 						@scoreUpdate="scoreUpdate"></BaseExerciseList>
 				</div>
+				<BaseHiteachPaper v-show="isHiteachPaper" :paper="paperInfo"></BaseHiteachPaper>
 			</div>
 		</div>
 
@@ -166,6 +167,7 @@
 		},
 		data() {
 			return {
+				isHiteachPaper:true,
 				editLoading:false,
 				hasModify:false,
 				curOrderTempIndex:0,
@@ -443,8 +445,11 @@
 				handler(newValue, oldValue) {
 					if (newValue.item && newValue.item.length) {
 						this.$nextTick(() => {
+							this.isHiteachPaper = newValue.qamode === 1
+							if(!this.isHiteachPaper){
+								this.$EventBus.$emit('getNewPaper', newValue)
+							}
 							console.log('TestPaper > paper', newValue)
-							this.$EventBus.$emit('getNewPaper', newValue)
 						})
 						this.curOrderTempIndex = newValue.orderTemp || 0
 						this.paperInfo = newValue

+ 18 - 0
TEAMModelOS/ClientApp/src/view/homepage/HomePage.less

@@ -422,4 +422,22 @@
     font-size: 16px;
     margin-left: 10px;
     color: #2d8cf0;
+}
+.rcd-item{
+    display: flex;
+    align-items: center;
+    border-bottom: 1px solid #f3f3f3;
+    padding: 5px 5px 5px 0px;
+    cursor: pointer;
+    &:hover{
+        background: #f3f3f3;
+    }
+}
+.rcd-poster{
+    margin-right: 5px;
+    width: 80px;
+}
+.rcd-time{
+    font-size: 12px;
+    color: #cccccc;
 }

+ 47 - 3
TEAMModelOS/ClientApp/src/view/homepage/HomePage.vue

@@ -223,11 +223,23 @@
                     </div>
                 </div> -->
                 <!-- 最近课堂记录-->
-                <div class="recent-box">
+                <div class="recent-box" style="padding-right:5px">
                     <p class="text-title">{{$t('home.recentRecord')}}</p>
                     <div class="recent-list-wrap">
                         <vuescroll>
-                            <EmptyData :textContent="$t('home.noRecord')"></EmptyData>
+                            <EmptyData :textContent="$t('home.noRecord')" v-if="!recentRcdList.length"></EmptyData>
+                            <template v-else>
+                                <div class="rcd-item" v-for="item in recentRcdList" :key="item.id">
+                                    <RcdPoster class="rcd-poster" :poster="item.poster"></RcdPoster>
+                                    <div>
+                                        <p>{{item.name}}</p>
+                                        <p class="rcd-time">
+                                            <Icon type="md-time" color="#70B1E7" />
+                                            {{$jsFn.timeFormat(item.startTime)}}
+                                        </p>
+                                    </div>
+                                </div>
+                            </template>
                         </vuescroll>
                     </div>
                 </div>
@@ -245,6 +257,7 @@
 import { mapGetters } from 'vuex'
 import countTo from 'vue-count-to'
 import AcCountPie from "./AcCountPie.vue"
+import RcdPoster from "./RcdPoster.vue"
 import HourDetail from "./HourDetail.vue"
 import TechScore from "./TechScore.vue"
 import TeachScore from "./TeachScore.vue"
@@ -255,11 +268,12 @@ import SpaceInfo from "./SpaceInfo.vue"
 import BlobTool from '@/utils/blobTool.js'
 export default {
     components: {
-        AcCountPie, TechScore, TeachScore, MinTable, HourDetail, countTo, ScoreCount, WeekCount, SpaceInfo
+        AcCountPie, TechScore, TeachScore, MinTable, HourDetail, countTo, ScoreCount, WeekCount, SpaceInfo, RcdPoster
     },
     inject: ['reload'],
     data() {
         return {
+            recentRcdList: [],
             sizeLoading: false,
             countData: {},
             platformList: [],
@@ -370,6 +384,35 @@ export default {
         }
     },
     methods: {
+        //查询近期课堂记录
+        getRecordList() {
+            let listType = 'school'
+            let params = {
+                "tmdid": this.$store.state.userInfo.TEAMModelId,
+                "scope": listType,
+                "school": this.$store.state.userInfo.schoolCode,
+                "DESC": "startTime",
+                "pageCount": 50,
+                "week": true
+            }
+            this.$api.lessonRecord.getLessonList(params).then(
+                res => {
+                    this.recentRcdList = res.lessonRecords
+                    let sasInfo = {}
+                    let blobInfo = listType === 'school' ? this.$store.state.user.schoolProfile : this.$store.state.user.userProfile
+                    sasInfo.sas = '?' + blobInfo.blob_sas
+                    sasInfo.name = 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.recentRcdList.forEach(item => {
+                        item.poster = `${sasInfo.url}/${sasInfo.name}/records/${item.id}/Record/CoverImage.jpg${sasInfo.sas}`
+                    })
+                    console.log(this.recentRcdList)
+                },
+                err => {
+                    this.$Message.error(this.$t('cusMgt.rcdErr'))
+                }
+            )
+        },
         // 获取容器空间情况 
         getBlobSize() {
             this.sizeLoading = true
@@ -678,6 +721,7 @@ export default {
         this.getSchoolSetting()
         this.getAcCount()
         this.getBlobSize()
+        this.getRecordList()
         if (this.$store.state.userInfo.hasSchool) {
             this.findNotice()
             if (this.$store.state.config.srvAdr == 'China') {

+ 47 - 0
TEAMModelOS/ClientApp/src/view/homepage/RcdPoster.vue

@@ -0,0 +1,47 @@
+<template>
+    <div>
+        <img class="rcd-poster-img" :src="poster" @error="imgError">
+    </div>
+</template>
+<script>
+export default {
+    props: {
+        poster: {
+            type: String,
+            default: ''
+        }
+    },
+    data() {
+        return {
+
+        }
+    },
+    methods: {
+        imgError(event) {
+            let img = event.srcElement;
+            let local = localStorage.getItem('local')
+            switch (local) {
+                case 'zh-cn':
+                    img.src = require('@/assets/image/no-poster-cn.png')
+                    break
+                case 'zh-tw':
+                    img.src = require('@/assets/image/no-poster-tw.png')
+                    break
+                case 'en':
+                    img.src = require('@/assets/image/no-poster-en.png')
+                    break
+                default:
+                    img.src = require('@/assets/image/no-poster-en.png')
+                    break
+            }
+
+            img.onerror = null; //防止闪图
+        },
+    }
+}
+</script>
+<style scoped lang="less">
+.rcd-poster-img {
+    width: 100%;
+}
+</style>

+ 6 - 2
TEAMModelOS/ClientApp/src/view/learnactivity/ExamMgt.vue

@@ -129,7 +129,8 @@
                 <!-- 评测试卷 -->
                 <ExamPaper v-show="curBarIndex == 1" :examInfo="examDetaiInfo" class="evaluation-base-info"></ExamPaper>
                 <!-- 阅卷任务 -->
-                <ExamTask v-show="curBarIndex == 2" class="evaluation-base-info"></ExamTask>
+                <!-- <ExamTask v-show="curBarIndex == 2" class="evaluation-base-info"></ExamTask> -->
+                <MarkSetting v-show="curBarIndex == 2" ref="markSetting" v-if="examDetaiInfo" :evInfo="examDetaiInfo" v-model="isSetting"></MarkSetting>
             </div>
         </Split>
         <!-- 修改评测名称 -->
@@ -167,12 +168,14 @@ import DataView from "./tabs/DataView.vue"
 import AnswerTable from "./tabs/AnswerTable.vue"
 import ExamPaper from "./tabs/ExamPaper.vue"
 import ExamTask from "./tabs/ExamTask.vue"
+import MarkSetting from "./markpaper/MarkSetting.vue"
 export default {
     components: {
-        DataView, AnswerTable, ExamPaper, ExamTask
+        DataView, AnswerTable, ExamPaper, ExamTask, MarkSetting
     },
     data() {
         return {
+            isSetting: false,
             examTargets: [],
             correctData: [],//各科错题分析数据
             paperQuInfo: [],
@@ -359,6 +362,7 @@ export default {
             })
         },
         selectBar(index) {
+			this.$EventBus.$emit('EvBarChange',index)
             this.checkScoreSave(this.handleSelectBar, index)
         },
         handleSelectBar(index) {

+ 4 - 2
TEAMModelOS/ClientApp/src/view/learnactivity/markpaper/MarkSetting.vue

@@ -17,7 +17,7 @@
             <p class="status-text">
                 <span style="font-size:16px;color:#ed4014">{{$t('learnActivity.mark.noPublish')}}</span>
             </p>
-            
+
             <span class="setting-btn" @click="isSetting = !isSetting">{{$t('learnActivity.mark.publish')}}</span>
         </div>
         <vuescroll v-show="isSetting">
@@ -1046,7 +1046,7 @@ export default {
 }
 </script>
 <style scoped lang="less">
-.task-tips{
+.task-tips {
     width: 70%;
     margin: auto;
 }
@@ -1237,5 +1237,7 @@ export default {
     float: right;
     margin-top: -42px;
     margin-right: 30px;
+    z-index: 999;
+    position: relative;
 }
 </style>

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

@@ -418,7 +418,6 @@
 }
 .record-poster-wrap{
     width: 120px;
-    background: #f3f3f3;
     height: 65px;
     background-size: contain;
     background-repeat: no-repeat;
@@ -458,4 +457,13 @@
 .heart-active{
     display: inline-block;
     color: #ed4014;
+}
+.rcd-item{
+    cursor: pointer;
+    display: flex;
+    border-bottom: 1px solid #e8eaec;
+    padding: 15px 0px;
+    &:hover{
+        background: var(--active-item-start);
+    }
 }

+ 71 - 69
TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue

@@ -154,79 +154,76 @@
                         <!-- 课堂记录 -->
                         <div v-show="tabName == 'record'" class="animated fadeIn class-record-wrap">
                             <vuescroll>
-                                <List>
-                                    <ListItem v-for="(item,index) in curRecordList" :key="index">
-                                        <ListItemMeta @click.native="toClassRecoerd(index)" style="cursor: pointer;">
-                                            <div slot="avatar" class="record-poster-wrap" :style="{backgroundImage:`url(${item.poster})`}">
-                                            </div>
-                                            <p slot="title" class="record-name" style="padding-left:10px">
-                                                {{item.name}}
-                                                <span style="float:right;margin-right:20px">
-                                                    <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')" />
-                                                    <Icon :type="isFavorite(item.id) ? 'md-heart':'md-heart-outline'" :class="['edit-ev-name',isFavorite(item.id) ? 'heart-active':'']" @click.stop="toggleFavorite(item)" :title="isFavorite(item.id) ? $t('cusMgt.unfvt') : $t('cusMgt.fvt')" />
-                                                </span>
-                                            </p>
-                                            <div slot="description" style="padding-left:10px;margin-top:10px">
-                                                <!-- 出席人数 -->
-                                                <span class="record-info">
-                                                    <span>{{$t('cusMgt.rcd.attendCount')}}:</span>
-                                                    <span class="record-info-value"> {{item.attendCount}}{{$t('unit.text7')}}</span>
-                                                </span>
-                                                <!-- 总计分 -->
-                                                <span class="record-info">
-                                                    <span>{{$t('cusMgt.rcdScore')}}</span>
-                                                    <span class="record-info-value">
-                                                        {{item.totalPoint}}
-                                                    </span>
+                                <div class="rcd-item" v-for="(item,index) in curRecordList" :key="index" @click="toClassRecoerd(index)">
+                                    <RcdPoster class="record-poster-wrap" :poster="item.poster"></RcdPoster>
+                                    <div style="flex:1">
+                                        <p class="record-name" style="padding-left:10px">
+                                            {{item.name}}
+                                            <span style="float:right;margin-right:20px">
+                                                <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')" />
+                                                <Icon :type="isFavorite(item.id) ? 'md-heart':'md-heart-outline'" :class="['edit-ev-name',isFavorite(item.id) ? 'heart-active':'']" @click.stop="toggleFavorite(item)" :title="isFavorite(item.id) ? $t('cusMgt.unfvt') : $t('cusMgt.fvt')" />
+                                            </span>
+                                        </p>
+                                        <div style="padding-left:10px;margin-top:10px">
+                                            <!-- 出席人数 -->
+                                            <span class="record-info">
+                                                <span>{{$t('cusMgt.rcd.attendCount')}}:</span>
+                                                <span class="record-info-value"> {{item.attendCount}}{{$t('unit.text7')}}</span>
+                                            </span>
+                                            <!-- 总计分 -->
+                                            <span class="record-info">
+                                                <span>{{$t('cusMgt.rcdScore')}}</span>
+                                                <span class="record-info-value">
+                                                    {{item.totalPoint}}
                                                 </span>
-                                                <!-- 作品总数 -->
-                                                <span class="record-info">
-                                                    <span>{{$t('cusMgt.rcd.colctCount')}}: </span>
-                                                    <span class="record-info-value">
-                                                        {{item.collateCount}}
-                                                    </span>
+                                            </span>
+                                            <!-- 作品总数 -->
+                                            <span class="record-info">
+                                                <span>{{$t('cusMgt.rcd.colctCount')}}: </span>
+                                                <span class="record-info-value">
+                                                    {{item.collateCount}}
                                                 </span>
-                                                <!-- 测验得分率 -->
-                                                <span class="record-info">
-                                                    <span>{{$t('cusMgt.rcd.scoreRate')}}: </span>
-                                                    <span class="record-info-value">
-                                                        {{item.examPointRate}}
-                                                    </span>
+                                            </span>
+                                            <!-- 测验得分率 -->
+                                            <span class="record-info">
+                                                <span>{{$t('cusMgt.rcd.scoreRate')}}: </span>
+                                                <span class="record-info-value">
+                                                    {{item.examPointRate}}
                                                 </span>
-                                                <!-- 互动总数 -->
-                                                <span class="record-info">
-                                                    <span>{{$t('cusMgt.rcd.interactionCount')}}: </span>
-                                                    <span class="record-info-value">
-                                                        {{item.clientInteractionCount}}
-                                                    </span>
+                                            </span>
+                                            <!-- 互动总数 -->
+                                            <span class="record-info">
+                                                <span>{{$t('cusMgt.rcd.interactionCount')}}: </span>
+                                                <span class="record-info-value">
+                                                    {{item.clientInteractionCount}}
                                                 </span>
-                                                <!-- 时长 -->
-                                                <span class="record-info">
-                                                    <span>{{$t('cusMgt.duration')}}</span>
-                                                    <span class="record-info-value">{{handleDuration(item.duration)}}</span>
+                                            </span>
+                                            <!-- 时长 -->
+                                            <span class="record-info">
+                                                <span>{{$t('cusMgt.duration')}}</span>
+                                                <span class="record-info-value">{{handleDuration(item.duration)}}</span>
+                                            </span>
+                                            <!-- 时间 -->
+                                            <span class="record-info" style="float:right">
+                                                <span>
+                                                    <Icon type="md-time" color="#70B1E7" />
                                                 </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 class="record-info-value">
+                                                    {{$jsFn.timeFormat(item.startTime)}}
                                                 </span>
-                                                <div class="record-action-wrap">
-                                                    <!-- <Icon class="action-icon" custom="iconfont icon-video" :title="$t('cusMgt.socrateMv')" @click.stop="viewVideo(item)" />
+                                            </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)">
+                                                <!-- <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)">
                                                         <Icon type="md-trash" :size="15" :title="$t('cusMgt.delRcd')"/>
                                                     </span> -->
-                                                </div>
                                             </div>
-                                        </ListItemMeta>
-                                    </ListItem>
-                                </List>
+                                        </div>
+                                    </div>
+                                </div>
                                 <EmptyData v-show="curRecordList.length == 0" :textContent="$t('cusMgt.noRecord')" :top="150"></EmptyData>
                             </vuescroll>
                         </div>
@@ -475,6 +472,7 @@
 </template>
 <script>
 import { mapGetters } from 'vuex'
+import RcdPoster from "../homepage/RcdPoster.vue"
 import PersonalPhoto from '@/components/public/personalPhoto/Index.vue'
 import StudentList from '@/components/coursemgt/StudentList.vue'
 import TeaTable from './TeaTable.vue'
@@ -482,8 +480,7 @@ import Video from '../video/Video.vue'
 import excel from '@/utils/excel.js'
 export default {
     components: {
-        StudentList, PersonalPhoto, TeaTable,
-        Video
+        StudentList, PersonalPhoto, TeaTable, RcdPoster, Video
     },
     inject: ['reload'],
     data() {
@@ -1836,7 +1833,7 @@ export default {
                     this.$router.push({
                         name: owner == 'school' ? 'manageVote' : 'personalVote',
                         params: {
-                            ac:this.acList[index]
+                            ac: this.acList[index]
                         }
                     })
                     break
@@ -1844,7 +1841,7 @@ export default {
                     this.$router.push({
                         name: owner == 'school' ? 'manageQuestionnaire' : 'personalSurvey',
                         params: {
-                            ac:this.acList[index]
+                            ac: this.acList[index]
                         }
                     })
                     break
@@ -1852,7 +1849,7 @@ export default {
                     this.$router.push({
                         name: 'manageHomeWork',
                         params: {
-                            ac:this.acList[index]
+                            ac: this.acList[index]
                         }
                     })
                     break
@@ -2153,7 +2150,7 @@ export default {
                     "school": this.$store.state.userInfo.schoolCode,
                     "DESC": "startTime",
                     "pageCount": 50,
-                    "courseId": this.courseListShow[this.curCusIndex].id //现在后端模拟数据,暂时不加课程id
+                    "courseId": this.courseListShow[this.curCusIndex].id
                 }
                 this.$api.lessonRecord.getLessonList(params).then(
                     res => {
@@ -2405,4 +2402,9 @@ export default {
         display: inline-block;
     }
 }
+.rcd-item:hover{
+    .edit-ev-name {
+        display: inline-block;
+    }
+}
 </style>

+ 1 - 1
TEAMModelOS/Controllers/Both/LessonRecordController.cs

@@ -155,7 +155,7 @@ namespace TEAMModelOS.Controllers
          */
 
         /// <summary>
-        /// 获取开课记录
+        /// 删除课堂记录
         /// </summary>
         /// <param name="request"></param>
         /// <returns></returns>

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

@@ -116,7 +116,7 @@ namespace TEAMModelOS.Controllers.Client
                 msg = new { lesson_id = $"{_lessonId}", tmdid = $"{_tmdid}", grant_types = updates, school = $"{_school}", scope = $"{_scope}" }.ToJsonString();
                 var messageChange = new ServiceBusMessage(msg);
                 messageChange.ApplicationProperties.Add("name", "LessonRecordEvent");
-               // await _dingDing.SendBotMsg($"{_option.Location},课堂id:{_lessonId} 更新事件,{msg}", GroupNames.醍摩豆服務運維群組);
+                await _dingDing.SendBotMsg($"{_option.Location},课堂id:{_lessonId} 更新事件,{msg}", GroupNames.醍摩豆服務運維群組);
                 await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChange);
                 return Ok(new { status = 200 });
             }

+ 55 - 4
TEAMModelOS/Controllers/School/SchoolController.cs

@@ -25,6 +25,7 @@ using TEAMModelOS.Filter;
 using Microsoft.AspNetCore.Authorization;
 using System.Net.Http.Headers;
 using System.Net.Http.Json;
+using HTEXLib.COMM.Helpers;
 
 namespace TEAMModelOS.Controllers
 {
@@ -1543,7 +1544,7 @@ namespace TEAMModelOS.Controllers
         public async Task<IActionResult> TeacherImportManage(JsonElement request) {
             if (!request.TryGetProperty("opt", out JsonElement _opt)) { return BadRequest(); }
             if (!request.TryGetProperty("schoolId", out JsonElement _schoolId)) { return BadRequest(); }
-            
+            long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
             TeacherImport teacherImport = null;
             List<SchoolTeacher> idsInSchool = new List<SchoolTeacher>();
             List<CoreUser> coreUsers = new List<CoreUser>();
@@ -1566,8 +1567,8 @@ namespace TEAMModelOS.Controllers
                     {
                         keys.AddRange(emails);
                     }
-                    long time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
-                    teachers.ForEach(x => { x.status = "import";x.time = time; });
+                   
+                    teachers.ForEach(x => { x.status = "import";x.time = now; });
                     if (keys.Any()) {
                         try
                         {
@@ -1594,6 +1595,7 @@ namespace TEAMModelOS.Controllers
                     }
                     if (coreUsers.Any())
                     {
+                        School schoolBase = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>($"{_schoolId}", new PartitionKey("Base"));
                         foreach (var t in teachers) {
                             if (!string.IsNullOrWhiteSpace(t.tmdid))
                             {
@@ -1601,6 +1603,7 @@ namespace TEAMModelOS.Controllers
                                 if (coreUser != null)
                                 {
                                     t.id = coreUser.id; 
+                                    t.picture=coreUser.picture;
                                 }
                             }
                             if (string.IsNullOrWhiteSpace(t.id))
@@ -1610,7 +1613,8 @@ namespace TEAMModelOS.Controllers
                                     CoreUser coreUser = coreUsers.Find(x => x.mobile.Equals(t.phone));
                                     if (coreUser != null)
                                     {
-                                        t.id = coreUser.id;
+                                        t.id = coreUser.id; 
+                                        t.picture = coreUser.picture;
                                     }
                                 }
                             }
@@ -1622,6 +1626,7 @@ namespace TEAMModelOS.Controllers
                                     if (coreUser != null)
                                     {
                                         t.id = coreUser.id;
+                                        t.picture = coreUser.picture;
                                     }
                                 }
                             }
@@ -1632,12 +1637,53 @@ namespace TEAMModelOS.Controllers
                                 {
                                     t.status = teacher.status;
                                 }
+                                else {
+                                    t.status = "invite";
+                                    teacher = new SchoolTeacher {
+                                        id = t.id,
+                                        name = t.name,
+                                        permissions = new List<string>(),
+                                        picture = t.picture,
+                                        job = null,
+                                        roles = new List<string> { "teacher" },
+                                        status = "invite",
+                                        createTime= now,
+                                        size = 0,
+                                        subjectIds= new List<string>(),
+                                        pk= "Teacher",
+                                        code=$"Teacher-{_schoolId}"
+                                    };
+                                    await  _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).CreateItemAsync(teacher, new PartitionKey (teacher.code));
+                                    Azure.Response responseTeacher = await  _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemStreamAsync(t.id, new PartitionKey("Base"));
+                                    if (responseTeacher.Status == 200)
+                                    {
+                                        Teacher teacherBase= JsonDocument.Parse(responseTeacher.Content).RootElement.Deserialize<Teacher>();
+                                        var school= teacherBase.schools?.Find(x => x.schoolId.Equals($"{_schoolId}"));
+                                        if (teacherBase.schools.IsNotEmpty())
+                                        {
+                                            if (school == null) {
+                                                teacherBase.schools.Add(new TeacherSchool { schoolId = schoolBase.id, name = schoolBase.name, picture = schoolBase.picture, areaId = schoolBase.areaId, time = now, status = "invite" });
+                                            }
+                                        }
+                                        else {
+                                            teacherBase.schools = new List<TeacherSchool> { new TeacherSchool {schoolId= schoolBase.id,name= schoolBase.name,picture= schoolBase.picture, areaId= schoolBase.areaId,time=now,status= "invite" } };
+                                        }
+                                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReplaceItemAsync(teacherBase, teacherBase.id, new PartitionKey("Base"));
+                                    }
+                                    else {
+                                        Teacher teacherBase = new Teacher { id = t.id, name = t.name, picture = t.picture, size = 2,code="Base",pk="Base", schools = new List<TeacherSchool> {
+                                            new TeacherSchool {schoolId= schoolBase.id,name= schoolBase.name,picture= schoolBase.picture, areaId= schoolBase.areaId,time=now,status= "invite" },
+                                        } };
+                                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).CreateItemAsync(teacherBase, new PartitionKey("Base"));
+                                    }
+                                }
                             }
                         }
                     }
                     teacherImport = new TeacherImport {id = $"{_schoolId}", code = "TeacherImport", pk = "TeacherImport", teachers=teachers};
                     await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).UpsertItemAsync(teacherImport, new PartitionKey("TeacherImport"));
                     break;
+                    /*
                 case "find":
                     Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemStreamAsync($"{_schoolId}", new PartitionKey("TeacherImport"));
                     if (response.Status == 200)
@@ -1692,6 +1738,7 @@ namespace TEAMModelOS.Controllers
                                     if (coreUser != null)
                                     {
                                         t.id = coreUser.id;
+                                        t.picture = coreUser.picture;
                                     }
                                     else
                                     {
@@ -1705,6 +1752,7 @@ namespace TEAMModelOS.Controllers
                                         if (coreUser != null)
                                         {
                                             t.id = coreUser.id;
+                                            t.picture = coreUser.picture;
                                         }
                                     }
                                     if (string.IsNullOrWhiteSpace(t.id))
@@ -1715,6 +1763,7 @@ namespace TEAMModelOS.Controllers
                                             if (coreUser != null)
                                             {
                                                 t.id = coreUser.id;
+                                                t.picture = coreUser.picture;
                                             }
                                         }
                                     }
@@ -1726,6 +1775,7 @@ namespace TEAMModelOS.Controllers
                                             if (coreUser != null)
                                             {
                                                 t.id = coreUser.id;
+                                                t.picture = coreUser.picture;
                                             }
                                         }
                                     }
@@ -1750,6 +1800,7 @@ namespace TEAMModelOS.Controllers
                         teacherImport= new TeacherImport { id=$"{_schoolId}",code= "TeacherImport",pk= "TeacherImport",teachers= new List<ImportTeacher>() };
                     }
                     break;
+                    */
             }
             return Ok(new { teacherImport });
         

+ 253 - 56
TEAMModelOS/Controllers/School/SchoolTeacherController.cs

@@ -67,7 +67,9 @@ namespace TEAMModelOS.Controllers
             //string status_str = (request.TryGetProperty("join_status", out JsonElement status_json)) ? status_json.ToString() : "join";
             //資料取得
             List<ScTeacher> teachers = new List<ScTeacher>();
-            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ScTeacher>(queryText: $"SELECT c.subjectIds, c.id, c.name,   c.picture ,c.status, c.job, c.createTime, ARRAY_LENGTH(c.permissions) as permissionCount,c.permissions,c.roles , c.size FROM c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school_code}") }))
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ScTeacher>
+                (queryText: $"SELECT c.subjectIds, c.id, c.name,   c.picture ,c.status, c.job, c.createTime, ARRAY_LENGTH(c.permissions) as permissionCount,c.permissions,c.roles , c.size FROM c", 
+                requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school_code}") }))
             {
                 if ($"{item.createTime}".Length > 10) {
                     item.createTime = item.createTime / 1000;
@@ -93,6 +95,141 @@ namespace TEAMModelOS.Controllers
                     });
                 }
             }
+            Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemStreamAsync($"{school_code}", new PartitionKey("TeacherImport"));
+            if (response.Status == 200) {
+                List<CoreUser> coreUsers = new List<CoreUser>();
+                TeacherImport teacherImport = JsonDocument.Parse(response.Content).RootElement.ToObject<TeacherImport>();
+                var idsIn = teacherImport.teachers.Where(x => !string.IsNullOrWhiteSpace(x.id));
+                //id是空 其他不是空的
+                var tmdidsi = teacherImport.teachers.Where(x => string.IsNullOrWhiteSpace(x.id) && !string.IsNullOrWhiteSpace(x.tmdid)).Select(z => z.tmdid);
+                var phonesi = teacherImport.teachers.Where(x => string.IsNullOrWhiteSpace(x.id) && !string.IsNullOrWhiteSpace(x.phone)).Select(z => z.phone);
+                var emailsi = teacherImport.teachers.Where(x => string.IsNullOrWhiteSpace(x.id) && !string.IsNullOrWhiteSpace(x.email)).Select(z => z.email);
+                List<string> skeys = new List<string>();
+                if (idsIn.Any()) {
+                    skeys.AddRange(idsIn.Select(x=>x.id));
+                }
+                if (tmdidsi.Any())
+                {
+                    skeys.AddRange(tmdidsi);
+                }
+                if (phonesi.Any())
+                {
+                    skeys.AddRange(phonesi);
+                }
+                if (emailsi.Any())
+                {
+                    skeys.AddRange(emailsi);
+                }
+                if (skeys.Any())
+                {
+                    try
+                    {
+                        var content = new StringContent(skeys.ToJsonString(), Encoding.UTF8, "application/json");
+                        string json = await _coreAPIHttpService.GetUserInfos(content);
+                        if (!string.IsNullOrWhiteSpace(json))
+                        {
+                            coreUsers = json.ToObject<List<CoreUser>>();
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        //await _dingDing.SendBotMsg($"{_option.Location},导入名单时,查验key信息错误{ex.Message}\n{ex.StackTrace}\n{skeys.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
+                    }
+                }
+                if (coreUsers.Any())
+                {
+                    teacherImport.teachers.ForEach(t => {
+                        if (!string.IsNullOrWhiteSpace(t.id))
+                        {
+                            CoreUser coreUser = coreUsers.Find(x => x.searchKey.Equals(t.id) || x.id.Equals(t.id));
+                            if (coreUser != null)
+                            {
+                                t.id = coreUser.id;
+                                t.picture = coreUser.picture;
+                            }
+                            else
+                            {
+                                t.id = null;
+                            }
+                        }
+                        if (string.IsNullOrWhiteSpace(t.id))
+                        {
+                            if (!string.IsNullOrWhiteSpace(t.tmdid))
+                            {
+                                CoreUser coreUser = coreUsers.Find(x => x.id.Equals(t.tmdid));
+                                if (coreUser != null)
+                                {
+                                    t.id = coreUser.id;
+                                }
+                            }
+                            if (string.IsNullOrWhiteSpace(t.id))
+                            {
+                                if (!string.IsNullOrWhiteSpace(t.phone))
+                                {
+                                    CoreUser coreUser = coreUsers.Find(x => x.mobile.Equals(t.phone));
+                                    if (coreUser != null)
+                                    {
+                                        t.id = coreUser.id;
+                                        t.picture = coreUser.picture;
+                                    }
+                                }
+                            }
+                            if (string.IsNullOrWhiteSpace(t.id))
+                            {
+                                if (!string.IsNullOrWhiteSpace(t.email))
+                                {
+                                    CoreUser coreUser = coreUsers.Find(x => x.mail.Equals(t.email));
+                                    if (coreUser != null)
+                                    {
+                                        t.id = coreUser.id;
+                                        t.picture = coreUser.picture;
+                                    }
+                                }
+                            }
+                        }
+                        if (!string.IsNullOrWhiteSpace(t.id))
+                        {
+                            var tch= teachers.Find(x => x.id.Equals(t.id));
+                            if (tch == null) {
+                                tch=  new ScTeacher
+                                {
+                                    id = t.id,
+                                    name = t.name,
+                                    picture = t.picture,
+                                    status = "import",
+                                    createTime = t.time,
+                                    permissionCount = 0,
+                                    size = 0,
+                                    permissions = new List<string>(),
+                                    roles = new List<string>(),
+                                    subjectIds = new List<string>(),
+                                    groups = new List<IdNameCode>(),
+                                };
+                                teachers.Add(tch);
+                            }
+                        }
+                        else {
+                            //teachers.Add();
+                            var tch=  new ScTeacher
+                            {
+                                id=t.id,
+                                picture=t.picture,
+                                name=t.name,
+                                status="import",
+                                createTime=t.time,
+                                permissionCount=0,
+                                size=0,
+                                permissions= new List<string>(),
+                                roles=new List<string>(),
+                                subjectIds=new List<string>(),
+                                groups= new List<IdNameCode>(),
+                            };
+                            teachers.Add(tch);
+                        }
+                    });
+                    
+                }
+            }
             return Ok(new { teachers });
         }
         public class ScTeacher
@@ -110,7 +247,7 @@ namespace TEAMModelOS.Controllers
             public List<string> subjectIds { get; set; }
             public List<IdNameCode> groups { get; set; } = new List<IdNameCode>();
 
-    }
+        }
         /// <summary>
         /// 取得某位老師的權限
         /// </summary>
@@ -395,6 +532,8 @@ namespace TEAMModelOS.Controllers
                 {
                     bizcode = "request-join";
                 }
+
+               
                 Notification notification = new Notification
                 {
                     hubName = "hita",
@@ -435,7 +574,7 @@ namespace TEAMModelOS.Controllers
                 if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
                 if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
                 if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
-
+                request.TryGetProperty("importName", out JsonElement _importName);
                 var client = _azureCosmos.GetCosmosClient();
                 //取得學校資訊
                 var schresponse = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(school_code.ToString(), new PartitionKey("Base"));
@@ -526,6 +665,38 @@ namespace TEAMModelOS.Controllers
                 if (grant_type.GetString() .Equals("join"))
                 {
                     bizcode = "request-join";
+                    if (!string.IsNullOrWhiteSpace($"{_importName}")) {
+                        Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemStreamAsync($"{school_code}", new PartitionKey("TeacherImport"));
+                        TeacherImport teacherImport = null;
+                        if (response.Status == 200)
+                        {
+                            teacherImport = JsonDocument.Parse(response.Content).RootElement.Deserialize<TeacherImport>();
+                            var tchs = teacherImport.teachers.FindAll(x => x.name.Equals($"{_importName}") && string.IsNullOrWhiteSpace(x.id));
+                            if (tchs.IsNotEmpty())
+                            {
+                                var tch = tchs[0];
+                                string ujson = null;
+                                var content = new StringContent(new List<string> { $"{id}" }.ToJsonString(), Encoding.UTF8, "application/json");
+                                ujson = await _coreAPIHttpService.GetUserInfos(content);
+                                List<CoreUser> coreUsers = new List<CoreUser>();
+                                if (!string.IsNullOrWhiteSpace(ujson))
+                                {
+                                    coreUsers = ujson.ToObject<List<CoreUser>>();
+                                }
+                                if (coreUsers.IsNotEmpty())
+                                {
+                                    tch.phone = coreUsers[0].mobile;
+                                    tch.email = coreUsers[0].mail;
+                                }
+                                tch.id = $"{teacher.id}";
+                                tch.picture = $"{teacher.picture}";
+                                tch.status = $"{grant_type}";
+                                tch.time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+                                tch.tmdid = teacher.id;
+                                await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(teacherImport, $"{school_code}", new PartitionKey("TeacherImport"));
+                            }
+                        }
+                    }
                 }
                 Notification notification = new Notification
                 {
@@ -565,66 +736,92 @@ namespace TEAMModelOS.Controllers
             {
                 var (tid, tname, _, tschool) = HttpContext.GetAuthTokenInfo();
                 if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
-                if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
-
+                request.TryGetProperty("id", out JsonElement id);
+                request.TryGetProperty("name", out JsonElement name); 
                 var client = _azureCosmos.GetCosmosClient();
                 //在老師表找出老師,刪除該學校 (老師基本資料應該要存在)
-                Teacher teacher = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<Teacher>(id.ToString(), new PartitionKey("Base"));
-                var school = teacher.schools.RemoveAll(x => x.schoolId.Equals(school_code.GetString(), StringComparison.OrdinalIgnoreCase));
-                if (!string.IsNullOrEmpty(teacher.defaultSchool) && teacher.defaultSchool.Equals($"{school_code}")) {
-                    if (teacher.schools.IsNotEmpty())
-                    {
-                        teacher.defaultSchool = teacher.schools[0].schoolId;
-                    }
-                    else {
-                        teacher.defaultSchool = null;
-                    }
-                }
-                await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, id.ToString(), new PartitionKey("Base"));
-                //移除學校表中的老師document
-                var sresponse = await client.GetContainer(Constant.TEAMModelOS, "School").DeleteItemStreamAsync(id.GetString(), new PartitionKey($"Teacher-{school_code}"));
-                //将教师移除学校,同时也移除研修名单,教研组。
-                StringBuilder queryText = new StringBuilder($"SELECT distinct value(c) FROM c where c.type='yxtrain' or  c.type='research' ");
-                await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<GroupList>(queryText: queryText.ToString(),
-                requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList-{school_code.GetString()}") }))
+                Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemStreamAsync($"{school_code}", new PartitionKey("TeacherImport"));
+                TeacherImport teacherImport = null;
+                if (response.Status == 200)
                 {
-                    bool exists = item.members.Exists(x => x.id.Equals(id.ToString()));
-                    if (exists) {
-                        item.members.RemoveAll(x => x.id.Equals(id.ToString()));
-                        await  GroupListService.UpsertList(item, _azureCosmos, _configuration, _azureServiceBus);
-                        //await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(item,item.id,new PartitionKey(item.code));
+                    teacherImport= JsonDocument.Parse(response.Content).RootElement.Deserialize<TeacherImport>();
+                }
+                if (!string.IsNullOrWhiteSpace($"{name}")  && teacherImport!= null) {
+                    //移除同名的、其中一个
+                    var ts=  teacherImport.teachers.FindAll(x => string.IsNullOrWhiteSpace(x.id)  &&  !string.IsNullOrWhiteSpace(x.name ) &&  x.name.Equals($"{name}"));
+                    if (ts.IsNotEmpty()) {
+                        teacherImport.teachers.Remove(ts.First());
+                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(teacherImport, $"{school_code}", new PartitionKey("TeacherImport"));
                     }
                 }
+                if (!string.IsNullOrWhiteSpace($"{id}")) {
 
-                //await TmdUserService.LeaveSchool(client, $"{teacher.id}",  $"{school_code}" );
-                //取得學校資訊
-                var schresponse = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(school_code.ToString(), new PartitionKey("Base"));
-                string schname = string.Empty;
-                if (schresponse.Status == 200)
-                {
-                    using var schjson = await JsonDocument.ParseAsync(schresponse.ContentStream);
-                    schjson.RootElement.TryGetProperty("name", out JsonElement jsonschname);
-                    schname = jsonschname.ToString();
-                }
-                else
-                {
-                    return BadRequest();
+                    if (teacherImport != null) {
+                        int count= teacherImport.teachers.RemoveAll(x => !string.IsNullOrWhiteSpace(x.id)  &&  x.id.Equals($"{id}"));
+                        if (count > 0) {
+                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(teacherImport, $"{school_code}", new PartitionKey("TeacherImport"));
+                        }
+                    }
+                    Teacher teacher = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<Teacher>(id.ToString(), new PartitionKey("Base"));
+                    var school = teacher.schools.RemoveAll(x => x.schoolId.Equals(school_code.GetString(), StringComparison.OrdinalIgnoreCase));
+                    if (!string.IsNullOrEmpty(teacher.defaultSchool) && teacher.defaultSchool.Equals($"{school_code}"))
+                    {
+                        if (teacher.schools.IsNotEmpty())
+                        {
+                            teacher.defaultSchool = teacher.schools[0].schoolId;
+                        }
+                        else
+                        {
+                            teacher.defaultSchool = null;
+                        }
+                    }
+                    await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, id.ToString(), new PartitionKey("Base"));
+                    //移除學校表中的老師document
+                    var sresponse = await client.GetContainer(Constant.TEAMModelOS, "School").DeleteItemStreamAsync(id.GetString(), new PartitionKey($"Teacher-{school_code}"));
+                    //将教师移除学校,同时也移除研修名单,教研组。
+                    StringBuilder queryText = new StringBuilder($"SELECT distinct value(c) FROM c where c.type='yxtrain' or  c.type='research' ");
+                    await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<GroupList>(queryText: queryText.ToString(),
+                    requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList-{school_code.GetString()}") }))
+                    {
+                        bool exists = item.members.Exists(x => x.id.Equals(id.ToString()));
+                        if (exists)
+                        {
+                            item.members.RemoveAll(x => x.id.Equals(id.ToString()));
+                            await GroupListService.UpsertList(item, _azureCosmos, _configuration, _azureServiceBus);
+                            //await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(item,item.id,new PartitionKey(item.code));
+                        }
+                    }
+
+                    //await TmdUserService.LeaveSchool(client, $"{teacher.id}",  $"{school_code}" );
+                    //取得學校資訊
+                    var schresponse = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(school_code.ToString(), new PartitionKey("Base"));
+                    string schname = string.Empty;
+                    if (schresponse.Status == 200)
+                    {
+                        using var schjson = await JsonDocument.ParseAsync(schresponse.ContentStream);
+                        schjson.RootElement.TryGetProperty("name", out JsonElement jsonschname);
+                        schname = jsonschname.ToString();
+                    }
+                    else
+                    {
+                        return BadRequest();
+                    }
+                    Notification notification = new Notification
+                    {
+                        hubName = "hita",
+                        type = "msg",
+                        from = $"ies5:{_option.Location}:private",
+                        to = new List<string> { teacher.id },
+                        label = $"remove_school",
+                        body = new { location = _option.Location, biz = "remove", tmdid = tid, tmdname = tname, schoolcode = $"{school_code}", schoolname = $"{schname}", status = 1, time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }.ToJsonString(),
+                        expires = DateTimeOffset.UtcNow.AddDays(7).ToUnixTimeSeconds()
+                    };
+                    var url = _configuration.GetValue<string>("HaBookAuth:CoreService:sendnotification");
+                    var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
+                    var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
+                    var location = _option.Location;
+                    var code = await _notificationService.SendNotification(clientID, clientSecret, location, url, notification);
                 }
-                Notification notification = new Notification
-                {
-                    hubName = "hita",
-                    type = "msg",
-                    from = $"ies5:{_option.Location}:private",
-                    to = new List<string> { teacher.id },
-                    label = $"remove_school",
-                    body = new { location = _option.Location, biz = "remove", tmdid = tid, tmdname = tname, schoolcode = $"{school_code}", schoolname = $"{schname}", status = 1, time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }.ToJsonString(),
-                    expires = DateTimeOffset.UtcNow.AddDays(7).ToUnixTimeSeconds()
-                };
-                var url = _configuration.GetValue<string>("HaBookAuth:CoreService:sendnotification");
-                var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
-                var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
-                var location = _option.Location;
-                var code = await _notificationService.SendNotification(clientID, clientSecret, location, url, notification);
                 return Ok(new { });
             }
             catch (Exception ex)

+ 35 - 0
TEAMModelOS/Controllers/Teacher/InitController.cs

@@ -28,6 +28,7 @@ using TEAMModelOS.Services;
 using Microsoft.AspNetCore.Authorization;
 using System.Diagnostics;
 using Microsoft.Extensions.Logging;
+using System.Text;
 
 namespace TEAMModelOS.Controllers
 {
@@ -819,6 +820,40 @@ namespace TEAMModelOS.Controllers
                         };
                         var response = await client.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync(st, new PartitionKey($"Teacher-{school_code}"));
                     }
+                    if ($"{grant_type}".Equals("request")) {
+                        Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemStreamAsync($"{school_code}", new PartitionKey("TeacherImport"));
+                        TeacherImport teacherImport = null;
+                        if (response.Status == 200)
+                        {
+                            teacherImport = JsonDocument.Parse(response.Content).RootElement.Deserialize<TeacherImport>();
+                            var tchs = teacherImport.teachers.FindAll(x => x.name.Equals($"{name}") && string.IsNullOrWhiteSpace(x.id));
+                            if (tchs.IsNotEmpty())
+                            {
+                                var tch  = tchs[0];
+                                string ujson = null;
+                                
+                                 
+                                var content = new StringContent(new List<string> { $"{id}"}.ToJsonString(), Encoding.UTF8, "application/json");
+                                ujson = await _coreAPIHttpService.GetUserInfos(content);
+                                List<CoreUser> coreUsers = new List<CoreUser>();
+                                if (!string.IsNullOrWhiteSpace(ujson))
+                                {
+                                    coreUsers = ujson.ToObject<List<CoreUser>>();
+                                }
+                                if (coreUsers.IsNotEmpty())
+                                {
+                                    tch.phone = coreUsers[0].mobile;
+                                    tch.email = coreUsers[0].mail;
+                                }
+                                tch.id = $"{id}";
+                                tch.picture = $"{picture}";
+                                tch.status = $"{grant_type}";
+                                tch.time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+                                tch.tmdid = id;
+                                await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(teacherImport, $"{school_code}", new PartitionKey("TeacherImport"));
+                            }
+                        }
+                    }
                     if (grant_type.ToString().Equals("join"))
                     {
                         await TmdUserService.JoinSchool(client, teacher.id, teacher.picture, teacher.name, school.schoolId, school.name);