Переглянути джерело

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

Li 3 роки тому
батько
коміт
d88c7c341f
29 змінених файлів з 1340 додано та 3323 видалено
  1. 0 66
      TEAMModelBI/ClientApp/src/assets/filter/http.js
  2. 17 2
      TEAMModelBI/ClientApp/src/view/teachermanage/areamanage.vue
  3. 242 2
      TEAMModelOS.SDK/Models/Service/Common/TeacherService.cs
  4. 1 4
      TEAMModelOS/ClientApp/src/common/VideoPlayer2.vue
  5. 38 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/cusMgt.js
  6. 38 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/cusMgt.js
  7. 151 113
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/cusMgt.js
  8. 33 22
      TEAMModelOS/ClientApp/src/view/classrecord/ClassRecord.vue
  9. 0 486
      TEAMModelOS/ClientApp/src/view/classrecord/data/1.json
  10. 0 1
      TEAMModelOS/ClientApp/src/view/classrecord/data/10.json
  11. 0 1
      TEAMModelOS/ClientApp/src/view/classrecord/data/11.json
  12. 0 604
      TEAMModelOS/ClientApp/src/view/classrecord/data/12.json
  13. 0 559
      TEAMModelOS/ClientApp/src/view/classrecord/data/2.json
  14. 0 1
      TEAMModelOS/ClientApp/src/view/classrecord/data/3.json
  15. 0 1
      TEAMModelOS/ClientApp/src/view/classrecord/data/4.json
  16. 0 494
      TEAMModelOS/ClientApp/src/view/classrecord/data/5.json
  17. 0 1
      TEAMModelOS/ClientApp/src/view/classrecord/data/6.json
  18. 0 559
      TEAMModelOS/ClientApp/src/view/classrecord/data/7.json
  19. 0 1
      TEAMModelOS/ClientApp/src/view/classrecord/data/8.json
  20. 0 1
      TEAMModelOS/ClientApp/src/view/classrecord/data/9.json
  21. 664 0
      TEAMModelOS/ClientApp/src/view/classrecord/data/Base.json
  22. 3 3
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/CorrectRate.vue
  23. 60 29
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/DataCount.vue
  24. 1 23
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/OptionCount.vue
  25. 1 1
      TEAMModelOS/ClientApp/src/view/classrecord/eventchart/Push.vue
  26. 9 4
      TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue
  27. 13 13
      TEAMModelOS/ClientApp/src/view/teachCenter/TeaResCenter.vue
  28. 67 73
      TEAMModelOS/Controllers/Teacher/InitController.cs
  29. 2 259
      TEAMModelOS/Controllers/Teacher/TeacherInitController.cs

+ 0 - 66
TEAMModelBI/ClientApp/src/assets/filter/http.js

@@ -1,66 +0,0 @@
-import axios from 'axios';
-import router from '@/router/index.js';
-axios.defaults.timeout = 1000000; //设置超时时长
-axios.defaults.baseURL = '';
-
-//http request 拦截器
-axios.interceptors.request.use(
-    config => {
-        // const token = getCookie('名称');
-        config.data = JSON.stringify(config.data);
-        config.headers['access_token'] = localStorage.getItem('accessToken')
-        config.headers['Content-Type'] = 'application/json'
-        return config;
-    },
-    error => {
-        return Promise.reject(error);
-    }
-);
-/**
- * 封装get方法
- * @param url
- * @param data
- * @returns {Promise}
- */
-
-export function fetch(url, params) {
-    let data = {};
-    data.method = url;
-    data.params = params;
-    data.lang = localStorage.getItem('local');
-    return new Promise((resolve, reject) => {
-        axios.get(url, data)
-            .then(response => {
-                resolve(response.data);
-                //  this.$Message.success('数据访问成功!');
-            })
-            .catch(error => {
-                reject(error);
-                this.$Message.error('数据访问错误!');
-            })
-    })
-}
-
-/**
- * 封装post请求
- * @param url
- * @param data
- * @returns {Promise}
- */
-
-export function post(url, params) {
-    let data = {};
-    data.method = url;
-    data.params = params;
-    data.lang = localStorage.getItem('local');
-    return new Promise((resolve, reject) => {
-        axios.post(url, params)
-            .then(response => {
-                resolve(response.data);
-                // this.$Message.success('数据访问成功!');
-            }, error => {
-                reject(error);
-                //this.$Message.error('数据访问错误!');
-            })
-    })
-}

+ 17 - 2
TEAMModelBI/ClientApp/src/view/teachermanage/areamanage.vue

@@ -168,7 +168,7 @@
                             <div><span class="general-title">地区:</span><span class="general-content">{{currentlySelect.provName}}{{currentlySelect.cityName}}</span></div>
                         </div>
                     </div>
-                    <div class="cutpastIcon">
+                    <div class="cutpastIcon" :loading="true">
                         <svg class="cutsbigIcon" aria-hidden="true">
                             <use xlink:href="#icon-xiangyou"></use>
                         </svg>
@@ -183,9 +183,16 @@
                     </div>
                 </div>
                 <template #footer>
+                    <div class="hint" v-show="loadingForm.cutAbility">
+                        <p>正在切换,请耐心等待...</p>
+                        <el-table v-loading="loadingForm.cutAbility" empty-text="   " style="width: 100%">
+                        </el-table>
+                    </div>
                     <div class="cut-footer">
                         <span class="dialog-footer">
-                            <el-button @click="CutNotarize = false">取消</el-button>
+                            <el-button @click="CutNotarize = false" v-if="loadingForm.cutAbility===false">取消</el-button>
+                            <el-button disabled v-else>取消</el-button>
+                            <!-- <el-button type="primary" @click="loadingForm.cutAbility=true" :loading="loadingForm.cutAbility">确认</el-button> -->
                             <el-button type="primary" @click="notarizeAbility(),loadingForm.cutAbility=true" :loading="loadingForm.cutAbility">确认</el-button>
                         </span>
                     </div>
@@ -843,6 +850,14 @@ export default {
 .closebtnIcon:hover {
     cursor: pointer;
 }
+.hint {
+    width: 100%;
+    text-align: center;
+}
+.hint p {
+    font-size: 16px;
+    color: #1da1f2;
+}
 </style>
 <style>
 .traitfrom .refer {

+ 242 - 2
TEAMModelOS.SDK/Models/Service/Common/TeacherService.cs

@@ -29,9 +29,249 @@ namespace TEAMModelOS.Services
 {
     public static class TeacherService
     {
+        public static async Task<TeacherInfo> TeacherInfo(AzureCosmosFactory _azureCosmos, Teacher teacher, string name, string picture, string id, AzureStorageFactory _azureStorage, Option _option)
+        {
+            List<object> schools = new List<object>();
+            List<AreaDto> areas = new List<AreaDto>();
+            string defaultschool = null;
+            //TODO 取得Teacher 個人相關數據(課程清單、虛擬教室清單、歷史紀錄清單等),學校數據另外API處理,多校切換時不同
+            var client = _azureCosmos.GetCosmosClient();
+            int total = 0;
+            int tsize = 0;
+            List<Area> areasDbs = new List<Area>();
+            List<AreaSetting> areaSettings = new List<AreaSetting>();
+            try
+            {
+                if (teacher == null)
+                {
+                    teacher = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<Teacher>(id, new PartitionKey("Base"));
+                    teacher.name = $"{name}";
+                    teacher.picture = $"{picture}";
+                }
+                else
+                {
+                    name = teacher.name;
+                    picture = teacher.picture;
+                    id = teacher.id;
+                }
+                ///教师的个人空间
+                tsize = teacher.size;
+                ///教师的总空间 包含 个人空间和学校赠送的空间累加
+                total = teacher.size;
 
-
-        
+                HashSet<string> areaIds = new HashSet<string>();
+                if (teacher.areas.IsNotEmpty())
+                {
+                    teacher.areas.ForEach(x => {
+                        areaIds.Add(x.areaId);
+                    });
+                   
+                }
+                if (teacher.schools.IsNotEmpty())
+                {
+                    teacher.schools.ForEach(x => {
+                        if (!string.IsNullOrEmpty(x.areaId))
+                        {
+                            areaIds.Add(x.areaId);
+                        }
+                    });
+                }
+                if (areaIds.Count > 0)
+                {
+                    string queryText = $"select value(c) from c where c.id in ({string.Join(",", areaIds.Select(x => $"'{x}'"))})";
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Area>(queryText: queryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base-Area") }))
+                    {
+                        areasDbs.Add(item);
+                    }
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<AreaSetting>(queryText: queryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("AreaSetting") }))
+                    {
+                        areaSettings.Add(item);
+                    }
+                }
+                if (teacher.areas.IsNotEmpty())
+                {
+                    foreach (var areat in teacher.areas)
+                    {
+                        Area area = areasDbs.Find(x => x.id.Equals(areat.areaId));
+                        AreaSetting setting = null;
+                        if (area != null)
+                        {
+                            setting = areaSettings.Find(x => x.id.Equals(areat.areaId));
+                        }
+                        int access = 0;
+                        if (setting != null && !string.IsNullOrWhiteSpace(setting.accessConfig))
+                        {
+                            access = 1;
+                        }
+                        if (setting != null)
+                        {
+                            setting.accessConfig = null;
+                        }
+                        areas.Add(new AreaDto { areaId = area.id, name = area.name, standard = area.standard, standardName = area.standardName, setting = setting, access = access });
+                    }
+                }
+                //检查是否有加入学校,如果加入学校,则当个人空间size是0G的时候,则免费获得一个G空间,但无论加入多少个学校,只能获取一次 1G的免费空间。没有加入学校则默认0G空间,除非自己购买空间
+                if (teacher.schools.IsNotEmpty())
+                {
+                    foreach (var sc in teacher.schools)
+                    {
+                        string statusNow = sc.status != null ? sc.status : "";
+                        if (statusNow.Equals("join") || statusNow.Equals("invite") || statusNow.Equals("request"))
+                        {
+                            dynamic schoolExtobj = new ExpandoObject();
+                            schoolExtobj.schoolId = sc.schoolId;
+                            schoolExtobj.name = sc.name;
+                            schoolExtobj.status = sc.status;
+                            schoolExtobj.time = sc.time;
+                            schoolExtobj.picture = sc.picture;
+                            schoolExtobj.areaId = $"{sc.areaId}";
+                            Area area = null;
+                            int access = 0;
+                            if (!string.IsNullOrEmpty($"{sc.areaId}"))
+                            {
+                                area = areasDbs.Find(x => x.id.Equals(sc.areaId));
+                                AreaSetting setting = null;
+                                if (area != null)
+                                {
+                                    setting = areaSettings.Find(x => x.id.Equals(sc.areaId));
+                                }
+                                if (setting != null && !string.IsNullOrWhiteSpace(setting.accessConfig))
+                                {
+                                    access = 1;
+                                }
+                            }
+                            if (area != null)
+                            {
+                                schoolExtobj.area = new { area.name, area.id, area.institution, area.provName, area.code, area.cityCode, area.cityName, area.standard, area.provCode, area.pk, access };
+                            }
+                            else
+                            {
+                                schoolExtobj.area = area;
+                            }
+                            var sctch = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(id, new PartitionKey($"Teacher-{sc.schoolId}"));
+                            if (sctch.Status == 200)
+                            {
+                                var jsonDoc = await JsonDocument.ParseAsync(sctch.ContentStream);
+                                SchoolTeacher schoolTeacher = jsonDoc.RootElement.ToObject<SchoolTeacher>();
+                                if (!schoolTeacher.name.Equals($"{name}") || !schoolTeacher.picture.Equals($"{picture}")) {
+                                    schoolTeacher.name = $"{name}";
+                                    schoolTeacher.picture = $"{picture}";
+                                    await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(schoolTeacher, id, new PartitionKey($"Teacher-{sc.schoolId}"));
+                                }
+                                if (jsonDoc.RootElement.TryGetProperty("size", out JsonElement _size) && _size.ValueKind.Equals(JsonValueKind.Number))
+                                {
+                                    total += _size.GetInt32();
+                                    schoolExtobj.size = _size.GetInt32();
+                                }
+                                else { schoolExtobj.size = 0; }
+                            }
+                            else
+                            {
+                                schoolExtobj.size = 0;
+                            }
+                            //if (statusNow.Equals("join"))
+                            //{
+                            //    await TmdUserService.JoinSchool(client, teacher.id, teacher.picture, teacher.name, sc.schoolId, sc.name);
+                            //}
+                            schools.Add(schoolExtobj);
+                        }
+                    }
+                    //如果包含任何申请,邀请,加入学校的记录 且个人空间未分配2G  则默认分配个人空间至2G.
+                    if (teacher.size < 2 && teacher.schools.Count > 0)
+                    {
+                        teacher.size = 2;
+                    }
+                    //如果未包含任何申请,邀请,加入学校的记录 且 个人空间没有分配1G 则默认赠送一个G 
+                    if (teacher.schools.Count == 0 && teacher.size < 1)
+                    {
+                        teacher.size = 1;
+                    }
+                }
+                if (string.IsNullOrEmpty(teacher.defaultSchool) && teacher.schools.IsNotEmpty())
+                {
+                    var tech = teacher.schools.FindAll(x => x.status.Equals("join"));
+                    if (tech.IsNotEmpty())
+                    {
+                        teacher.defaultSchool = teacher.schools[0].schoolId;
+                    }
+                }
+                await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, id, new PartitionKey("Base"));
+                //預設學校ID
+                defaultschool = teacher.defaultSchool;
+            }
+            catch (CosmosException ex)
+            {
+                if (ex.Status == 404 && teacher == null)
+                {
+                    //如果沒有,則初始化Teacher基本資料到Cosmos
+                    teacher = new Teacher
+                    {
+                        id = id,
+                        pk = "Base",
+                        code = "Base",
+                        name = name?.ToString(),
+                        picture = picture?.ToString(),
+                        //创建账号并第一次登录IES5则默认赠送1G
+                        size = 1,
+                        defaultSchool = null,
+                        schools = new List<Teacher.TeacherSchool>(),
+                    };
+                    var container = _azureStorage.GetBlobContainerClient(id);
+                    await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在
+                    teacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<Teacher>(teacher, new PartitionKey("Base"));
+                    total = teacher.size;
+                    tsize = teacher.size;
+                }
+            }
+            catch (Exception ex)
+            {
+                throw new Exception($"{ex.Message}{ex.StackTrace}");
+            }
+            //私人課程
+            List<object> courses = new List<object>();
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIterator(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{id}") }))
+            {
+                using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                {
+                    foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                    {
+                        courses.Add(obj.ToObject<object>());
+                    }
+                }
+            }
+            List<string> roles = new List<string>() { "teacher" };
+            Area areaa = null;
+            if (areas.Count > 0)
+            {
+                roles.Add("area");
+                if (!string.IsNullOrEmpty($"{areas[0]}"))
+                {
+                    areaa = areasDbs.Find(x => x.Equals(areas[0].areaId));
+                }
+            }
+            //換取AuthToken,提供給前端
+            var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id, name?.ToString(), picture?.ToString(), _option.JwtSecretKey, Website: "IES", scope: Constant.ScopeTeacher, standard: areaa != null ? areaa.standard : "", roles: roles.ToArray());
+            //取得Teacher Blob 容器位置及SAS 
+            await _azureStorage.GetBlobContainerClient(id).CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在
+            var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete);
+            var (osblob_uri, osblob_sas) = roles.Contains("area") ? _azureStorage.GetBlobContainerSAS("teammodelos", BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete) : _azureStorage.GetBlobContainerSAS("teammodelos", BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
+            return new TeacherInfo
+            {
+                auth_token = auth_token,
+                blob_uri = blob_uri,
+                blob_sas = blob_sas,
+                schools = schools,
+                defaultschool = defaultschool,
+                courses = courses,
+                total = total,
+                osblob_sas = osblob_sas,
+                osblob_uri = osblob_uri,
+                tsize = tsize,
+                areas = areas,
+                teacher = teacher
+            };
+        }
 
         public static async Task<TeacherInfo> GetTeacherInfo (AzureCosmosFactory _azureCosmos,Teacher teacher,string name,string picture,string id , AzureStorageFactory _azureStorage, Option _option)
         {

+ 1 - 4
TEAMModelOS/ClientApp/src/common/VideoPlayer2.vue

@@ -1,6 +1,6 @@
 <template>
     <div class="video-wrap">
-        <video class="" ref="videoPlayer" class="video-js"></video>
+        <video ref="videoPlayer" class="video-js"></video>
     </div>
 </template>
 
@@ -36,7 +36,6 @@ export default {
         )
         //时间切片
         let _this = this
-        console.log('mounted设置', this.markers)
         this.player.markers({
             markerStyle: {
                 width: "16px",
@@ -98,11 +97,9 @@ export default {
     watch: {
         markers: {
             handler(n, o) {
-                console.log('markers变化', n)
                 if (!this.player) return
                 console.log(JSON.stringify(this.player.markers.getMarkers()))
                 this.player.on('loadeddata', () => {
-                    console.log('视频加载完成')
                     this.player.markers.reset(n)
                     setTimeout(() => {
                         let mkDoms = document.getElementsByClassName('vjs-marker ')

+ 38 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/cusMgt.js

@@ -333,5 +333,43 @@ export default {
         parseErr: 'Failed to parse login information',
         cusLabel: 'Course:',
         toTeammodel: 'Go to TEAM Model Cloud now!>>>'
+    },
+
+    //ClassRecord.vue
+    rcd: {
+        ctime: '上課時間:',
+        rtn: '返回',
+        rcdLabel: '互動記錄',
+        enote: '電子筆記',
+        sokrateRpt: '蘇格拉底報告',
+        dataCount: '數據統計',
+        allRcd: '所有記錄',
+        qustion: '即問即答',
+        message: '飛訊',
+        image: '圖片',
+        file: '附件',
+        link: '超鏈接',
+        cw: '課件第',
+        page: '頁',
+        pageNoRcd: '此頁沒有互動數據',
+        di: '第',
+        dataErr: '獲取數據失敗',
+        noNote: '暫無電子筆記',
+        crtRate: '正確率',
+        correct: '正確',
+        wrong: '錯誤',
+        attendCount: '出席人數',
+        gCount: '小組數',
+        taskCount: '任務總數',
+        colctCount: '作品總數',
+        pushCount: '推送總數',
+        totalScore: '總計分',
+        examCount: '測驗總數',
+        quCount: '互動題數',
+        scoreRate: '測驗得分率',
+        interactionCount: '學生互動總數',
+        intUnit: '次/人',
+        optionCount: '選項分佈',
+        tPushLabel: '教師推送了一張圖:'
     }
 }

+ 38 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/cusMgt.js

@@ -333,5 +333,43 @@ export default {
         parseErr:'登录信息解析失败',
         cusLabel:'课程:',
         toTeammodel:'即刻前往醍摩豆云平台>>>'
+    },
+
+    //ClassRecord.vue
+    rcd:{
+        ctime:'上课时间:',
+        rtn:'返回',
+        rcdLabel:'互动记录',
+        enote:'电子笔记',
+        sokrateRpt:'苏格拉底报告',
+        dataCount:'数据统计',
+        allRcd:'所有记录',
+        qustion:'即问即答',
+        message:'飞讯',
+        image:'图片',
+        file:'附件',
+        link:'超链接',
+        cw:'课件第',
+        page:'页',
+        pageNoRcd:'此页没有互动数据',
+        di:'第',
+        dataErr:'获取数据失败',
+        noNote:'暂无电子笔记',
+        crtRate:'正确率',
+        correct:'正确',
+        wrong:'错误',
+        attendCount:'出席人数',
+        gCount:'小组数',
+        taskCount:'任务总数',
+        colctCount:'作品总数',
+        pushCount:'推送总数',
+        totalScore:'总计分',
+        examCount:'测验总数',
+        quCount:'互动题数',
+        scoreRate:'测验得分率',
+        interactionCount:'学生互动总数',
+        intUnit:'次/人',
+        optionCount:'选项分布',
+        tPushLabel:'教师推送了一张图:'
     }
 }

+ 151 - 113
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/cusMgt.js

@@ -7,11 +7,11 @@ export default {
     editCus: '編輯課程',
     cusName: '課程名稱',
     cNameHolder: '請輸入課程名稱',
-    cNameErr:'課程名稱不能包含空格',
+    cNameErr: '課程名稱不能包含空格',
     cusCode: '課程編碼',
     codeHolder: '請輸入課程編碼',
-    cusDesc:'課程描述',
-    descHolder:'請輸入課程描述',
+    cusDesc: '課程描述',
+    descHolder: '請輸入課程描述',
     cusPd: '課程學制',
     pdHolder: '請選擇學制',
     cusSubject: '課程學科',
@@ -95,45 +95,45 @@ export default {
     qu: '問卷',
     hw: '工作',
     sl: '自主學習',
-    acTime:'活動時間',
-    private:'個人',
-    school:'學校',     
-    noRecord:'暫無課堂記錄',
-    groupTips:'溫馨提示:當前分組為編制班分組,任課教師可前往HiTeach端自定義分組。 ',
-    noSchoolStu:'暫未加入學校無法新增學校學生,可以建立自定義名單,學生通過掃碼加入名單!',
-    qrCodeLabel:'掃碼加入名單',
-    hasDelClass:'(此班已被刪除)',
-    hasDelList:'(名單已被刪除)',
-    schoolType:'校內帳號',
-    tmIDType:'用户編號',
-    qrCodeText:'邀請碼:',
-    inviteUrl:'邀請鏈接:',
-    copyUrl:'複製鏈接',
-    createTips1:'溫馨提示:您(已加入學校)可以挑選學校學生加入課程或讓學生通過輸入課程邀請碼、掃描課程二維碼、課程鏈接方式主動加入課程。 ',
-    createTips2:'溫馨提示:您(暫未加入學校)可讓學生通過輸入課程邀請碼、掃描課程二維碼、課程鏈接方式主動加入課程。 ',
-    renameListTitle:'修改名稱',
-    selectListTips:'請選擇名單',
-    alreadyExist:'已在課程名單',
-    listAPIErr:'名單列表獲取失敗',
-    justRmList:'僅從課程名單移除(沒有真正刪除,名單可繼續使用)',
-    permDelList:'永久刪除 (如果其他課程在使用名單也會關聯刪除)',
-    listSaveOk:'保存/更新成功',
-    listSaveErr:'保存/更新失敗',
-    listExp:'名單異常無法創建二維碼',
-    getListErr:'獲取名單數據失敗',
-    hasGraduate:'已畢業',
-    notStart:'未到入學時間',
-    noNote:'暫無電子筆記',
-    duration:'時長:',
-    noData:'暫無數據',
-    rcdErr:'查詢課堂記錄失敗',
+    acTime: '活動時間',
+    private: '個人',
+    school: '學校',
+    noRecord: '暫無課堂記錄',
+    groupTips: '溫馨提示:當前分組為編制班分組,任課教師可前往HiTeach端自定義分組。 ',
+    noSchoolStu: '暫未加入學校無法新增學校學生,可以建立自定義名單,學生通過掃碼加入名單!',
+    qrCodeLabel: '掃碼加入名單',
+    hasDelClass: '(此班已被刪除)',
+    hasDelList: '(名單已被刪除)',
+    schoolType: '校內帳號',
+    tmIDType: '用户編號',
+    qrCodeText: '邀請碼:',
+    inviteUrl: '邀請鏈接:',
+    copyUrl: '複製鏈接',
+    createTips1: '溫馨提示:您(已加入學校)可以挑選學校學生加入課程或讓學生通過輸入課程邀請碼、掃描課程二維碼、課程鏈接方式主動加入課程。 ',
+    createTips2: '溫馨提示:您(暫未加入學校)可讓學生通過輸入課程邀請碼、掃描課程二維碼、課程鏈接方式主動加入課程。 ',
+    renameListTitle: '修改名稱',
+    selectListTips: '請選擇名單',
+    alreadyExist: '已在課程名單',
+    listAPIErr: '名單列表獲取失敗',
+    justRmList: '僅從課程名單移除(沒有真正刪除,名單可繼續使用)',
+    permDelList: '永久刪除 (如果其他課程在使用名單也會關聯刪除)',
+    listSaveOk: '保存/更新成功',
+    listSaveErr: '保存/更新失敗',
+    listExp: '名單異常無法創建二維碼',
+    getListErr: '獲取名單數據失敗',
+    hasGraduate: '已畢業',
+    notStart: '未到入學時間',
+    noNote: '暫無電子筆記',
+    duration: '時長:',
+    noData: '暫無數據',
+    rcdErr: '查詢課堂記錄失敗',
     delRcd: '删除',
     delRcdTitle: '删除課堂記錄',
     delRcdContent: '課堂記錄數據删除後將無法找回,確認删除當前課堂記錄嗎?',
-    
+
     //ManageClass.vue
-    stuMgt:'學生管理',
-    classNotice:'班級公告',
+    stuMgt: '學生管理',
+    classNotice: '班級公告',
     classLabel: '班級:',
     stuCount: '學生人數:',
     autoGroup: '自動分組',
@@ -142,14 +142,14 @@ export default {
     viewport2: '清單視圖',
     noStu: '暫無學生',
     resetPw: '重置密碼',
-    resetPwContent1:'確認重置',
-    resetPwContent2:'的密碼',
-    resetPwContent3:'確認批量重置',
-    resetPwContent4:'個學生的密碼',
-    resetPwOk:'重置成功',
+    resetPwContent1: '確認重置',
+    resetPwContent2: '的密碼',
+    resetPwContent3: '確認批量重置',
+    resetPwContent4: '個學生的密碼',
+    resetPwOk: '重置成功',
     noMgtClass1: '暫未加入學校',
     noMgtClass2: '學校暫未設置您為班導師',
-    toJoin:'前往申請加入學校',
+    toJoin: '前往申請加入學校',
     groupNameHolder: '請設定組名',
     edtiGroupName: '修改組名',
     addGroup: '新增組別',
@@ -163,27 +163,27 @@ export default {
     action: '操作',
     atLeast: '至少保留一組',
     checkName: '請先輸入組名再建立組別',
-    groupNameRepeat:'組名重複',
+    groupNameRepeat: '組名重複',
     noStuTips: '暫無學生可以進行分組',
     groupCount: '分組數量最少為1',
     groupTypeTips: '請設定分組管道',
     groupUnit: '組',
     stuNameList: '學生名單',
     saveGroup: '儲存分組',
-    setAvatar:'設置頭像',
-    stuNameLabel:'姓名:',
-    reupload:'重新上傳',
-    uploadAvatar:'上傳頭像',
-    uploadTips:'請上傳頭像',
-    setOk:'設置成功',
-    setErr:'設置失敗',
-    uploadErr:'頭像上傳失敗',
-    deleteGroup:'刪除分組',
-    delGroupContent:'確認刪除',
-    setAvatarLabel:'設置頭像',
-    classStuErr:'獲取班級名單失敗',
-    unGroup:'未分組學生',
-    setGroupName:'請設置組名',
+    setAvatar: '設置頭像',
+    stuNameLabel: '姓名:',
+    reupload: '重新上傳',
+    uploadAvatar: '上傳頭像',
+    uploadTips: '請上傳頭像',
+    setOk: '設置成功',
+    setErr: '設置失敗',
+    uploadErr: '頭像上傳失敗',
+    deleteGroup: '刪除分組',
+    delGroupContent: '確認刪除',
+    setAvatarLabel: '設置頭像',
+    classStuErr: '獲取班級名單失敗',
+    unGroup: '未分組學生',
+    setGroupName: '請設置組名',
 
     //NewCusMgt.vue
     schdTable: '課表模式',
@@ -191,18 +191,18 @@ export default {
     stuListMgt: '自定義名單',
     teaLabel: '教師',
     noTeacher: '暫無授課教師',
-    noCourse:'當前學段暫未創建課程',
+    noCourse: '當前學段暫未創建課程',
     cusNameList: '課程名單',
     cusTime: '課程時段',
     saveLabel: '儲存變更',
     addStuList: '新增名單',
-    addListType:'方式',
-    addListType1:'新建名單',
-    addListType2:'選擇已有名單',
-    listLabel:'名單',
+    addListType: '方式',
+    addListType1: '新建名單',
+    addListType2: '選擇已有名單',
+    listLabel: '名單',
     removeList: '移除名單',
-    addrLabel:'上課教室:',
-    nameLabel:'班級名單:',
+    addrLabel: '上課教室:',
+    nameLabel: '班級名單:',
     defaultList: '預設名單',
     noSet: '未設定',
     defaultTips: '預設名單為教室對應的名單,否則需要指定自定義名單。',
@@ -212,15 +212,15 @@ export default {
     notime1: '暫未設定時段,請先',
     notime2: '設定時段',
     notime3: '再安排上課時段。',
-    listType1:'編制班',
-    listType2:'選課班',
+    listType1: '編制班',
+    listType2: '選課班',
     confirmAdd: '確認新增',
     cancelAdd: '取消新增',
     createList: '新建選課班',
     name: '名稱:',
     nameHolder: '請輸入名單名稱…',
-    nameRepeat:'選課班名稱重複',
-    pdHolder:'請設置學段',
+    nameRepeat: '選課班名稱重複',
+    pdHolder: '請設置學段',
     timeSetTitle: '時段設定',
     job: '職位',
     teaName: '姓名',
@@ -241,28 +241,28 @@ export default {
     remvTeaTitle: '移除授課老師',
     remvTeaContent: '是否確認移除',
     gradeLabel: '年級',
-    cusNoRepeat:'課程編碼重複',
-    cusNameRepeat:'課程名稱重複',
-    noClassInfo:'暫未找到班級資訊',
-    noRoomInfo:'暫未找到教室資訊',
+    cusNoRepeat: '課程編碼重複',
+    cusNameRepeat: '課程名稱重複',
+    noClassInfo: '暫未找到班級資訊',
+    noRoomInfo: '暫未找到教室資訊',
 
     //MgtStuList.vue
     nameList: '名單',
     remvStu: '移除學生',
-    editStu:'設置IRS',
-    goBack:'返回上級',
-    delListTitle:'刪除自定義名單',
-    notSet:'未設置',
-    irsTips1:'1、按照名單順序快速設置IRS號碼;',
-    irsTips2:'2、如果學生已經設置IRS號碼將被重置。 ',
-    irsRepeat:'IRS號碼重複',
-    remvContent1:'是否確認從名單移除',
-    remvContent2:'位學生',
-    okText:'是',
-    cancelText:'否',
-    remvTips:'請選擇需要移除的學生',
-    findListInfoErr:'查詢選課班資訊失敗',
-    findListErr:'查詢選課班列表失敗',
+    editStu: '設置IRS',
+    goBack: '返回上級',
+    delListTitle: '刪除自定義名單',
+    notSet: '未設置',
+    irsTips1: '1、按照名單順序快速設置IRS號碼;',
+    irsTips2: '2、如果學生已經設置IRS號碼將被重置。 ',
+    irsRepeat: 'IRS號碼重複',
+    remvContent1: '是否確認從名單移除',
+    remvContent2: '位學生',
+    okText: '是',
+    cancelText: '否',
+    remvTips: '請選擇需要移除的學生',
+    findListInfoErr: '查詢選課班資訊失敗',
+    findListErr: '查詢選課班列表失敗',
 
     //TeaTable.vue
     am: '上午',
@@ -293,8 +293,8 @@ export default {
     cusTable: '課程表',
     importLabel: '匯入課表',
     cusMode: '課程模式',
-    roomLabel:'教室',
-    roomType:'教室類型:',
+    roomLabel: '教室',
+    roomType: '教室類型:',
 
     //ClassTable.vue
     noAddTea: '當前課程未新增授課老師',
@@ -310,28 +310,66 @@ export default {
     fri: '星期五',
     sat: '星期六',
     sun: '星期日',
-    nameListType:'類型',
-    scClass:'學校班級',
-    customNameList:'自定義名單',
-    teaTimeWraning:'該教師此時段已有課程安排',
-    classTimeWarning:'該班級此時段已有課程安排',
-    
+    nameListType: '類型',
+    scClass: '學校班級',
+    customNameList: '自定義名單',
+    teaTimeWraning: '該教師此時段已有課程安排',
+    classTimeWarning: '該班級此時段已有課程安排',
+
     // JoinClass.vue
-    join:{
-        title:'加入課程名單',
-        errorInfo:'數據錯誤,請重新掃碼',
-        teacherLabel:'教師:',
-        listLabel:'名單:',
-        joinBtn:'立即加入',
-        errorTile:'訊息錯誤',
-        errorContent:'課程名單讀取失敗,請重新掃碼加入! ',
-        joinOk:'加入成功',
-        joinErr:'加入失敗',
-        getListErr:'獲取名單訊息失敗',
-        hasJoin:'課程加入成功! ',
-        getErr:'用戶訊息讀取失敗',
-        parseErr:'登入訊息讀取失敗',
-        cusLabel:'課程:',
-        toTeammodel:'即刻前往醍摩豆雲平台>>>'
-    }  
+    join: {
+        title: '加入課程名單',
+        errorInfo: '數據錯誤,請重新掃碼',
+        teacherLabel: '教師:',
+        listLabel: '名單:',
+        joinBtn: '立即加入',
+        errorTile: '訊息錯誤',
+        errorContent: '課程名單讀取失敗,請重新掃碼加入! ',
+        joinOk: '加入成功',
+        joinErr: '加入失敗',
+        getListErr: '獲取名單訊息失敗',
+        hasJoin: '課程加入成功! ',
+        getErr: '用戶訊息讀取失敗',
+        parseErr: '登入訊息讀取失敗',
+        cusLabel: '課程:',
+        toTeammodel: '即刻前往醍摩豆雲平台>>>'
+    },
+
+    //ClassRecord.vue
+    rcd: {
+        ctime: '上課時間:',
+        rtn: '返回',
+        rcdLabel: '互動記錄',
+        enote: '電子筆記',
+        sokrateRpt: '蘇格拉底報告',
+        dataCount: '數據統計',
+        allRcd: '所有記錄',
+        qustion: '即問即答',
+        message: '飛訊',
+        image: '圖片',
+        file: '附件',
+        link: '超鏈接',
+        cw: '課件第',
+        page: '頁',
+        pageNoRcd: '此頁沒有互動數據',
+        di: '第',
+        dataErr: '獲取數據失敗',
+        noNote: '暫無電子筆記',
+        crtRate: '正確率',
+        correct: '正確',
+        wrong: '錯誤',
+        attendCount: '出席人數',
+        gCount: '小組數',
+        taskCount: '任務總數',
+        colctCount: '作品總數',
+        pushCount: '推送總數',
+        totalScore: '總計分',
+        examCount: '測驗總數',
+        quCount: '互動題數',
+        scoreRate: '測驗得分率',
+        interactionCount: '學生互動總數',
+        intUnit: '次/人',
+        optionCount: '選項分佈',
+        tPushLabel: '教師推送了一張圖:'
+    }
 }

+ 33 - 22
TEAMModelOS/ClientApp/src/view/classrecord/ClassRecord.vue

@@ -9,7 +9,7 @@
                     </span>
                     <div style="display:inline-block;margin-left:30px">
                         <span class="label-text">
-                            上课时间:
+                            {{$t('cusMgt.rcd.ctime')}}
                         </span>
                         <span class="label-value">
                             {{$jsFn.timeFormat(recordInfo.startTime)}}
@@ -17,7 +17,7 @@
                     </div>
                     <Button type="info" size="small" @click="goBack" style="float:right">
                         <Icon custom="iconfont icon-arrow" size="12" style="vertical-align: baseline;" />
-                        返回
+                        {{$t('cusMgt.rcd.rtn')}}
                     </Button>
                 </div>
                 <!--上课内容-->
@@ -38,26 +38,34 @@
                 <div class="cus-data-wrap">
                     <!--课堂互动记录-->
                     <h2 class="content-title">
-                        互动记录
-                        <span class="e-note-tag" @click="viewENote">电子笔记</span>
-                        <span class="e-note-tag" @click="viewReport">苏格拉底报告</span>
-                        <span class="e-note-tag" @click="viewData">数据统计</span>
+                        {{$t('cusMgt.rcd.rcdLabel')}}
+                        <span class="e-note-tag" @click="viewENote">
+                            {{$t('cusMgt.rcd.rcdLabel')}}
+                        </span>
+                        <span class="e-note-tag" @click="viewReport">
+                            {{$t('cusMgt.rcd.sokrateRpt')}}
+                        </span>
+                        <span class="e-note-tag" @click="viewData">
+                            {{$t('cusMgt.rcd.dataCount')}}
+                        </span>
                     </h2>
                     <div class="interaction-record-wrap">
                         <div class="interaction-type-wrap">
                             <span style="border-bottom:5px solid #efefef;display:block; margin-bottom:10px;padding-top:5px;">
-                                <Icon size="22" :class="typeIndex == 'all' ? 'type-icon-active type-icon':'type-icon'" custom="iconfont icon-basic-setting" @click="filterType('all')" title="所有记录" />
+                                <Icon size="22" :class="typeIndex == 'all' ? 'type-icon-active type-icon':'type-icon'" custom="iconfont icon-basic-setting" @click="filterType('all')" :title="$t('cusMgt.rcd.allRcd')" />
                             </span>
-                            <span :class="typeIndex == 'irs' ? 'type-icon-active type-icon':'type-icon'" style="font-size:32px;line-height:30px;" @click="filterType('irs')" title="即问即答">Q</span>
-                            <Icon :class="typeIndex == 'msg' ? 'type-icon-active type-icon':'type-icon'" custom="iconfont icon-message" style="font-size:24px;" @click="filterType('msg')" title="飞讯" />
-                            <Icon :class="typeIndex == 'img' ? 'type-icon-active type-icon':'type-icon'" type="ios-image" @click="filterType('img')" title="图片" />
-                            <Icon :class="typeIndex == 'file' ? 'type-icon-active type-icon':'type-icon'" type="md-document" @click="filterType('file')" title="附件" />
-                            <Icon :class="typeIndex == 'link' ? 'type-icon-active type-icon':'type-icon'" type="ios-link" @click="filterType('link')" title="超链接" />
+                            <span :class="typeIndex == 'irs' ? 'type-icon-active type-icon':'type-icon'" style="font-size:32px;line-height:30px;" @click="filterType('irs')" :title="$t('cusMgt.rcd.qustion')">Q</span>
+                            <Icon :class="typeIndex == 'msg' ? 'type-icon-active type-icon':'type-icon'" custom="iconfont icon-message" style="font-size:24px;" @click="filterType('msg')" :title="$t('cusMgt.rcd.message')" />
+                            <Icon :class="typeIndex == 'img' ? 'type-icon-active type-icon':'type-icon'" type="ios-image" @click="filterType('img')" :title="$t('cusMgt.rcd.image')" />
+                            <Icon :class="typeIndex == 'file' ? 'type-icon-active type-icon':'type-icon'" type="md-document" @click="filterType('file')" :title="$t('cusMgt.rcd.file')" />
+                            <Icon :class="typeIndex == 'link' ? 'type-icon-active type-icon':'type-icon'" type="ios-link" @click="filterType('link')" :title="$t('cusMgt.rcd.link')" />
                         </div>
                         <vuescroll ref="datawrap">
                             <div class="page-item" :key="index" v-for="(item,index) in pageList" :id="'page'+(item.page)">
                                 <div class="page-info-wrap">
-                                    <span class="page-tag" @click="toVideo(index+1,$event)" :ref="'page'+(index+1)">课件第{{item.page}}页</span>
+                                    <span class="page-tag" @click="toVideo(index+1,$event)" :ref="'page'+(index+1)">
+                                        {{`${$t('cusMgt.rcd.cw')}${item.page}${$t('cusMgt.rcd.page')}`}}
+                                    </span>
                                     <!-- 课件缩略图 -->
                                     <!-- <img class="page-mini-img" @click="openViewer(item.img)" :src="item.img" /> -->
                                     <Timeline style="margin-top:10px;margin-left:-5px">
@@ -68,7 +76,7 @@
                                     </Timeline>
                                 </div>
                                 <div class="record-data-wrap">
-                                    <EmptyData v-if="!item.pageData.length" textContent="此页没有互动数据"></EmptyData>
+                                    <EmptyData v-if="!item.pageData.length" :textContent="$t('cusMgt.rcd.pageNoRcd')"></EmptyData>
                                     <template v-else>
                                         <!-- 互动数据 -->
                                         <div>
@@ -95,7 +103,7 @@
         </div>
         <!--返回顶部-->
         <BackToTop @on-to-top="handleToTop"></BackToTop>
-        <Modal v-model="dataStatus" title="数据统计" :width="800" footer-hide>
+        <Modal v-model="dataStatus" :title="$t('cusMgt.rcd.dataCount')" :width="800" footer-hide>
             <DataCount></DataCount>
         </Modal>
     </div>
@@ -149,7 +157,7 @@ export default {
                 //fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
                 sources: [],
                 poster: '',
-                notSupportedMessage: '此视频暂无法播放,请稍后再试' //允许覆盖Video.js无法播放媒体源时显示的默认信息。
+                // notSupportedMessage: '此视频暂无法播放,请稍后再试' //允许覆盖Video.js无法播放媒体源时显示的默认信息。
             },
             eventMap: {
                 SPQStrt: '课中评测',
@@ -208,20 +216,21 @@ export default {
                     this.markers = pageEvent.map((item, index) => {
                         return {
                             time: item.Time,
-                            text: `第${index + 1}页`,
+                            text: `${this.$t('cusMgt.rcd.di')}${index + 1}${this.$t('cusMgt.rcd.page')}`,
                             page: index + 1
                         }
                     })
                 },
                 err => {
-                    this.$Message.error('获取数据失败')
+                    this.$Message.error(this.$t('cusMgt.rcd.dataErr'))
                 }
             )
         },
         //查看苏格拉底报告
         viewReport() {
             this.$router.push({
-                name: 'teachCenter'
+                name: 'teachCenter',
+                query: { id: this.recordInfo.id, name: this.recordInfo.name }
             })
         },
         //查看数据统计
@@ -233,7 +242,7 @@ export default {
             if (this.recordInfo.eNote) {
                 window.open('/web/viewer.html?file=' + encodeURIComponent(this.recordInfo.eNote))
             } else {
-                this.$Message.warning('暂无电子笔记')
+                this.$Message.warning(this.$t('cusMgt.rcd.noNote'))
             }
         },
         //点击视频切片
@@ -313,11 +322,12 @@ export default {
         }
     },
     created() {
-        this.recordInfo = this.$route.params.record
+        this.recordInfo = this.$route.params.record || (sessionStorage.getItem('record') ? JSON.parse(sessionStorage.getItem('record')) : undefined)
+        console.log(this.recordInfo)
         if (!this.recordInfo) {
-            // this.$Message.warning('没有课堂记录数据')
             this.$router.go(-1)
         } else {
+            sessionStorage.setItem('record', JSON.stringify(this.recordInfo))
             //对接Blob数据
             let userProfile = this.$store.state.user.userProfile
             this.videoUrl = `${userProfile.blob_uri}/records/${this.recordInfo.id}/Record/CourseRecord.mp4?${userProfile.blob_sas}`
@@ -326,6 +336,7 @@ export default {
             this.playerOptions.sources.push({
                 src: this.videoUrl
             })
+
             this.getPageList()
         }
     }

+ 0 - 486
TEAMModelOS/ClientApp/src/view/classrecord/data/1.json

@@ -1,486 +0,0 @@
-{
-    "item": [
-        {
-            "shapeType": "ellipse",
-            "paragraph": [
-                {
-                    "style": {
-                        "vert": "v-mid",
-                        "hori": "h-mid",
-                        "writing": "horz"
-                    },
-                    "texts": [
-                        {
-                            "content": "Shape with image background",
-                            "isbr": false,
-                            "style": {
-                                "color": "FFFF00",
-                                "size": 20.0,
-                                "family": "inherit",
-                                "weight": "initial",
-                                "style": "normal",
-                                "decoration": "initial",
-                                "vertAlign": "baseline",
-                                "align": "initial",
-                                "shadow": "none"
-                            }
-                        }
-                    ]
-                }
-            ],
-            "fill": {
-                "type": 3,
-                "image": "https://teammodelostest.blob.core.chinacloudapi.cn/teammodelos/pptx/223c84bdbc0075e8fa418522644345ef8577ec4b/imgs/4fd5bb0f9d4afa6ace354fec0052c6d7b39294ac.jpeg",
-                "rot": 0.0,
-                "grad": []
-            },
-            "border": {
-                "width": 1.0,
-                "color": "117EA7",
-                "type": "solid",
-                "stroke": "0"
-            },
-            "type": "Sp",
-            "position": {
-                "rot": 0.0,
-                "flipH": 0,
-                "flipV": 0,
-                "x": 300.0,
-                "y": 3.1297,
-                "cx": 312.5217,
-                "cy": 210.8337
-            },
-            "index": 3,
-            "svg": {
-                "id": "3",
-                "svgShape": [
-                    {
-                        "rx": "156.26085",
-                        "ry": "105.41685",
-                        "cx": "156.26085",
-                        "cy": "105.41685",
-                        "type": "ellipse"
-                    }
-                ]
-            },
-            "uid": "4cd59085897f46c19f03dc676eefac34"
-        },
-        {
-            "shapeType": "rect",
-            "paragraph": [
-                {
-                    "style": {
-                        "vert": "v-mid",
-                        "hori": "h-right",
-                        "writing": "horz"
-                    },
-                    "texts": [
-                        {
-                            "content": "Introduction to",
-                            "isbr": false,
-                            "style": {
-                                "color": "FFFF00",
-                                "size": 54.0,
-                                "family": "Calibri",
-                                "weight": "bold",
-                                "style": "normal",
-                                "decoration": "underline",
-                                "vertAlign": "baseline",
-                                "align": "initial",
-                                "shadow": "none"
-                            }
-                        }
-                    ]
-                }
-            ],
-            "fill": {
-                "type": 1,
-                "color": "1CADE4",
-                "rot": 0.0,
-                "grad": []
-            },
-            "border": {
-                "width": 1.0,
-                "color": "FFFFFF",
-                "type": "solid",
-                "stroke": "0"
-            },
-            "type": "Sp",
-            "position": {
-                "rot": 0.0,
-                "flipH": 0,
-                "flipV": 0,
-                "x": 165.1793,
-                "y": 142.3244,
-                "cx": 600.0,
-                "cy": 96.9375
-            },
-            "index": 4,
-            "svg": {
-                "id": "4",
-                "svgShape": [
-                    {
-                        "x": "0",
-                        "y": "0",
-                        "width": "600",
-                        "height": "96.9375",
-                        "type": "rect"
-                    }
-                ]
-            },
-            "uid": "91424bee5f004caaab8c0842a9c11663"
-        },
-        {
-            "mediaType": "image",
-            "image": "https://teammodelostest.blob.core.chinacloudapi.cn/teammodelos/pptx/223c84bdbc0075e8fa418522644345ef8577ec4b/imgs/435f132b0c9fc2ff49d90b782da885717d02f5ac.png",
-            "fill": {
-                "type": 0,
-                "rot": 0.0,
-                "grad": []
-            },
-            "border": {
-                "width": 0.0,
-                "type": "solid",
-                "stroke": "0"
-            },
-            "type": "Media",
-            "position": {
-                "rot": 0.0,
-                "flipH": 0,
-                "flipV": 0,
-                "x": 174.2006,
-                "y": 213.9634,
-                "cx": 564.1202,
-                "cy": 225.1638
-            },
-            "index": 5,
-            "uid": "8cf33bdcca8445d7bc8bbbab13c24de1"
-        },
-        {
-            "shapeType": "pie",
-            "paragraph": [
-                {
-                    "style": {
-                        "vert": "v-mid",
-                        "hori": "h-mid",
-                        "writing": "horz"
-                    },
-                    "texts": [
-                        {
-                            "content": "Pie",
-                            "isbr": false,
-                            "style": {
-                                "color": "0000FF",
-                                "size": 0.0,
-                                "family": "inherit",
-                                "weight": "initial",
-                                "style": "normal",
-                                "decoration": "initial",
-                                "vertAlign": "baseline",
-                                "align": "initial",
-                                "shadow": "none"
-                            }
-                        }
-                    ]
-                }
-            ],
-            "fill": {
-                "type": 1,
-                "color": "1CADE4",
-                "rot": 0.0,
-                "grad": []
-            },
-            "border": {
-                "width": 1.0,
-                "color": "117EA7",
-                "type": "solid",
-                "stroke": "0"
-            },
-            "type": "Sp",
-            "position": {
-                "rot": 0.0,
-                "flipH": 0,
-                "flipV": 0,
-                "x": 688.6956,
-                "y": 448.4924,
-                "cx": 257.2173,
-                "cy": 241.7685
-            },
-            "index": 6,
-            "svg": {
-                "id": "6",
-                "svgShape": [
-                    {
-                        "d": "M120.8842,120.8842 L120.8842,0 A120.8842,120.8842 0 1,1 0.012088419999997768,119.39732434000001 z",
-                        "type": "path",
-                        "transform": "rotate(-5.957783333333339, 120.8842, 120.8842)"
-                    }
-                ]
-            },
-            "uid": "9a8bc75a520e4ad5a95baa455041e408"
-        },
-        {
-            "shapeType": "arc",
-            "paragraph": [
-                {
-                    "style": {
-                        "vert": "v-mid",
-                        "hori": "h-mid",
-                        "writing": "horz"
-                    },
-                    "texts": [
-                        {
-                            "content": "arc2",
-                            "isbr": false,
-                            "style": {
-                                "color": "FF0000",
-                                "size": 0.0,
-                                "family": "inherit",
-                                "weight": "initial",
-                                "style": "normal",
-                                "decoration": "initial",
-                                "vertAlign": "baseline",
-                                "align": "initial",
-                                "shadow": "none"
-                            }
-                        }
-                    ]
-                }
-            ],
-            "border": {
-                "width": 4.5,
-                "color": "2683C6"
-            },
-            "type": "Sp",
-            "position": {
-                "rot": 0.0,
-                "flipH": 0,
-                "flipV": 0,
-                "x": 519.1305,
-                "y": 475.7682,
-                "cx": 148.6956,
-                "cy": 206.6087
-            },
-            "index": 7,
-            "svg": {
-                "id": "7",
-                "svgShape": [
-                    {
-                        "d": "M103.3044,0 A74.3478,103.3044 0 1,1 60.08789196000001,1.921461839999992",
-                        "type": "path",
-                        "transform": "rotate(360, 103.3044, 103.3044)"
-                    }
-                ]
-            },
-            "uid": "578c6470af3441e6b9b54d5914d7fb68"
-        },
-        {
-            "shapeType": "custom",
-            "paragraph": [
-                {
-                    "style": {
-                        "vert": "v-mid",
-                        "hori": "h-mid",
-                        "writing": "horz"
-                    },
-                    "texts": []
-                }
-            ],
-            "border": {
-                "width": 1.0,
-                "color": "117EA7",
-                "type": "solid",
-                "stroke": "0"
-            },
-            "type": "Sp",
-            "position": {
-                "rot": 0.0,
-                "flipH": 0,
-                "flipV": 0,
-                "x": 792.0,
-                "y": 112.6955,
-                "cx": 134.5271,
-                "cy": 230.793
-            },
-            "index": 8,
-            "svg": {
-                "id": "8",
-                "svgShape": [
-                    {
-                        "d": "M0,0 C0.6522,87.1304 1.3044,174.2609 20.8696,180 C40.4349,185.7391 98.6087,44.7826 117.3913,34.4348 C136.1739,24.0869 135.5652,85.4783 133.5652,117.9131 C131.5652,150.3478 113.826,217.2174 105.3913,229.0435 C96.9565,240.8695 82.9565,188.8696 82.9565,188.8696 L82.9565,188.8696",
-                        "type": "path"
-                    }
-                ]
-            },
-            "uid": "2a54608fcf244d5882700ef39e72b85c"
-        },
-        {
-            "shapeType": "arc",
-            "paragraph": [
-                {
-                    "style": {
-                        "vert": "v-mid",
-                        "hori": "h-mid",
-                        "writing": "horz"
-                    },
-                    "texts": [
-                        {
-                            "content": "arc1",
-                            "isbr": false,
-                            "style": {
-                                "color": "000000",
-                                "size": 18.0,
-                                "family": "inherit",
-                                "weight": "initial",
-                                "style": "normal",
-                                "decoration": "initial",
-                                "vertAlign": "baseline",
-                                "align": "initial",
-                                "shadow": "none"
-                            }
-                        }
-                    ]
-                }
-            ],
-            "fill": {
-                "type": 1,
-                "color": "1CADE4",
-                "rot": 0.0,
-                "grad": []
-            },
-            "border": {
-                "width": 1.0,
-                "color": "1CADE4",
-                "type": "solid",
-                "stroke": "0"
-            },
-            "type": "Sp",
-            "position": {
-                "rot": 0.0,
-                "flipH": 0,
-                "flipV": 0,
-                "x": 66.1852,
-                "y": 257.7693,
-                "cx": 94.4349,
-                "cy": 105.4169
-            },
-            "index": 9,
-            "svg": {
-                "id": "9",
-                "svgShape": [
-                    {
-                        "d": "M52.7084,0 A47.2174,52.7084 0 1,1 21.753056179999998,97.09414364",
-                        "type": "path",
-                        "transform": "rotate(360, 52.7084, 52.7084)"
-                    }
-                ]
-            },
-            "uid": "f50a5c13d9ba458f844c6a762dbdd162"
-        },
-        {
-            "cxnType": "curvedConnector3",
-            "border": {
-                "width": 0.75,
-                "color": "1CADE4",
-                "type": "solid",
-                "stroke": "0"
-            },
-            "type": "CxnSp",
-            "position": {
-                "rot": 0.0,
-                "flipH": 0,
-                "flipV": 0,
-                "x": 65.2174,
-                "y": 50.6087,
-                "cx": 99.9619,
-                "cy": 57.9377
-            },
-            "index": 10,
-            "svg": {
-                "id": "10",
-                "svgShape": [
-                    {
-                        "d": "M0,0 C 24.990475,0 49.98095,14.484425 49.98095,28.96885 C 49.98095,43.453275 74.971425,57.9377 99.9619,57.9377",
-                        "type": "path"
-                    }
-                ]
-            },
-            "uid": "da48c46664ab4be2af58fcf6727ff108"
-        },
-        {
-            "shapeType": "rect",
-            "paragraph": [
-                {
-                    "style": {
-                        "vert": "v-up",
-                        "hori": "h-mid",
-                        "writing": "horz"
-                    },
-                    "texts": [
-                        {
-                            "content": "Amir",
-                            "isbr": false,
-                            "style": {
-                                "color": "FFFFFF",
-                                "size": 115.0,
-                                "family": "inherit",
-                                "weight": "bold",
-                                "style": "normal",
-                                "decoration": "initial",
-                                "vertAlign": "baseline",
-                                "align": "initial",
-                                "shadow": "-0.6929px 0 , 0 0.6929px , 0.6929px 0 , 0 -0.6929px ;"
-                            }
-                        }
-                    ]
-                }
-            ],
-            "border": {
-                "width": 0.0,
-                "type": "solid",
-                "stroke": "0"
-            },
-            "type": "Sp",
-            "position": {
-                "rot": 0.0,
-                "flipH": 0,
-                "flipV": 0,
-                "x": 141.7873,
-                "y": 474.246,
-                "cx": 337.2954,
-                "cy": 195.4906
-            },
-            "index": 11,
-            "svg": {
-                "id": "11",
-                "svgShape": [
-                    {
-                        "x": "0",
-                        "y": "0",
-                        "width": "337.2954",
-                        "height": "195.4906",
-                        "type": "rect"
-                    }
-                ]
-            },
-            "uid": "2bc52a4a1a23418c85c467f365f3df4c"
-        }
-    ],
-    "fill": {
-        "type": 3,
-        "image": "https://teammodelostest.blob.core.chinacloudapi.cn/teammodelos/pptx/223c84bdbc0075e8fa418522644345ef8577ec4b/imgs/29100d92c12748d02845a4c652275177bb2c9a73.jpeg",
-        "style": {
-            "left": 0,
-            "top": -1000,
-            "right": 0,
-            "bottom": -1000
-        },
-        "rot": 0.0,
-        "grad": []
-    },
-    "index": 0,
-    "width": 960.0,
-    "height": 720.0,
-    "source": 1,
-    "flag": 1
-}

Різницю між файлами не показано, бо вона завелика
+ 0 - 1
TEAMModelOS/ClientApp/src/view/classrecord/data/10.json


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
TEAMModelOS/ClientApp/src/view/classrecord/data/11.json


Різницю між файлами не показано, бо вона завелика
+ 0 - 604
TEAMModelOS/ClientApp/src/view/classrecord/data/12.json


Різницю між файлами не показано, бо вона завелика
+ 0 - 559
TEAMModelOS/ClientApp/src/view/classrecord/data/2.json


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
TEAMModelOS/ClientApp/src/view/classrecord/data/3.json


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
TEAMModelOS/ClientApp/src/view/classrecord/data/4.json


Різницю між файлами не показано, бо вона завелика
+ 0 - 494
TEAMModelOS/ClientApp/src/view/classrecord/data/5.json


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
TEAMModelOS/ClientApp/src/view/classrecord/data/6.json


Різницю між файлами не показано, бо вона завелика
+ 0 - 559
TEAMModelOS/ClientApp/src/view/classrecord/data/7.json


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
TEAMModelOS/ClientApp/src/view/classrecord/data/8.json


Різницю між файлами не показано, бо вона завелика
+ 0 - 1
TEAMModelOS/ClientApp/src/view/classrecord/data/9.json


+ 664 - 0
TEAMModelOS/ClientApp/src/view/classrecord/data/Base.json

@@ -0,0 +1,664 @@
+{
+  "summary": {
+    "activityName": "動態名單",
+    "hostName": "罗老师",
+    "meterialName": "英聽測試",
+    "date": "2022.02.08",
+    "startTime": "16:53:53",
+    "endTime": "16:54:59",
+    "attendCount": 3,
+    "clientCount": 20,
+    "attendRate": 15.0,
+    "groupCount": 3,
+    "totalPoint": 0.0,
+    "totalInteractPoint": 110.0,
+    "collateTaskCount": 0,
+    "collateCount": 0,
+    "pushCount": 0,
+    "examCount": 1,
+    "examQuizCount": 1,
+    "examPointRate": 5.0,
+    "interactionCount": 2,
+    "clientInteractionCount": 5,
+    "clientInteractionAverge": 1.7
+  },
+  "report": {
+    "activityName": "動態名單",
+    "hostName": "罗老师",
+    "meterialName": "英聽測試",
+    "date": "2022.02.08",
+    "startTime": "16:53:53",
+    "endTime": "16:54:59",
+    "attendCount": 3,
+    "clientCount": 20,
+    "attendRate": 15.0,
+    "groupCount": 3,
+    "totalPoint": 0.0,
+    "totalInteractPoint": 110.0,
+    "collateTaskCount": 0,
+    "collateCount": 0,
+    "pushCount": 0,
+    "examCount": 1,
+    "examQuizCount": 1,
+    "examPointRate": 5.0,
+    "interactionCount": 2,
+    "clientInteractionCount": 5,
+    "clientInteractionAverge": 1.7,
+    "quizSummaryList": [
+      {
+        "quizID": "1",
+        "pageOrderStr": "P1",
+        "score": "10",
+        "correctAnswer": "2",
+        "correctRateStr": "0%"
+      },
+      {
+        "quizID": "2",
+        "pageOrderStr": "P4",
+        "score": "100",
+        "correctAnswer": "1",
+        "correctRateStr": "0%"
+      }
+    ],
+    "clientSummaryList": [
+      {
+        "groupName": "組別1",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 1,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          100.0
+        ],
+        "interactScore": 100.0,
+        "answerList": [
+          "1",
+          "1"
+        ],
+        "seatID": 1,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別2",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 1,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 10.0,
+        "answerList": [
+          "2",
+          "2"
+        ],
+        "seatID": 2,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別3",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 1,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "3",
+          "--"
+        ],
+        "seatID": 3,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別1",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 4,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別2",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 5,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別3",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 6,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別1",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 7,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別2",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 8,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別3",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 9,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別1",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 10,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別2",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 11,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別3",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 12,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別1",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 13,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別2",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 14,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別3",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 15,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別1",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 16,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別2",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 17,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別3",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 18,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別1",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 19,
+        "name": "學生"
+      },
+      {
+        "groupName": "組別2",
+        "groupScore": 0,
+        "groupTaskCompleteCount": 0,
+        "attendState": 0,
+        "score": 0,
+        "taskCompleteCount": 0,
+        "examScoreList": [
+          0.0
+        ],
+        "interactScore": 0.0,
+        "answerList": [
+          "--",
+          "--"
+        ],
+        "seatID": 20,
+        "name": "學生"
+      }
+    ]
+  },
+  "teacheract": [
+    {
+      "t": "T_idx",
+      "c": 5
+    },
+    {
+      "t": "DataChannel",
+      "c": 5
+    },
+    {
+      "t": "PgPushLoad",
+      "c": 5
+    },
+    {
+      "t": "BeamPgLoad",
+      "c": 0
+    },
+    {
+      "t": "DiffPush",
+      "c": 0
+    },
+    {
+      "t": "FdbkCollLoad",
+      "c": 0
+    },
+    {
+      "t": "HitaClientCmp",
+      "c": 0
+    },
+    {
+      "t": "DataResponse",
+      "c": 5
+    },
+    {
+      "t": "PopQuesLoad",
+      "c": 3
+    },
+    {
+      "t": "QuesLoad",
+      "c": 0
+    },
+    {
+      "t": "BuzrLoad",
+      "c": 0
+    },
+    {
+      "t": "CmpetinLoad",
+      "c": 0
+    },
+    {
+      "t": "ReAtmpAnsStrt",
+      "c": 2
+    },
+    {
+      "t": "DecisionStat",
+      "c": 3
+    },
+    {
+      "t": "StatChartLoad",
+      "c": 3
+    },
+    {
+      "t": "PieChart",
+      "c": 2
+    },
+    {
+      "t": "BarChart",
+      "c": 1
+    },
+    {
+      "t": "GrpChart",
+      "c": 0
+    },
+    {
+      "t": "FociStud",
+      "c": 0
+    },
+    {
+      "t": "PickupResult",
+      "c": 0
+    },
+    {
+      "t": "PickupSmart",
+      "c": 0
+    },
+    {
+      "t": "ShowAnsLoad",
+      "c": 0
+    },
+    {
+      "t": "MultiAssess",
+      "c": 3
+    },
+    {
+      "t": "ScoBrdLoad",
+      "c": 0
+    },
+    {
+      "t": "TimerResult",
+      "c": 0
+    },
+    {
+      "t": "WrkCmp",
+      "c": 3
+    },
+    {
+      "t": "TakePic",
+      "c": 0
+    }
+  ],
+  "student": [
+    {
+      "id": "91478",
+      "seatID": 1,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91479",
+      "seatID": 2,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91480",
+      "seatID": 3,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91481",
+      "seatID": 4,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91482",
+      "seatID": 5,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91483",
+      "seatID": 6,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91484",
+      "seatID": 6,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91485",
+      "seatID": 7,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91486",
+      "seatID": 8,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91487",
+      "seatID": 9,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91488",
+      "seatID": 10,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91489",
+      "seatID": 11,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91490",
+      "seatID": 12,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91491",
+      "seatID": 13,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91492",
+      "seatID": 14,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91493",
+      "seatID": 15,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91494",
+      "seatID": 16,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91495",
+      "seatID": 17,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91496",
+      "seatID": 18,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91497",
+      "seatID": 19,
+      "name": "學生",
+      "type": 0
+    },
+    {
+      "id": "91498",
+      "seatID": 20,
+      "name": "學生",
+      "type": 0
+    }
+  ]
+}

+ 3 - 3
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/CorrectRate.vue

@@ -9,7 +9,7 @@
                 optionBar: undefined,
                 option: {
                     title: {
-                        text: '正确率统计',
+                        text: this.$t('cusMgt.rcd.crtRate'),
                         // textStyle: {
                         //     color: 'white'
                         // },
@@ -35,11 +35,11 @@
                                     itemStyle: {
                                         color: '#1cc0f3'
                                     },
-                                    name:'正确'
+                                    name:this.$t('cusMgt.rcd.correct')
                                 },
                                 {
                                     value: 510,
-                                    name: '错误',
+                                    name: this.$t('cusMgt.rcd.wrong'),
                                     itemStyle: {
                                         color: '#ed4014'
                                     },

+ 60 - 29
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/DataCount.vue

@@ -2,7 +2,7 @@
     <div class="data-count-container">
         <div v-for="(item,index) in dataList" :key="index" class="data-item">
             <p class="data-value" :style="{borderColor:colorList[index]}">{{item.value}}</p>
-            <p class="data-label" >{{item.label}}</p>
+            <p class="data-label">{{item.label}}</p>
             <p class="data-info">{{item.info}}</p>
         </div>
     </div>
@@ -15,61 +15,92 @@ export default {
     },
     data() {
         return {
-            colorList:['#2d8cf0','#2d8cf0','#2db7f5','#2db7f5','#2db7f5','#19be6b','#2db7f5','#2db7f5','#2db7f5','#ed4014'],
+            baseData: {},
+            colorList: ['#2d8cf0', '#2d8cf0', '#2db7f5', '#2db7f5', '#2db7f5', '#19be6b', '#2db7f5', '#2db7f5', '#2db7f5', '#ed4014'],
             dataList: [
                 {
-                    label: '出席人数',
-                    value: 25,
-                    info: '(25/30 83.3%)'
+                    label: this.$t('cusMgt.rcd.attendCount'),
+                    value: 0,
+                    info: ''
                 },
                 {
-                    label: '小组数',
-                    value: 6,
+                    label: this.$t('cusMgt.rcd.gCount'),
+                    value: 0,
                     info: ''
                 },
-                
+
                 {
-                    label: '任务总数',
-                    value: 2,
+                    label: this.$t('cusMgt.rcd.taskCount'),
+                    value: 0,
                     info: ''
                 },
                 {
-                    label: '作品总数',
-                    value: 50,
+                    label: this.$t('cusMgt.rcd.colctCount'),
+                    value: 0,
                     info: ''
                 },
                 {
-                    label: '推送总数',
-                    value: 4,
+                    label: this.$t('cusMgt.rcd.pushCount'),
+                    value: 0,
                     info: ''
                 },
                 {
-                    label: '总记分',
-                    value: 117,
+                    label: this.$t('cusMgt.rcd.totalScore'),
+                    value: 0,
                     info: ''
                 },
                 {
-                    label: '测验总题数',
-                    value: 4,
+                    label: this.$t('cusMgt.rcd.examCount'),
+                    value: 0,
                     info: ''
                 },
                 {
-                    label: '互动题数',
-                    value: 8,
+                    label: this.$t('cusMgt.rcd.quCount'),
+                    value: 0,
                     info: ''
                 },
                 {
-                    label: '测验得分率',
-                    value: '20.8%',
+                    label: this.$t('cusMgt.rcd.scoreRate'),
+                    value: 0,
                     info: ''
                 },
                 {
-                    label: '学生互动总数',
-                    value: 175,
-                    info: '(7次/人)'
+                    label: this.$t('cusMgt.rcd.interactionCount'),
+                    value: 0,
+                    info: ''
                 }
             ]
         }
+    },
+    created() {
+        //Base.json Blob尚未上传,暂时从本地读取
+        this.baseData = require("../data/Base.json")
+        console.log(this.baseData)
+        if (this.baseData.summary) {
+            const summary = this.baseData.summary
+            // 出席人数
+            this.dataList[0].value = summary.attendCount
+            this.dataList[0].info = `(${summary.attendCount}/${summary.clientCount} ${summary.attendRate}%)`
+            // 小组数
+            this.dataList[1].value = summary.groupCount
+            //任务总数(作品收集任務數)
+            this.dataList[2].value = summary.collateTaskCount
+            // 作品总数
+            this.dataList[3].value = summary.collateCount
+            //推送總數(頁面+資源+訊息+差異化)
+            this.dataList[4].value = summary.pushCount
+            // 總計分
+            this.dataList[5].value = summary.totalPoint
+            // 测验总题数
+            this.dataList[6].value = summary.examQuizCount
+            // 互动题数
+            this.dataList[7].value = summary.interactionCount
+            // 测验得分率
+            this.dataList[8].value = summary.examPointRate
+            // 学生互动总数
+            this.dataList[9].value = summary.clientInteractionCount
+            this.dataList[9].info = `(${summary.clientInteractionAverge}${this.$t('cusMgt.rcd.intUnit')})`
+        }
     }
 }
 </script>
@@ -80,12 +111,12 @@ export default {
     flex-wrap: wrap;
     padding: 20px 0px;
 }
-.data-item{
+.data-item {
     width: 150px;
     padding: 10px;
     text-align: center;
 }
-.data-value{
+.data-value {
     font-size: 40px;
     font-weight: 600;
     color: #17233d;
@@ -95,11 +126,11 @@ export default {
     margin-bottom: 5px;
     border-bottom: 2px solid;
 }
-.data-label{
+.data-label {
     font-size: 16px;
     // color: #2d8cf0;
 }
-.data-info{
+.data-info {
     font-size: 12px;
 }
 </style>

+ 1 - 23
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/OptionCount.vue

@@ -9,10 +9,7 @@
                 optionBar: undefined,
                 option: {
                     title: {
-                        text: '选项分布',
-                        // textStyle: {
-                        //     color: 'white'
-                        // },
+                        text: this.$t('cusMgt.rcd.optionCount'),
                         right: '85',
                         top:'10'
                     },
@@ -22,9 +19,6 @@
                             type: 'shadow'
                         }
                     },
-                    //legend: {
-                    //    data: ['2011年', '2012年']
-                    //},
                     grid: {
                         left: '3%',
                         right: '4%',
@@ -34,26 +28,10 @@
                     xAxis: {
                         type: 'value',
                         boundaryGap: [0, 0.01],
-                        // axisLabel: {
-                        //     color:'white'
-                        // },
-                        // axisLine: {
-                        //     lineStyle: {
-                        //         color:'white'
-                        //     }
-                        // }
                     },
                     yAxis: {
                         type: 'category',
                         data: ['A', 'B', 'C', 'D'],
-                        // axisLabel: {
-                        //     color:'white'
-                        // },
-                        // axisLine: {
-                        //     lineStyle: {
-                        //         color:'white'
-                        //     }
-                        // }
                     },
                     series: [
                         {

+ 1 - 1
TEAMModelOS/ClientApp/src/view/classrecord/eventchart/Push.vue

@@ -3,7 +3,7 @@
         <TeacherClient></TeacherClient>
         <template v-if="pushType == 'img'">
             <div class="question-data-wrap">
-                <p class="text-label">教師推送了一張圖: </p>
+                <p class="text-label">{{$t('cusMgt.rcd.tPushLabel')}}</p>
                 <img  class="tea-push-img" src="https://teammodelostest.blob.core.chinacloudapi.cn/teammodelcontest/common/20200213/%E9%86%8D%E6%91%A9%E8%B1%86_%E8%B1%86%E5%AD%90%E5%BE%BD%E7%AB%A0_20200213154333.png" @click="openViewer('https://teammodelostest.blob.core.chinacloudapi.cn/teammodelcontest/common/20200213/%E9%86%8D%E6%91%A9%E8%B1%86_%E8%B1%86%E5%AD%90%E5%BE%BD%E7%AB%A0_20200213154333.png')" />
             </div>
         </template>

+ 9 - 4
TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue

@@ -152,7 +152,7 @@
                                                 <Time class="record-time" :time="item.startTime" />
                                                 <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')" @click.stop="shareRecord" />
+                                                    <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)" />
                                                 </div>
                                             </div>
@@ -552,7 +552,7 @@ export default {
     },
     methods: {
         shareRecord() {
-            this.$Message.warning('暂未开发分享功能')
+            this.$Message.warning('分享功能开发中')
         },
         delRecord(id) {
             this.$Modal.confirm({
@@ -1344,7 +1344,7 @@ export default {
         },
         filterRecordList(index) {
             this.recordListShow = this.recordList.filter(item => {
-                let id = this.teaClassList[index].classId || this.teaClassList[index].stulist
+                let id = this.teaClassList[index]?.classId || this.teaClassList[index]?.stulist
                 return item.groupIds.includes(id)
             })
         },
@@ -1353,7 +1353,12 @@ export default {
             this.$router.push({
                 name: 'classRecord',
                 params: {
-                    record: this.recordList[index]
+                    record: {
+                        id:this.recordList[index].id,
+                        name:this.recordList[index].name,
+                        startTime:this.recordList[index].startTime,
+                        eNote:this.recordList[index].eNote
+                    }
                 }
             })
         },

+ 13 - 13
TEAMModelOS/ClientApp/src/view/teachCenter/TeaResCenter.vue

@@ -239,7 +239,7 @@ export default {
                             },
                             createEl: function() {
                                 let divObj = videojs.dom.createEl("div", {
-                                    className: "vjs-quartet noShow",
+                                    className: "vjs-quartet",
                                     innerHTML: "<div id='quartetChart'></div>"
                                 })
                                 return divObj
@@ -252,7 +252,7 @@ export default {
                             },
                             createEl: function() {
                                 let divObj = videojs.dom.createEl("div", {
-                                    className: "vjs-column-chart noShow",
+                                    className: "vjs-column-chart",
                                     innerHTML: `<div id='ColumnChart'></div><div id="Interaction"></div><div id="Teaching"></div>`
                                 })
                                 return divObj
@@ -292,16 +292,6 @@ export default {
         changePan() {
             this.showPan = !this.showPan
             if(this.showPan) {
-                this.player.getChild("controlBar").height("38%")
-                // document.getElementsByClassName("vjs-control-bar")[0].style.height = "37vh"
-
-                this.player.getChild("cloumn").removeClass("noShow")
-
-                this.player.getChild("controlBar").getChild("progressControl").getChild("quartetChart").removeClass("noShow")
-
-                this.player.getChild("controlBar").getChild("progressControl").children()[0].children()[2].addClass("time-line")
-
-            } else {
                 this.player.getChild("controlBar").height("6%")
                 // document.getElementsByClassName("vjs-control-bar")[0].style.height = "4em"
 
@@ -311,6 +301,16 @@ export default {
                 
                 this.player.getChild("controlBar").getChild("progressControl").children()[0].children()[2].removeClass("time-line")
 
+            } else {
+                this.player.getChild("controlBar").height("38%")
+                // document.getElementsByClassName("vjs-control-bar")[0].style.height = "37vh"
+
+                this.player.getChild("cloumn").removeClass("noShow")
+
+                this.player.getChild("controlBar").getChild("progressControl").getChild("quartetChart").removeClass("noShow")
+
+                this.player.getChild("controlBar").getChild("progressControl").children()[0].children()[2].addClass("time-line")
+
             }
         },
         // 背景波峰
@@ -899,7 +899,7 @@ export default {
         display: flex;
         align-items: flex-end;
         // padding-top: 30px;
-        height: 4em; //6em
+        height: 38%; //4em
         background-color: rgba(0, 0, 0, 0.82);
     }
     .video-js .vjs-control{

+ 67 - 73
TEAMModelOS/Controllers/Teacher/InitController.cs

@@ -240,8 +240,7 @@ namespace TEAMModelOS.Controllers
                 jwt.Payload.TryGetValue("name", out object name);
                 jwt.Payload.TryGetValue("picture", out object picture);
                 Teacher teacher = null;
-
-                TeacherInfo teacherInfo= await TeacherService.GetTeacherInfo(_azureCosmos, teacher, $"{name}", $"{picture}", id, _azureStorage, _option);
+                TeacherInfo teacherInfo= await TeacherService.TeacherInfo(_azureCosmos, teacher, $"{name}", $"{picture}", id, _azureStorage, _option);
                 return Ok(new { location = _option.Location, teacherInfo. auth_token, teacherInfo. blob_uri, teacherInfo.blob_sas, teacherInfo.schools, teacherInfo.defaultschool, teacherInfo. courses,
                     teacherInfo.total,
                     teacherInfo.osblob_uri,
@@ -284,39 +283,58 @@ namespace TEAMModelOS.Controllers
                 List<string> permissions = new List<string>();
                 int size = 0;
                 Teacher teacher = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<Teacher>(id, new PartitionKey("Base"));
-                
                 List<AreaDto> areas = new List<AreaDto>();
+                HashSet<string> areaIds = new HashSet<string>();
+                if (teacher.areas.IsNotEmpty())
+                {
+                    teacher.areas.ForEach(x => {
+                        areaIds.Add(x.areaId);
+                    });
+                }
+                if (teacher.schools.IsNotEmpty())
+                {
+                    teacher.schools.ForEach(x => {
+                        if (!string.IsNullOrEmpty(x.areaId)) {
+                            areaIds.Add(x.areaId);
+                        }
+                        
+                    });
+                }
+                List<Area> areasDbs = new List<Area>();
+                List<AreaSetting> areaSettings = new List<AreaSetting>();
+                if (areaIds.Count > 0)
+                {
+                    string queryText = $"select value(c) from c where c.id in ({string.Join(",", areaIds.Select(x => $"'{x}'"))})";
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Area>(queryText: queryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base-Area") }))
+                    {
+                        areasDbs.Add(item);
+                    }
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<AreaSetting>(queryText: queryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("AreaSetting") }))
+                    {
+                        areaSettings.Add(item);
+                    }
+                }
                 if (teacher.areas.IsNotEmpty()) {
                     foreach (var areat in teacher.areas)
                     {
-                        try
+                         
+                        Area area = areasDbs.Find(x => x.id.Equals(areat.areaId));
+                        AreaSetting setting = null;
+                        if (area != null)
                         {
-                            Area area = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<Area>($"{areat.areaId}", new PartitionKey("Base-Area"));
-                            AreaSetting setting = null;
-                            try
-                            {
-                                setting = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<AreaSetting>($"{areat.areaId}", new PartitionKey("AreaSetting"));
-                            }
-                            catch (CosmosException ex)
-                            {
-                                setting = null;
-                            }
-                            int access = 0;
-                            if (setting != null && !string.IsNullOrWhiteSpace(setting.accessConfig))
-                            {
-                                access = 1;
-                            }
-                            if (setting != null)
-                            {
-                                setting.accessConfig = null;
-                            }
-                            areas.Add(new AreaDto { areaId = area.id, name = area.name, standard = area.standard, standardName = area.standardName, setting= setting, access = access });
+                            setting = areaSettings.Find(x => x.id.Equals(areat.areaId));
                         }
-                        catch (CosmosException)
+
+                        int access = 0;
+                        if (setting != null && !string.IsNullOrWhiteSpace(setting.accessConfig))
                         {
-                            //数据库捞不到数据
-                            continue;
+                            access = 1;
                         }
+                        if (setting != null)
+                        {
+                            setting.accessConfig = null;
+                        }
+                        areas.Add(new AreaDto { areaId = area.id, name = area.name, standard = area.standard, standardName = area.standardName, setting= setting, access = access });
                     }
                 }
                 if (school_code.Equals(teacher.defaultSchool) && teacher.schools.IsNotEmpty() && !teacher.schools.Select(x => x.schoolId).Contains(school_code))
@@ -383,16 +401,12 @@ namespace TEAMModelOS.Controllers
                 if (!string.IsNullOrEmpty(school_base.areaId)) {
                     try
                     {
-                        Area  area = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<Area>($"{school_base.areaId}", new PartitionKey("Base-Area"));
+                        Area area = areasDbs.Find(x => x.id.Equals(school_base.areaId));
                         AreaSetting setting = null;
-                        try
-                        {
-                            setting = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<AreaSetting>($"{school_base.areaId}", new PartitionKey("AreaSetting"));
-                        }
-                        catch (CosmosException ex)
-                        {
-                            setting = null;
+                        if (area != null) {
+                            setting= areaSettings.Find(x => x.id.Equals(school_base.areaId));
                         }
+                        
                         int access = 0;
                         AccessConfig accessConfig = null;
                         if (setting != null && !string.IsNullOrWhiteSpace(setting.accessConfig))
@@ -405,10 +419,10 @@ namespace TEAMModelOS.Controllers
                         }
                         currArea = new   
                         {
-                            areaId = area.id, 
-                            name = area.name, 
-                            standard = area.standard, 
-                            standardName = area.standardName, 
+                            areaId = area?.id, 
+                            name = area?.name, 
+                            standard = area?.standard, 
+                            standardName = area?.standardName, 
                             setting = setting, 
                             access = access,
                             //submitType=accessConfig?.submitType,
@@ -430,7 +444,9 @@ namespace TEAMModelOS.Controllers
 
                 //取得班级
                 List<object> school_classes = new List<object>();
-                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: $"SELECT c.id,c.x,c.y,c.name,c.year,c.teacher,c.periodId,c.gradeId,c.room,c.sn,c.no,c.style,c.status,c.openType,c.school, ARRAY_LENGTH(c.students) AS studCount FROM c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Class-{school_code}") }))
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator
+                    (queryText: $"SELECT c.id,c.x,c.y,c.name,c.year,c.teacher,c.periodId,c.gradeId,c.room,c.sn,c.no,c.style,c.status,c.openType,c.school, ARRAY_LENGTH(c.students) AS studCount FROM c", 
+                    requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Class-{school_code}") }))
                 {
                     var jsonc = await JsonDocument.ParseAsync(item.ContentStream);
                     foreach (var classeinfo in jsonc.RootElement.GetProperty("Documents").EnumerateArray())
@@ -445,35 +461,6 @@ namespace TEAMModelOS.Controllers
                 {
                     school_rooms.Add(item);
                 }
-                //List<object> periods = new List<object>();
-                //List<object> grades = new List<object>();
-                //var responsesch = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(school_code.ToString(), new PartitionKey($"Base"));
-                //if (responsesch.Status == 200)
-                //{
-                //    var jsons = await JsonDocument.ParseAsync(responsesch.ContentStream);
-                //    if (jsons.RootElement.TryGetProperty("period", out JsonElement periodJobj))
-                //    {
-                //        foreach (var periodinfo in periodJobj.EnumerateArray())
-                //        {
-                //            dynamic periodExtobj = new ExpandoObject();
-                //            periodExtobj.id = periodinfo.GetProperty("id");
-                //            periodExtobj.name = periodinfo.GetProperty("name");
-                //            periods.Add(periodExtobj);
-                //            if (periodinfo.TryGetProperty("grades", out JsonElement gradesJobj))
-                //            {
-                //                foreach (var gradeinfo in gradesJobj.EnumerateArray())
-                //                {
-                //                    dynamic gradeExtobj = new ExpandoObject();
-                //                    gradeExtobj.id = gradeinfo.GetProperty("id");
-                //                    gradeExtobj.name = gradeinfo.GetProperty("name");
-                //                    gradeExtobj.periodId = periodinfo.GetProperty("id");
-                //                    grades.Add(gradeExtobj);
-                //                }
-                //            }
-                //        }
-                //    }
-                //}
-
                 //該老師排定的學校課程
                 List<object> school_courses = new List<object>();
                 var query = $"SELECT distinct value(c) FROM c JOIN A1 IN c.schedule where A1.teacherId='{id}'";
@@ -488,7 +475,14 @@ namespace TEAMModelOS.Controllers
                         }
                     }
                 }
-
+                List<SchoolProductSumProdInfo> prodInfos = new List<SchoolProductSumProdInfo>();
+                Azure.Response productSumResponse = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(school_code, new PartitionKey("ProductSum"));
+                if (productSumResponse.Status == 200) {
+                    var doc= JsonDocument.Parse(productSumResponse.Content);
+                    if (doc.RootElement.TryGetProperty("prodinfo", out JsonElement element)) {
+                        prodInfos = element.ToObject<List<SchoolProductSumProdInfo>>();                  
+                    }
+                }
                 //校本課綱 [式樣未定 先不取]
                 
                 //取得School Blob 容器位置及SAS
@@ -498,7 +492,7 @@ namespace TEAMModelOS.Controllers
                 var (blob_uri, blob_sas) = (roles.Contains("admin") || permissions.Contains("schoolAc-upd")) ? _azureStorage.GetBlobContainerSAS(school_code_blob, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete) : _azureStorage.GetBlobContainerSAS(school_code_blob, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Write);
                 ///https://teammodelstorage.blob.core.chinacloudapi.cn/teammodelos
                 var (osblob_uri, osblob_sas) = roles.Contains("area") ? _azureStorage.GetBlobContainerSAS("teammodelos", BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete) : _azureStorage.GetBlobContainerSAS("teammodelos", BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
-                return Ok(new { auth_token, blob_uri, blob_sas, school_base, school_courses,  school_classes, school_rooms, size, osblob_uri, osblob_sas, status = 200, areas , currArea });
+                return Ok(new { auth_token, blob_uri, blob_sas, school_base, school_courses,  school_classes, school_rooms, size, osblob_uri, osblob_sas, status = 200, areas , currArea , productSum= new { prodinfo= prodInfos } });
             }
             catch (CosmosException ex)
             {
@@ -507,7 +501,7 @@ namespace TEAMModelOS.Controllers
                 HttpContext.Request.Headers.TryGetValue("sec-ch-ua-platform", out var platform);
                 HttpContext.Request.Headers.TryGetValue("user-agent", out var useragent);
                 await _dingDing.SendBotMsg($"IES5,{_option.Location},Teacher/init/get-school-info()\n{ex.Message}{ex.StackTrace}\n{request.ToJsonString()}\nreferer:{referer}\nsec-ch-ua:{chua}\nsec-ch-ua-platform:{platform}\nuser-agent:{useragent}", GroupNames.醍摩豆服務運維群組);
-                return Ok(new { status = ex.Status });
+                return BadRequest(new { status = ex.Status });
             }
             catch (Exception ex)
             {
@@ -516,7 +510,7 @@ namespace TEAMModelOS.Controllers
                 HttpContext.Request.Headers.TryGetValue("sec-ch-ua-platform", out var platform);
                 HttpContext.Request.Headers.TryGetValue("user-agent", out var useragent);
                 await _dingDing.SendBotMsg($"IES5,{_option.Location},Teacher/init/get-school-info()\n{ex.Message}{ex.StackTrace}\n{request.ToJsonString()}\nreferer:{referer}\nsec-ch-ua:{chua}\nsec-ch-ua-platform:{platform}\nuser-agent:{useragent}", GroupNames.醍摩豆服務運維群組);
-                return Ok(new { status = 500 });
+                return BadRequest(new { status = 500 });
             }
         }
 

+ 2 - 259
TEAMModelOS/Controllers/Teacher/TeacherInitController.cs

@@ -68,7 +68,7 @@ namespace TEAMModelOS.Controllers
                 jwt.Payload.TryGetValue("name", out object name);
                 jwt.Payload.TryGetValue("picture", out object picture);
                 Teacher teacher = null;
-                TeacherInfo teacherInfo = await TeacherInfo(_azureCosmos, teacher, $"{name}", $"{picture}", id, _azureStorage, _option);
+                TeacherInfo teacherInfo = await TeacherService. TeacherInfo(_azureCosmos, teacher, $"{name}", $"{picture}", id, _azureStorage, _option);
                 return Ok(new
                 {
                     location = _option.Location,
@@ -98,263 +98,6 @@ namespace TEAMModelOS.Controllers
             }
         }
 
-        public static async Task<TeacherInfo> TeacherInfo(AzureCosmosFactory _azureCosmos, Teacher teacher, string name, string picture, string id, AzureStorageFactory _azureStorage, Option _option)
-        {
-            List<object> schools = new List<object>();
-            List<AreaDto> areas = new List<AreaDto>();
-            List<Area> areasd = new List<Area>();
-            string defaultschool = null;
-            //TODO 取得Teacher 個人相關數據(課程清單、虛擬教室清單、歷史紀錄清單等),學校數據另外API處理,多校切換時不同
-            var client = _azureCosmos.GetCosmosClient();
-            int total = 0;
-            int tsize = 0;
-            try
-            {
-                if (teacher == null)
-                {
-                    teacher = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<Teacher>(id, new PartitionKey("Base"));
-                    teacher.name = $"{name}";
-                    teacher.picture = $"{picture}";
-                }
-                else
-                {
-                    name = teacher.name;
-                    picture = teacher.picture;
-                    id = teacher.id;
-                }
-                ///教师的个人空间
-                tsize = teacher.size;
-                ///教师的总空间 包含 个人空间和学校赠送的空间累加
-                total = teacher.size;
-                //areas = teacher.areas;
-                if (teacher.areas.IsNotEmpty())
-                {
-                    //teacher.areas.Select(x => x.areaId);
-                    //await foreach (var item    client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Area>($"{areat.areaId}", new PartitionKey("Base-Area"))) { 
-
-                    //}
-                    //https://test.teammodel.cn/hita/join-school?ts=1644291704907&school=cdxcwgy
-                    foreach (var areat in teacher.areas)
-                    {
-                        try
-                        {
-                            Area area = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<Area>($"{areat.areaId}", new PartitionKey("Base-Area"));
-                            areasd.Add(area);
-                            AreaSetting setting = null;
-                            try
-                            {
-                                setting = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<AreaSetting>($"{areat.areaId}", new PartitionKey("AreaSetting"));
-                            }
-                            catch (CosmosException ex)
-                            {
-                                setting = null;
-                            }
-                            int access = 0;
-                            if (setting != null && !string.IsNullOrWhiteSpace(setting.accessConfig))
-                            {
-                                access = 1;
-                            }
-                            if (setting != null)
-                            {
-                                setting.accessConfig = null;
-                            }
-                            areas.Add(new AreaDto { areaId = area.id, name = area.name, standard = area.standard, standardName = area.standardName, setting = setting, access = access });
-                        }
-                        catch (CosmosException)
-                        {
-                            //数据库捞不到数据
-                            continue;
-                        }
-                    }
-                }
-                //检查是否有加入学校,如果加入学校,则当个人空间size是0G的时候,则免费获得一个G空间,但无论加入多少个学校,只能获取一次 1G的免费空间。没有加入学校则默认0G空间,除非自己购买空间
-                if (teacher.schools.IsNotEmpty())
-                {
-                    foreach (var sc in teacher.schools)
-                    {
-                        string statusNow = sc.status != null ? sc.status : "";
-                        if (statusNow.Equals("join") || statusNow.Equals("invite") || statusNow.Equals("request"))
-                        {
-                            dynamic schoolExtobj = new ExpandoObject();
-                            // var schoolJson = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync($"{sc.schoolId}", new PartitionKey("Base"));
-                            //var school = await JsonDocument.ParseAsync(schoolJson.ContentStream);
-                            schoolExtobj.schoolId = sc.schoolId;
-                            schoolExtobj.name = sc.name;
-                            schoolExtobj.status = sc.status;
-                            schoolExtobj.time = sc.time;
-                            schoolExtobj.picture = sc.picture;
-                            schoolExtobj.areaId = $"{sc.areaId}";
-                            Area area = null;
-                            int access = 0;
-                            if (!string.IsNullOrEmpty($"{sc.areaId}"))
-                            {
-
-                                try
-                                {
-
-                                    area = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<Area>($"{sc.areaId}", new PartitionKey("Base-Area"));
-                                    AreaSetting setting = null;
-                                    try
-                                    {
-                                        setting = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<AreaSetting>($"{area.id}", new PartitionKey("AreaSetting"));
-                                    }
-                                    catch (CosmosException ex)
-                                    {
-                                        setting = null;
-                                    }
-
-                                    if (setting != null && !string.IsNullOrWhiteSpace(setting.accessConfig))
-                                    {
-                                        access = 1;
-                                    }
-                                    areasd.Add(area);
-
-                                }
-                                catch (CosmosException)
-                                {
-                                    area = null;
-                                }
-                            }
-                            if (area != null)
-                            {
-                                schoolExtobj.area = new { area.name, area.id, area.institution, area.provName, area.code, area.cityCode, area.cityName, area.standard, area.provCode, area.pk, access };
-
-                            }
-                            else
-                            {
-                                schoolExtobj.area = area;
-                            }
-                            var sctch = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(id, new PartitionKey($"Teacher-{sc.schoolId}"));
-                            if (sctch.Status == 200)
-                            {
-                                var jsonDoc = await JsonDocument.ParseAsync(sctch.ContentStream);
-                                SchoolTeacher schoolTeacher = jsonDoc.RootElement.ToObject<SchoolTeacher>();
-                                schoolTeacher.name = $"{name}";
-                                schoolTeacher.picture = $"{picture}";
-                                await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(schoolTeacher, id, new PartitionKey($"Teacher-{sc.schoolId}"));
-                                if (jsonDoc.RootElement.TryGetProperty("size", out JsonElement _size) && _size.ValueKind.Equals(JsonValueKind.Number))
-                                {
-                                    total += _size.GetInt32();
-                                    schoolExtobj.size = _size.GetInt32();
-                                }
-                                else { schoolExtobj.size = 0; }
-                            }
-                            else
-                            {
-                                schoolExtobj.size = 0;
-                            }
-                            if (statusNow.Equals("join"))
-                            {
-                                //初始化
-                                await TmdUserService.JoinSchool(client, teacher.id, teacher.picture, teacher.name, sc.schoolId, sc.name);
-                            }
-                            schools.Add(schoolExtobj);
-                        }
-                    }
-                    //如果包含任何申请,邀请,加入学校的记录 且个人空间未分配2G  则默认分配个人空间至2G.
-                    if (teacher.size < 2 && teacher.schools.Count > 0)
-                    {
-                        teacher.size = 2;
-                    }
-                    //如果未包含任何申请,邀请,加入学校的记录 且 个人空间没有分配1G 则默认赠送一个G 
-                    if (teacher.schools.Count == 0 && teacher.size < 1)
-                    {
-                        teacher.size = 1;
-                    }
-                }
-                if (string.IsNullOrEmpty(teacher.defaultSchool) && teacher.schools.IsNotEmpty())
-                {
-                    var tech = teacher.schools.FindAll(x => x.status.Equals("join"));
-                    if (tech.IsNotEmpty())
-                    {
-                        teacher.defaultSchool = teacher.schools[0].schoolId;
-                    }
-                }
-                await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, id, new PartitionKey("Base"));
-                //預設學校ID
-                defaultschool = teacher.defaultSchool;
-            }
-            catch (CosmosException ex)
-            {
-                if (ex.Status == 404)
-                {
-                    //如果沒有,則初始化Teacher基本資料到Cosmos
-                    teacher = new Teacher
-                    {
-                        id = id,
-                        pk = "Base",
-                        code = "Base",
-                        name = name?.ToString(),
-                        picture = picture?.ToString(),
-                        //创建账号并第一次登录IES5则默认赠送1G
-                        size = 1,
-                        defaultSchool = null,
-                        schools = new List<Teacher.TeacherSchool>(),
-                    };
-                    var container = _azureStorage.GetBlobContainerClient(id);
-                    await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在
-                    teacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<Teacher>(teacher, new PartitionKey("Base"));
-                    total = teacher.size;
-                    tsize = teacher.size;
-                }
-            }
-            catch (Exception ex) {
-                throw new Exception($"{ex.Message}{ex.StackTrace}");
-            }
-            //私人課程
-            List<object> courses = new List<object>();
-            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIterator(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{id}") }))
-            {
-                using var json = await JsonDocument.ParseAsync(item.ContentStream);
-                if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
-                {
-                    foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
-                    {
-                        courses.Add(obj.ToObject<object>());
-                    }
-                }
-            }
-
-
-            List<string> roles = new List<string>() { "teacher" };
-            Area areaa = null;
-            if (areas.Count > 0)
-            {
-                roles.Add("area");
-                if (!string.IsNullOrEmpty($"{areas[0]}"))
-                {
-
-                    try
-                    {
-                        areaa = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<Area>($"{areas[0].areaId}", new PartitionKey("Base-Area"));
-                    }
-                    catch (CosmosException)
-                    {
-                        areaa = null;
-                    }
-                }
-            }
-            //換取AuthToken,提供給前端
-            var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id, name?.ToString(), picture?.ToString(), _option.JwtSecretKey, Website: "IES", scope: Constant.ScopeTeacher, standard: areaa != null ? areaa.standard : "", roles: roles.ToArray());
-            //取得Teacher Blob 容器位置及SAS 
-            await _azureStorage.GetBlobContainerClient(id).CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在
-            var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete);
-            var (osblob_uri, osblob_sas) = roles.Contains("area") ? _azureStorage.GetBlobContainerSAS("teammodelos", BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete) : _azureStorage.GetBlobContainerSAS("teammodelos", BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
-            return new TeacherInfo
-            {
-                auth_token = auth_token,
-                blob_uri = blob_uri,
-                blob_sas = blob_sas,
-                schools = schools,
-                defaultschool = defaultschool,
-                courses = courses,
-                total = total,
-                osblob_sas = osblob_sas,
-                osblob_uri = osblob_uri,
-                tsize = tsize,
-                areas = areas,
-                teacher = teacher
-            };
-        }
+        
     }
 }