Jelajahi Sumber

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

Li 3 tahun lalu
induk
melakukan
ce9b058e9b
57 mengubah file dengan 876 tambahan dan 308 penghapusan
  1. 1 1
      TEAMModelBI/ClientApp/public/index.html
  2. 2 2
      TEAMModelBI/ClientApp/src/router/index.js
  3. 6 1
      TEAMModelBI/ClientApp/src/view/common/header.vue
  4. 1 1
      TEAMModelBI/ClientApp/src/view/index/dashboard.vue
  5. 175 7
      TEAMModelBI/ClientApp/src/view/index/operateLog.vue
  6. 5 2
      TEAMModelBI/ClientApp/src/view/teachermanage/areamanage.vue
  7. 1 1
      TEAMModelBI/ClientApp/src/view/teachermanage/manage.vue
  8. 4 1
      TEAMModelBI/ClientApp/src/view/teachermanage/school.vue
  9. 1 1
      TEAMModelBI/ClientApp/src/view/teachermanage/traitmanage.vue
  10. 9 6
      TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs
  11. 3 0
      TEAMModelOS.SDK/Models/Cosmos/Common/LessonRecord.cs
  12. 16 4
      TEAMModelOS.SDK/Models/Cosmos/Teacher/Favorite.cs
  13. 16 0
      TEAMModelOS.SDK/Models/Service/Third/Nx/NxModel.cs
  14. 0 0
      TEAMModelOS.SDK/Models/Service/Third/Sc/ScApisService.cs
  15. 0 0
      TEAMModelOS.SDK/Models/Service/Third/Sc/ScYxptModel.cs
  16. 10 1
      TEAMModelOS/ClientApp/src/api/schoolSetting.js
  17. 1 1
      TEAMModelOS/ClientApp/src/common/BasePreviewFile.vue
  18. 3 3
      TEAMModelOS/ClientApp/src/locale/lang/en-US/cusMgt.js
  19. 5 5
      TEAMModelOS/ClientApp/src/locale/lang/en-US/evaluation.js
  20. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/learnActivity.js
  21. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/login.js
  22. 3 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/researchCenter.js
  23. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/stuAccount.js
  24. 16 16
      TEAMModelOS/ClientApp/src/locale/lang/en-US/studentWeb.js
  25. 16 16
      TEAMModelOS/ClientApp/src/locale/lang/en-US/syllabus.js
  26. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/system.js
  27. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/teachContent.js
  28. 6 6
      TEAMModelOS/ClientApp/src/locale/lang/en-US/unit.js
  29. 4 4
      TEAMModelOS/ClientApp/src/locale/lang/en-US/updModal.js
  30. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/login.js
  31. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/researchCenter.js
  32. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/answerSheet.js
  33. 2 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/evaluation.js
  34. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/learnActivity.js
  35. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/login.js
  36. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/researchCenter.js
  37. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/settings.js
  38. 1 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/studentWeb.js
  39. 7 2
      TEAMModelOS/ClientApp/src/utils/public.js
  40. 1 1
      TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue
  41. 19 7
      TEAMModelOS/ClientApp/src/view/homepage/HomePage.less
  42. 110 78
      TEAMModelOS/ClientApp/src/view/homepage/HomePage.vue
  43. 1 1
      TEAMModelOS/ClientApp/src/view/homepage/TechScore.vue
  44. 0 34
      TEAMModelOS/ClientApp/src/view/homepage/WeekCount.vue
  45. 24 0
      TEAMModelOS/ClientApp/src/view/homework/ManageHomeWork.vue
  46. 11 6
      TEAMModelOS/ClientApp/src/view/login/page/Teacher.vue
  47. 142 27
      TEAMModelOS/ClientApp/src/view/mgtPlatform/MgtPlatform.vue
  48. 11 3
      TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.less
  49. 5 5
      TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue
  50. 14 2
      TEAMModelOS/ClientApp/src/view/teachCenter/TeaResCenter.less
  51. 29 8
      TEAMModelOS/ClientApp/src/view/teachCenter/TeaResCenter.vue
  52. 1 1
      TEAMModelOS/Controllers/Both/ShareController.cs
  53. 56 6
      TEAMModelOS/Controllers/Client/HiTeachController.cs
  54. 17 32
      TEAMModelOS/Controllers/Both/FavoriteController.cs
  55. 104 0
      TEAMModelOS/Controllers/Third/NxController.cs
  56. 1 1
      TEAMModelOS/Controllers/Third/ScController.cs
  57. 4 4
      TEAMModelOS/TEAMModelOS.csproj

+ 1 - 1
TEAMModelBI/ClientApp/public/index.html

@@ -11,7 +11,7 @@
     </title>
 </head>
 <script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>
-<script src="https://at.alicdn.com/t/font_2934132_jamkq43te8b.js"></script>
+<script src="https://at.alicdn.com/t/font_2934132_93b96cu3q3k.js"></script>
 
 <body>
     <noscript>

+ 2 - 2
TEAMModelBI/ClientApp/src/router/index.js

@@ -1,4 +1,4 @@
-import { createRouter, createWebHashHistory } from "vue-router";
+import { createWebHashHistory, createRouter } from "vue-router";
 // import store from '@/store/index.js'
 const routes = [{
         path: "/",
@@ -59,7 +59,7 @@ const routes = [{
                 component: () => require.ensure([], (require) => require(`@/view/teachermanage/traitmanage.vue`))
             },
             {
-                name: "创区/创校",
+                name: "created",
                 path: "created",
                 permission: "batcharea-read|batcharea-upd|batchschool-read|batchschool-upd",
                 menuName: "",

+ 6 - 1
TEAMModelBI/ClientApp/src/view/common/header.vue

@@ -52,7 +52,12 @@ export default {
         })
         function quit() {
             router.push('/login')
-            localStorage.clear()
+            localStorage.removeItem('userData')
+            localStorage.removeItem('id_token')
+            localStorage.removeItem('blobInfo')
+            localStorage.removeItem('management')
+            localStorage.removeItem('organization')
+            // localStorage.clear()
         }
         function pushlog() {
             router.push('/home/log')

+ 1 - 1
TEAMModelBI/ClientApp/src/view/index/dashboard.vue

@@ -137,7 +137,7 @@ export default {
             { name: '创校总数', value: '' },
             { name: '教师总人数', value: '' },
             { name: '学生总人数', value: '' },
-            { name: '空间总大小', value: '' },
+            { name: '空间总大小(GB)', value: '' },
         ])
         //处理url多余的参数内容
         let headerHost = window.location.href.split('/login?code')

+ 175 - 7
TEAMModelBI/ClientApp/src/view/index/operateLog.vue

@@ -4,14 +4,57 @@
             <div class="exportFile">
                 <el-button type="primary" size="small" @click="exportExcel">导出日志文件</el-button>
             </div>
-            <div class="block">
-                <span class="demonstration">日期:</span>
-                <el-date-picker v-model="times" type="daterange" range-separator="至" start-placeholder="开始时间" end-placeholder="截止时间" clearable @change='timeChange' format="YYYY/MM/DD" value-format="x">
-                </el-date-picker>
+            <div class="iconGroup" v-show="models==='default'">
+                <div v-for="item in iconGroups" :key="item.id" :title="item.title" @click="models=item.models" @blur="models='default'" class="log-icons">
+                    <svg class="logicon" aria-hidden="true">
+                        <use :xlink:href="item.icon"></use>
+                    </svg>
+                </div>
+            </div>
+            <div class="block" v-if="models==='time'">
+                <div class="block-title"><span class="demonstration">日期:</span></div>
+                <div class="block-content">
+                    <el-date-picker v-model="times" type="daterange" range-separator="至" start-placeholder="开始时间" end-placeholder="截止时间" clearable @change='timeChange' format="YYYY/MM/DD" value-format="x">
+                    </el-date-picker>
+                </div>
+                <div class="close-icon" @click="models='default'">
+                    <svg class="closelog-icon" aria-hidden="true">
+                        <use xlink:href="#icon-cuowuguanbiquxiao-yuankuang"></use>
+                    </svg>
+                </div>
+            </div>
+            <div class="block" v-else-if="models==='select'">
+                <div class="block-title"><span class="demonstration">平台:</span></div>
+                <div class="block-content">
+                    <el-checkbox-group v-model="cities.citiesValue" size="default" @change="changePlatform">
+                        <el-checkbox-button v-for="city in cities.data" :key="city" :label="city">{{city}}</el-checkbox-button>
+                    </el-checkbox-group>
+                </div>
+                <div class="close-icon" @click="models='default'">
+                    <svg class="closelog-icon" aria-hidden="true">
+                        <use xlink:href="#icon-cuowuguanbiquxiao-yuankuang"></use>
+                    </svg>
+                </div>
+            </div>
+            <div class="block" v-else-if="models==='search'">
+                <div class="block-search">
+                    <el-input placeholder="请输入姓名/tmdID" prefix-icon="el-icon-search" v-model="searchKey" @change="searchkeyword">
+                    </el-input>
+                    <i class="iclosebtn" @click="searchClear">
+                        <svg class="Abilityicon" aria-hidden="true">
+                            <use xlink:href="#icon-guanbi-quxiao-guanbi"></use>
+                        </svg>
+                    </i>
+                </div>
+                <div class="close-icon" @click="models='default'">
+                    <svg class="closelog-icon-repetition" aria-hidden="true">
+                        <use xlink:href="#icon-cuowuguanbiquxiao-yuankuang"></use>
+                    </svg>
+                </div>
             </div>
         </div>
         <div class="recordbox">
-            <el-table ref="multipleTableRef" :data="tableData" style="width: 100%" @selection-change="handleSelectionChange">
+            <el-table ref="multipleTableRef" :data="tableData" style="width: 100%" @selection-change="handleSelectionChange" empty-text='暂无数据'>
                 <el-table-column prop="index" label="编号" sortable align="center" />
                 <el-table-column property="name" label="操作人姓名" align="center" />
                 <el-table-column property="tmdId" label="tmdId" align="center" />
@@ -26,12 +69,24 @@
 </template>
 <script>
 import { getCurrentInstance, ref } from 'vue'
+import { Search } from '@element-plus/icons-vue'
 export default {
     setup() {
         let { proxy } = getCurrentInstance()
         let tableData = ref([])
         let originalData = ref([])
         let times = ref('')
+        let cities = ref({
+            data: ['BI', 'IES'],
+            citiesValue: ['BI', 'IES'],
+        })
+        let searchKey = ref('')
+        let models = ref('default')
+        let iconGroups = ref([
+            { id: 1, title: '平台选择', icon: '#icon-fenlei', models: 'select' },
+            { id: 2, title: '搜索', icon: '#icon-chaxun', models: 'search' },
+            { id: 3, title: '时间日期选择', icon: '#icon-riqi', models: 'time' },
+        ])
         //获取所有日志内容
         function getLogcontent(startDate, endDate, platform, model) {
             console.log(startDate, endDate, platform, model, '接收的内容')
@@ -63,13 +118,52 @@ export default {
         //日期选择
         function timeChange(val) {
             console.log(val, '时间发生变化')
+            if (!val) {
+                tableData.value = originalData.value
+                return
+            }
             let starTime = ''
             let endTime = ''
             val[0] && val[1] ? ((starTime = val[0]), (endTime = val[1]), getLogcontent(starTime, endTime)) : val === null ? (tableData.value = originalData.value) : ''
             console.log(starTime, endTime, '时间')
         }
+        //平台选择
+        function changePlatform(val) {
+            console.log(val)
+            let presentData = val
+            let filterDatas = []
+            presentData.forEach((item) => {
+                let name = item
+                originalData.value.forEach((items) => {
+                    items.platform === name ? filterDatas.push(items) : ''
+                })
+            })
+            filterDatas.sort(function (a, b) {
+                return a.index - b.index
+            })
+            tableData.value = filterDatas
+        }
+        //搜索
+        function searchkeyword(value) {
+            console.log(value)
+            if (value === '' || value === null || value === undefined) {
+                tableData.value = originalData.value
+                return
+            }
+            let key = value
+            let newdata = originalData.value.filter((item) => {
+                return item.name === key || item.tmdId === key
+            })
+            console.log(newdata, '新数据')
+            tableData.value = newdata
+        }
+        //搜索清除
+        function searchClear() {
+            tableData.value = originalData.value
+            searchKey.value = ''
+        }
         getLogcontent('', '', '', 'init')
-        return { tableData, getLogcontent, exportExcel, times, timeChange }
+        return { tableData, getLogcontent, exportExcel, times, timeChange, cities, changePlatform, Search, searchKey, models, iconGroups, searchkeyword, searchClear }
     },
 }
 </script>
@@ -81,7 +175,7 @@ export default {
 .topbox {
     text-align: left;
     padding-left: 1%;
-    line-height: 20px;
+    line-height: 48px;
     display: flex;
     justify-content: space-between;
 }
@@ -90,8 +184,82 @@ export default {
     padding: 1%;
 }
 .block {
+    display: flex;
     margin-right: 1%;
 }
+.iconGroup {
+    display: flex;
+    margin-right: 2%;
+}
+.block-title {
+    /* margin-top: 2.5%; */
+    line-height: 40px;
+}
+.block-content {
+    line-height: 0px;
+}
+.close-icon {
+    line-height: 20px;
+}
+.block-title,
+.block-content,
+.log-icons,
+.close-icon {
+    display: inline-block;
+}
+.log-icons {
+    line-height: 25px;
+}
+.block-search {
+    width: 100%;
+    position: relative;
+}
+.logicon {
+    width: 1.8em;
+    height: 1.8em;
+    vertical-align: -1em;
+    fill: currentColor;
+    overflow: hidden;
+    margin-right: 5px;
+}
+.iconGroup div {
+    margin-right: 6%;
+}
+.iconGroup div:hover,
+.closelog-icon:hover {
+    cursor: pointer;
+}
+.closelog-icon {
+    width: 1.2em;
+    height: 1.2em;
+    vertical-align: -0.9em;
+    fill: currentColor;
+    overflow: hidden;
+    margin-left: 5px;
+}
+.Abilityicon {
+    width: 1em;
+    height: 1em;
+    vertical-align: -0.3em;
+    fill: currentColor;
+    overflow: hidden;
+}
+.iclosebtn {
+    bottom: 2px;
+    position: absolute;
+    right: 5px;
+}
+.iclosebtn:hover {
+    cursor: pointer;
+}
+.closelog-icon-repetition {
+    width: 1.2em;
+    height: 1.2em;
+    vertical-align: -1.2em;
+    fill: currentColor;
+    overflow: hidden;
+    margin-left: 5px;
+}
 </style>
 <style>
 .recordbox .el-table--fit {

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

@@ -30,7 +30,7 @@
                 </div>
             </div>
             <div class="boxselect" @click="createArea" v-if="PowerShow">
-                <a href="#">
+                <a>
                     <div class="layer">
                         <span></span>
                         <span></span>
@@ -47,7 +47,7 @@
             </div>
         </div>
         <div class="traitfrom">
-            <el-table :data="optionData" style="width: 100%" :highlight-current-row="true" height="74vh" v-loading="loading">
+            <el-table :data="optionData" style="width: 100%" :highlight-current-row="true" height="74vh" v-loading="loading" empty-text='暂无数据'>
                 <el-table-column prop="index" label="编号" type=index sortable align="center" />
                 <el-table-column prop="name" label="名称" align="center" />
                 <el-table-column prop="id" label="ID编码" align="center" />
@@ -494,6 +494,9 @@ export default {
     margin-right: 2%;
     margin-bottom: 1%;
 }
+.boxselect:hover {
+    cursor: pointer;
+}
 .boxselect a {
     text-decoration: none;
     color: #fff;

+ 1 - 1
TEAMModelBI/ClientApp/src/view/teachermanage/manage.vue

@@ -14,7 +14,7 @@
         </el-button>
     </div>
     <div class="manage-table">
-        <el-table :data="tableData.value" style="width: 100%" height="80vh" v-loading="loading" element-loading-text="Loading..." class="customer-table">
+        <el-table :data="tableData.value" style="width: 100%" height="80vh" v-loading="loading" element-loading-text="Loading..." class="customer-table" empty-text='暂无数据'>
             <el-table-column prop="id" label="编号" sortable align="center" />
             <el-table-column label="头像" align="center">
                 <template #default="scope">

+ 4 - 1
TEAMModelBI/ClientApp/src/view/teachermanage/school.vue

@@ -30,7 +30,7 @@
             </div>
         </div>
         <div class="boxselect" @click="createdSchoolbtn" v-if="PowerShow">
-            <a href="#">
+            <a>
                 <div class="layer">
                     <span></span>
                     <span></span>
@@ -603,6 +603,9 @@ export default {
     margin-top: 1%;
     margin-left: 15%;
 }
+.boxselect:hover {
+    cursor: pointer;
+}
 .boxselect a {
     text-decoration: none;
     color: #fff;

+ 1 - 1
TEAMModelBI/ClientApp/src/view/teachermanage/traitmanage.vue

@@ -22,7 +22,7 @@
                     </div>
                 </el-tab-pane>
                 <el-tab-pane label="方案列表">
-                    <el-table :data="abilityProject" :highlight-current-row="true" style="width: 100%">
+                    <el-table :data="abilityProject" :highlight-current-row="true" style="width: 100%" empty-text='暂无数据'>
                         <el-table-column prop="index" label="编号" type=index width="180" align="center" />
                         <el-table-column prop="standardName" label="方案名称" width="260" align="center" />
                         <el-table-column prop="name" label="来源" align="center" />

+ 9 - 6
TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs

@@ -100,7 +100,7 @@ namespace TEAMModelOS.FunctionV4
                             try
                             {
                                 //处理活动中间件
-                                (List<string> classes, List<RMember> members) = await Activity(info, client, _dingDing, sub);
+                                (List<string> classes, List<RGroupList> members) = await Activity(info, client, _dingDing, sub);
                                 //向学生或醍摩豆账号发起通知
                                 #region
                                 //Notice notice = new Notice()
@@ -131,7 +131,8 @@ namespace TEAMModelOS.FunctionV4
                                         int m = 0;
                                         foreach (ExamSubject subject in info.subjects)
                                         {
-                                            string classCode = "";
+                                            string classCode = String.Empty;
+                                            string cname = string.Empty;
                                             if (string.IsNullOrEmpty(info.school) || !info.scope.Equals("school", StringComparison.OrdinalIgnoreCase))
                                             {
                                                 classCode = "ExamClassResult-" + info.creatorId;
@@ -140,6 +141,7 @@ namespace TEAMModelOS.FunctionV4
                                             {
                                                 classCode = "ExamClassResult-" + info.school;
                                             }
+                                            cname = members.Where(m => m.id.Equals(cla)).FirstOrDefault()?.name;
                                             ExamClassResult result = new ExamClassResult
                                             {
                                                 code = classCode,
@@ -150,6 +152,7 @@ namespace TEAMModelOS.FunctionV4
                                                 scope = info.scope
                                             };
                                             result.info.id = cla;
+                                            result.info.name = cname;
                                             List<string> ans = new List<string>();
                                             List<List<string>> anses = new List<List<string>>();
                                             List<List<Details>> marks = new List<List<Details>>();
@@ -197,7 +200,7 @@ namespace TEAMModelOS.FunctionV4
                                                     }
                                                 }
                                                 //result.info.id = classroom.id;
-                                                result.info.name = classroom.name;
+                                                //result.info.name = classroom.name;
                                                 //result.gradeId = classroom.year.ToString();
                                                 //处理班级人数
                                                /* await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(queryText: $"select c.id from c where c.classId = '{classroom.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Base-{info.school}") }))
@@ -254,7 +257,7 @@ namespace TEAMModelOS.FunctionV4
                                                     }
                                                 }
                                             }*/
-                                            ids = members.Select(m => m.id).ToList();
+                                            ids = members.Where(c => c.id.Equals(cla)).SelectMany(m => m.members).Select(g => g.id).ToList();
                                             foreach (string stu in ids)
                                             {
                                                 result.mark.Add(marks);
@@ -528,7 +531,7 @@ namespace TEAMModelOS.FunctionV4
                 await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测作答记录结算异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
             }
         }
-        public static async Task<(List<string> classes,List<RMember> members)> Activity(ExamInfo info, CosmosClient client, DingDing _dingDing, List<string> sub) {
+        public static async Task<(List<string> classes,List<RGroupList> members)> Activity(ExamInfo info, CosmosClient client, DingDing _dingDing, List<string> sub) {
             List<(string pId, List<string> gid)> ps = new List<(string pId, List<string> gid)>();
             if (info.groupLists.Count > 0)
             {
@@ -603,7 +606,7 @@ namespace TEAMModelOS.FunctionV4
                 });
             }
             await ActivityService.SaveStuActivity(client, _dingDing, stuActivities, tmdActivities, null);
-            return (classes, tchList);
+            return (classes, classLists);
         }
 
         public static async Task knowledgeCount(ExamInfo info, ExamSubject subject, DingDing _dingDing, int no, List<ExamClassResult> classResults,

+ 3 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/LessonRecord.cs

@@ -102,6 +102,9 @@ namespace TEAMModelOS.SDK.Models
         /// 不填  ["混合学习","语文教研"]课例类别,tag标签,IES5维护
         /// </summary>
         public List<string> category { get; set; } = new List<string>();
+        /// <summary>
+        /// 0 是否包含视频,1包含视频
+        /// </summary>
         public int hasVideo { get; set; }
         /// <summary>
         /// 

+ 16 - 4
TEAMModelOS.SDK/Models/Cosmos/Teacher/Favorite.cs

@@ -7,16 +7,16 @@ using TEAMModelOS.SDK.Models.Cosmos.Common;
 namespace TEAMModelOS.SDK.Models.Cosmos
 {
     /// <summary>
-    /// 课纲-我喜欢的,我的收藏
+    /// 我喜欢的,我的收藏,可以收藏 试卷,题目,课例,课纲, 资源,活动。
     /// </summary>
     public class Favorite : CosmosEntity
     {
         public Favorite() {
             pk = "Favorite";
             ttl = -1;
+            // id 与fromid 相同
             //code ="Favorite-tmdid"
         }
-        public SyllabusTree node { get; set; }
         /// <summary>
         /// 名称 默认选中节点名称,或者自定义输入名称
         /// </summary>
@@ -28,12 +28,24 @@ namespace TEAMModelOS.SDK.Models.Cosmos
         /// <summary>
         /// 引用来源课纲id
         /// </summary>
-        [Required(ErrorMessage = "引用来源课纲id 必须设置")]
+        [Required(ErrorMessage = "必填")]
         public string fromId { get; set; }
         /// <summary>
         /// 引用来源 课纲Code 分区键
         /// </summary>
-        [Required(ErrorMessage = "引用来源课纲code 必须设置")]
+        [Required(ErrorMessage = "必填")]
         public string fromCode { get; set; }
+        [Required(ErrorMessage = "必填")]
+        public string type { get; set; }
+        /// <summary>
+        /// 数据所有者
+        /// </summary>
+        [Required(ErrorMessage = "必填")]
+        public string owner { get; set; }
+        /// <summary>
+        /// 数据
+        /// </summary>
+        [Required(ErrorMessage = "必填")]
+        public string scope { get; set; }
     }
 }

+ 16 - 0
TEAMModelOS.SDK/Models/Service/Third/Nx/NxModel.cs

@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TEAMModelOS.SDK.Models
+{
+    public class NxModel
+    {
+    }
+    public record NxOauth {
+        public string code { get; set; }
+        public string state { get; set; }
+    }
+}

TEAMModelOS.SDK/Models/Service/Third/ScApisService.cs → TEAMModelOS.SDK/Models/Service/Third/Sc/ScApisService.cs


TEAMModelOS.SDK/Models/Service/Third/ScYxptModel.cs → TEAMModelOS.SDK/Models/Service/Third/Sc/ScYxptModel.cs


+ 10 - 1
TEAMModelOS/ClientApp/src/api/schoolSetting.js

@@ -77,5 +77,14 @@ export default {
     //转让管理员身份
     TransferAdminRole:function (data) {
         return post('/teacher/init/set-teacher-info', data)
-    }
+    },
+    //保存/更新学校基础设置
+    upsertSchoolSetting:function (data) {
+        return post('/school/setting/opt-setting', data)
+    },
+    //查询学校基础设置
+    getSchoolSetting:function (data) {
+        return post('/school/setting/find-id', data)
+    },
+    
 }

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

@@ -64,7 +64,7 @@
 
 			.preview-fail {
 				width: 700px;
-				height: 600px;
+				height: 500px;
 				display: flex;
 				justify-content: center;
 				align-items: center;

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

@@ -175,11 +175,11 @@ export default {
     setErr:'Failed to set up',
     uploadErr:'Failed to upload profile picture',
     deleteGroup:'Delete Group',
-    delGroupContent:'Are you sure to delete',
+    delGroupContent:'Are you sure to delete ',
     setAvatarLabel:'Set Profile Picture',
     classStuErr:'Failure to obtain class list',
-    unGroup:'未分組學生',
-    setGroupName:'請設置組名',
+    unGroup:'Ungrouped student',
+    setGroupName:'Please set the group name',
     
     //NewCusMgt.vue
     schdTable:'Schedule Mode',

+ 5 - 5
TEAMModelOS/ClientApp/src/locale/lang/en-US/evaluation.js

@@ -1,15 +1,15 @@
 export default {
-	saving:'試卷保存中...',
-	choosePageItems:'Select all items in this book',
+	saving:'The exam file is being saved...',
+	choosePageItems:'Select all questions in this page',
 	completeTip:'Please complete the subject, grade and semester data for the current school system first!',
 	canChoose:'choice(s)',
 	importItems:'Import Question',
 	composePaper:'Form Exam File',
 	syncItems:'Synchronize questions to the question bank',
 	syncPoints:'Synchronize key concept points to the school library',
-	toolOpenTip:'已開啟醍摩豆教學助手,可以獲得更好圖文粘貼體驗',
-	toolCloseTip:'檢測到您暫未開啟醍摩豆教學助手,啟動後可獲得更好圖文粘貼體驗',
-	start:'啟動',
+	toolOpenTip:'You have opened the TM Teaching Assistant for a better picture/text paste experience.',
+	toolCloseTip:'You can open the TM Teaching Assistant to get a better picture/text paste experience.',
+	start:'Open',
 	tag:'Tag',
 	summaryText:'Explanatory Text',
 	orderTemp:'Question No. Template',

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

@@ -49,7 +49,7 @@ export default {
         ftType: 'Type:',
         ftMode: 'Method:',
         search: 'Search',
-        taskTips:'您可以發布閱卷任務,將評測作答數據分配給老師進行線上閱卷評分。 ',
+        taskTips:'You can start marking tasks and assign assessment responses data to teachers for online marking.',
         editEndTime:'修改結束時間',
         endTimeHolder:'請設置評測結束時間',
         updOk:'修改成功',

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

@@ -42,6 +42,7 @@ export default {
         fb: 'Facebook',
         google: 'Google',
         wechat: 'WeChat',
+        dingding: '釘釘',
     },
     apiError: {
         text1: ' User name or password incorrect'

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

@@ -4,6 +4,8 @@ export default{
         order: "次",
         part: "分",
         scienceScore: "Technological Interaction Index",
-        TScore: "教学应用",
+        TScore: "Teaching Application",
+       
+        noVideo: "暫沒有視頻資源",
     }
 }

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

@@ -1,5 +1,5 @@
 export default {
-	qrcode: '二維碼貼紙',
+	qrcode: 'QR code stickers',
 	// table title
 	seatNo: 'Seat No.',
 	account: 'Account/Student ID',

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

@@ -39,7 +39,7 @@ export default {
         homework: "Homework",
         vote: "Poll",
         survey: "Survey",
-        wrongTopic: "错题本",
+        wrongTopic: "Incorrectly Answered Question Book",
     },
     state: [
         {
@@ -67,7 +67,7 @@ export default {
     },
     settingView: {
         title: 'Personal Settings',
-        fileError: "获取信息失败",
+        fileError: "Failed to obtain information",
     },
     'tmManagement': {
         'page-title': 'TEAM Model Account Management',
@@ -123,7 +123,7 @@ export default {
             updOk:'Update successfully',
             codeErr:'Incorrect verification code',
             uploadErr:'Failed to upload profile picture',
-            changeFail: "修改失败",
+            changeFail: "Failed to modify",
         },
     },
     preference: {
@@ -259,7 +259,7 @@ export default {
         unFinished: 'Unfinished',
         Fineshed: 'Completed',
         Closed: 'Ended',
-        duration: "时长",
+        duration: "Duration",
     },
     billboard: {
         description: 'Description',
@@ -314,7 +314,7 @@ export default {
         delOk: "Delete",
         delCancel: "Cancel",
         delSuccess: "Deleted successfully",
-        delError: "删除失败",
+        delError: "Failed to delete",
         type: {
             once: "Once",
             day: "Daily",
@@ -602,10 +602,10 @@ export default {
         noCourse: "No course yet",
         baseInfo: 'Basic Information',
         description: 'Course Overview',
-        nameList: "班级名单",
+        nameList: "Classmates Name List",
         classmates: 'Classmates list',
         classmates1: 'TEAM Model List',
-        classRecord: "课堂记录",
+        classRecord: "Lesson Records",
         classID: 'Course Code',
         classTime: 'Class Time',
         classroom: 'Classroom',
@@ -626,16 +626,16 @@ export default {
         noRoom: "Not yet set",
         courseCode: "Course QR Code",
         me: "me",
-        notes: "电子笔记",
+        notes: "E-Note",
         type: {
-            all: "全部",
-            msg: "飞讯",
-            file: "文件",
-            img: "图片",
-            link: "超链接",
-            answer: "即问即答",
-            right: "答对",
-            wrong: "答错",
+            all: "All",
+            msg: "Text",
+            file: "File",
+            img: "Image",
+            link: "Hyperlink",
+            answer: "Pop Quiz",
+            right: "Correct",
+            wrong: "Incorrect",
         },
     },
     'calendar-title': 'Calendar-Second semester of 2020 school year',

+ 16 - 16
TEAMModelOS/ClientApp/src/locale/lang/en-US/syllabus.js

@@ -3,22 +3,22 @@ export default {
 	chooseChapterTip: '請先選擇需要收藏的章節!',
 	chooseVolumeTip: '請選擇已創建的冊別或者新建冊別!',
 	playFailTip: '資源暫不支持播放',
-	shareSyllabus: '分享個人課綱',
-	chooseShareChapter: '選擇分享的章節',
-	allShare: '整冊分享',
-	chooseTeacher: '選擇分享的教師',
-	saveSyllabus: '收藏分享課綱',
-	chooseSaveSyllabus: '選擇要收藏的章節',
-	allSave: '整冊收藏',
-	chooseSavePos: '選擇收藏位置',
-	pos1: '已有冊別',
-	pos2: '新建冊別',
-	chooseVolume: '選擇一個冊別',
-	newVolume: '輸入新冊別名稱',
-	confirmSave: '確認收藏',
-	save: '收藏',
-	ignore: '忽略',
-	delTip1: '冊別已被分享者',
+	shareSyllabus: 'Share Personal Syllabus',
+	chooseShareChapter: 'Select a topic to share',
+	allShare: 'Share the whole book',
+	chooseTeacher: 'Choose the teachers to share with',
+	saveSyllabus: 'Save Shared Syllabus',
+	chooseSaveSyllabus: 'Select the topic to save',
+	allSave: 'Save all',
+	chooseSavePos: 'Select save to where',
+	pos1: 'Existing Book',
+	pos2: 'Create New Book',
+	chooseVolume: 'Select a book',
+	newVolume: 'Enter the new book name',
+	confirmSave: 'Confirm Saving',
+	save: 'Save',
+	ignore: 'Ignore',
+	delTip1: 'Book Shared',
 	download: 'Download',
 	orderUpdateTip: 'Book order has been updated',
 	noSaveShare: 'This topic has not been saved yet. Please save it before operation!',

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

@@ -86,5 +86,5 @@ export default {
         tbColErr2: ',please complete the form information before importing',
         fileReadErr:'Failed to read file'
     },
-    versionLog:'醍摩豆雲平台更新日誌'
+    versionLog:'The updated logs of the TEAM Model Cloud'
 }

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

@@ -65,5 +65,5 @@ export default {
   renameTitle:'Rename',
   fileName:'File Name:',
   sltPeriod:'Please select at least one school system',
-  nameRept:'文件名称重复'
+  nameRept:'File with the same name already exists'
 }

+ 6 - 6
TEAMModelOS/ClientApp/src/locale/lang/en-US/unit.js

@@ -18,10 +18,10 @@ export default {
 	second: 'second(s)',
 	day: 'day(s)',
 	week: 'week(s)',
-	diffTip1: '月前',
-	diffTip2: '周前',
-	diffTip3: '天前',
-	diffTip4: '小時前',
-	diffTip5: '分鐘前',
-	diffTip6: '剛剛',
+	diffTip1: ' month(s) ago',
+	diffTip2: ' week(s) ago',
+	diffTip3: ' day(s) ago',
+	diffTip4: ' hour(s) ago',
+	diffTip5: ' minute(s) ago',
+	diffTip6: 'Now',
 }

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

@@ -25,8 +25,8 @@
     compressImgErr:'Failed to upload compressed image',
     posterOk:'Video cover uploaded successfully',
     posterErr:'Failed to upload video cover',
-    hasExist:'雲端已存在',
-    sltPeriod:'請至少選擇一個學段',
-    sltFile:'請添加文件後上傳',
-    formatWarning:'不支持截取封面和在線播放'
+    hasExist:'Already exists on IES',
+    sltPeriod:'Please select at least one school system',
+    sltFile:'Please add file and upload',
+    formatWarning:' is not supported for video cover screenshot and online playing'
 }

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

@@ -42,6 +42,7 @@ export default {
         fb: 'Facebook',
         google: 'Google',
         wechat: '微信',
+        dingding: '钉钉',
     },
     apiError: {
         text1: '您的账号或密码不正确'

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

@@ -5,5 +5,6 @@ export default{
         part: "分",
         scienceScore: "科技互动指数",
         TScore: "教学应用",
+        noVideo: "暂没有视频资源",
     }
 }

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

@@ -47,7 +47,7 @@ export default {
 	lineTip: '(請輸入1 ~ 20內的整數)',
 	wordCount: '字數',
 	wordTip: '(請輸入100 ~ 2000內的整數)',
-	baseInfo: '配基本資訊項',
+	baseInfo: '配基本資訊項',
 	needTitle: '需要填寫內容',
 	idNumber: '准考證號位數',
 	id: '考號',

+ 2 - 2
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/evaluation.js

@@ -7,8 +7,8 @@ export default {
 	composePaper:'組成試卷',
 	syncItems:'同步試題到題庫',
 	syncPoints:'保存時同步知識點到校本庫',
-	toolOpenTip:'已開啟醍摩豆教學助手,可以獲得更好圖文貼體驗',
-	toolCloseTip:'檢測到您暫未開啟醍摩豆教學助手,啟動後可獲得更好圖文貼體驗',
+	toolOpenTip:'已開啟醍摩豆教學助手,可以獲得更好圖文貼體驗',
+	toolCloseTip:'檢測到您暫未開啟醍摩豆教學助手,啟動後可獲得更好圖文貼體驗',
 	start:'啟動',
 	tag:'標簽',
 	summaryText:'說明文本',

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

@@ -49,7 +49,7 @@ export default {
         ftType: '類型:',
         ftMode: '模式:',
         search: '搜尋',
-        taskTips:'您可以發布閱卷任務,將評測作答數據分配給老師進行線上閱卷評分。 ',
+        taskTips:'您可以發布閱卷任務,將評測作答數據分配給老師進行線上閱卷評分。',
         editEndTime:'修改結束時間',
         endTimeHolder:'請設置評測結束時間',
         updOk:'修改成功',

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

@@ -42,6 +42,7 @@ export default {
         fb: 'Facebook',
         google: 'Google',
         wechat: 'WeChat',
+        dingding: '釘釘',
     },
     apiError: {
         text1: '您的 帳號 或 密碼 不正確'

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

@@ -5,5 +5,6 @@ export default{
         part: "分",
         scienceScore: "科技互動指數",
         TScore: "教學應用",
+        noVideo: "暫沒有視頻資源",
     }
 }

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

@@ -66,7 +66,7 @@ export default {
     openStatus: '狀態',
     enable: '啟用',
     disable: '禁用',
-    webhook: "通知接口配",
+    webhook: "通知接口配",
     authorization: "接口金鑰",
     domainName: "域名",
 	subNews: "訂閱通知接口",

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

@@ -602,7 +602,7 @@ export default {
         noCourse: "暫無課程",
         baseInfo: '基本資訊',
         description: '課程概述',
-        nameList: "班級名單",
+        nameList: "課程名單",
         classmates: '同學名單',
         classmates1: '醍摩豆名單',
         classRecord: "課堂記錄",

+ 7 - 2
TEAMModelOS/ClientApp/src/utils/public.js

@@ -6,6 +6,7 @@ import JSZip from "jszip";
 import QRCode from 'qrcodejs2'
 import JsPDF from 'jspdf'
 import domtoimage from '@/utils/dom_to_image';
+import excel from '@/utils/excel.js'
 import {
 	app
 } from '@/boot-app.js'
@@ -201,17 +202,21 @@ export default {
 			document.webkitExitFullscreen();
 		}
 	},
+	exportTable(params){
+		excel.export_array_to_excel(params)
+	},
 	/* 根据最新服务器时间获取当前所在学期的起止时间戳 */
 	getSemesterTimeRange() {
 		let curServerTime = localStorage.getItem('serverTime') // 服务器时间
+		let curPeriod = store.state.user.curPeriod
+		let settingSemesters = curPeriod.semesters // 基础设置的学期数据
 		// 如果没有记录到服务器时间或者学期数据,则默认查全部
-		if (!curServerTime || !store.state.user.curPeriod) {
+		if (!curServerTime || !curPeriod || !curPeriod.semesterCount) {
 			return {
 				st: null,
 				et: null
 			}
 		} else {
-			let settingSemesters = store.state.user.curPeriod.semesters // 基础设置的学期数据
 			let settingRange = this.getSettingTermRange(settingSemesters) // 获取设置学期对应的月和日
 			let serverTimeArr = this.formatTime(curServerTime, 'MM-dd').split('-') // 获取当前服务器时间的月和日
 			let curSemeterIndex = this.getCurSemesterIndex(settingSemesters, settingRange, serverTimeArr) // 获取当前学期的序号

+ 1 - 1
TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue

@@ -136,7 +136,7 @@
 				tags: [], //试卷标签
 				curMode: 'paper',
 				isGeneratePaper: false, //是否组成试卷
-				isSaveToBank: true, //是否保存到题库
+				isSaveToBank: false, //是否保存到题库
 				isSavePoints: false, //是否同步导入的知识点到校本知识点库
 				split1: 0.2,
 				isLoading: false,

+ 19 - 7
TEAMModelOS/ClientApp/src/view/homepage/HomePage.less

@@ -68,11 +68,8 @@
     box-shadow: 0 0 10px 2px var(--card-shadow);
     padding: 25px 20px;
     position: relative;
-    // margin-right: 2%;
     margin-bottom: 30px;
-    // height: 380px;
-    // width: 25%;
-    width: 100%;
+    width: 30%;
     min-width: 200px;
     background: white;
 }
@@ -81,16 +78,25 @@
     left: 20px;
     top: 20px;
 }
+@media screen and (max-width: 1400px){
+    .train-chart-box{
+        width: 100% !important;
+        margin-right: 0px !important;
+    }
+    .ac-count-box{
+        width: 100%;
+    }
+}
 .train-chart-box{
     border-radius: 5px;
     box-shadow: 0 0 10px 2px var(--card-shadow);
-    // width: 71%;
-    width: 100%;
+    width: ~"calc(70% - 15px)";
+    margin-right: 15px;
     min-width: 500px;
     height: fit-content;
     padding: 25px 20px;
     position: relative;
-    margin-bottom: 30px;
+    margin-bottom: 15px;
     background: white;
 }
 .train-hour-wrap{
@@ -179,6 +185,10 @@
     height: 170px;
     margin: 10px 0px;
 }
+.platform-list-wrap{
+    height: 340px;
+    margin: 10px 0px;
+}
 .in-pro-ac-item {
     width: 100%;
     color: @second-textColor;
@@ -320,6 +330,8 @@
     border-top: 1px dashed var(--border-color);
     padding-top: 30px;
     padding-left: 30px;
+    margin-top: 5px;
+    padding-bottom: 10px;
     column-count: 3;
     .train-count-item{
         width: fit-content;

+ 110 - 78
TEAMModelOS/ClientApp/src/view/homepage/HomePage.vue

@@ -8,8 +8,21 @@
                     <div class="cus-table-box">
                         <MinTable @tmwCus="getTmwCus"></MinTable>
                     </div>
+                    <!-- 第三方平台连接 -->
+                    <div class="recent-box" style="height:389px" v-if="checkHost()">
+                        <p class="text-title">{{$t('platform.ptText')}}</p>
+                        <div class="platform-list-wrap">
+                            <vuescroll>
+                                <EmptyData v-show="!platformList.length"></EmptyData>
+                                <div class="platform-item" v-for="(item,index) in platformList" :key="index" @click="openPlatform(index)">
+                                    <div class="platform-img" :style="{backgroundImage: `url(${item.thum + '?' + areaSas})`}"></div>
+                                    <p class="platform-name">{{item.name}}</p>
+                                </div>
+                            </vuescroll>
+                        </div>
+                    </div>
                     <!-- 活动统计 -->
-                    <div class="ac-count-box">
+                    <div class="ac-count-box" v-else style="width:100%">
                         <p class="chart-title">
                             {{$t('home.acCount')}}
                         </p>
@@ -18,13 +31,7 @@
                 </div>
                 <div class="chart-box-column2">
                     <!-- 课堂数据 -->
-                    <div class="class-chart-box" v-show="$store.state.config.srvAdrType != 'product'">
-                        <!-- <p class="chart-title">
-                            {{$t('home.classData')}}
-                            <span style="color: var(--normal-icon-color);margin-left: 6px;font-size: 12px;">
-                                ({{$t('system.preview')}})
-                            </span>
-                        </p> -->
+                    <div class="class-chart-box" v-if="checkHost()">
                         <div class="cus-count-wrap">
                             <div class="cus-count-item">
                                 <p class="tag-label">{{$t('home.cusTotal')}}</p>
@@ -53,65 +60,72 @@
                             <!-- 科技分占比 -->
                             <ScoreCount :scoreCount="scoreCount"></ScoreCount>
                         </div>
-
-                        <!-- <div style="width:45%;padding-top:15px">
-                            <TeachScore class="class-chart"></TeachScore>
-                        </div> -->
                     </div>
-                    <!-- 研修数据 -->
-                    <div class="train-chart-box" v-show="$store.state.config.srvAdr == 'China'">
-                        <p class="chart-title">
-                            研修统计
-                        </p>
-                        <!-- 学时统计 -->
-                        <div class="train-hour-wrap">
-                            <!-- 总学时 -->
-                            <div class="train-hour-box">
-                                <i-circle :stroke-color="strokeColor" :percent="allPercent" :stroke-width="8" :trail-width="8" :size="180">
-                                    <span class="complete-hour">{{teacherInfo.totalTime || 0}}</span>
-                                    <span style="font-size:24px">/{{settings.allTime || 0}}</span>
-                                    <p class="total-hour-label">
-                                        {{ $t("jyzx.homePage.totalTime") }}
-                                        <Tooltip :max-width="400" transfer>
-                                            <Icon type="ios-alert" size="15" />
-                                            <div slot="content">
-                                                <div>
-                                                    {{ $t("jyzx.homePage.remarks1") }}
-                                                </div>
-                                                <div>
-                                                    {{ $t("jyzx.homePage.remarks2") }}
-                                                </div>
-                                                <div>
-                                                    {{ $t("jyzx.homePage.remarks3") }}{{ settings.lessonMinutes}}{{ $t("jyzx.homePage.remarks4") }}
+                    <!-- 研修数据 && 活动统计-->
+                    <div style="display: flex;">
+                        <!-- 研修数据 -->
+                        <div class="train-chart-box" :style="{width:!checkHost() ? '100%' : 'calc(70% - 15px)',marginRight:!checkHost() ? '0px' : '15px'}" v-show="$store.state.config.srvAdr == 'China'">
+                            <p class="chart-title">
+                                {{$t('system.menu.trainCount')}}
+                            </p>
+                            <!-- 学时统计 -->
+                            <div class="train-hour-wrap">
+                                <!-- 总学时 -->
+                                <div class="train-hour-box">
+                                    <i-circle :stroke-color="strokeColor" :percent="allPercent" :stroke-width="8" :trail-width="8" :size="160">
+                                        <span class="complete-hour">{{teacherInfo.totalTime || 0}}</span>
+                                        <span style="font-size:24px">/{{settings.allTime || 0}}</span>
+                                        <p class="total-hour-label">
+                                            {{ $t("jyzx.homePage.totalTime") }}
+                                            <Tooltip :max-width="400" transfer>
+                                                <Icon type="ios-alert" size="15" />
+                                                <div slot="content">
+                                                    <div>
+                                                        {{ $t("jyzx.homePage.remarks1") }}
+                                                    </div>
+                                                    <div>
+                                                        {{ $t("jyzx.homePage.remarks2") }}
+                                                    </div>
+                                                    <div>
+                                                        {{ $t("jyzx.homePage.remarks3") }}{{ settings.lessonMinutes}}{{ $t("jyzx.homePage.remarks4") }}
+                                                    </div>
                                                 </div>
-                                            </div>
-                                        </Tooltip>
-                                    </p>
-                                </i-circle>
-                            </div>
-                            <!-- 学时详情 -->
-                            <div class="hour-detail-box">
-                                <div class="hour-detail-item">
-                                    <HourDetail class="hour-detail-chart" :hourInfo="onlineInfo"></HourDetail>
-                                    <HourDetail class="hour-detail-chart" :hourInfo="offlineInfo"></HourDetail>
+                                            </Tooltip>
+                                        </p>
+                                    </i-circle>
                                 </div>
-                                <div class="hour-detail-item">
-                                    <HourDetail class="hour-detail-chart" :hourInfo="verifyInfo"></HourDetail>
-                                    <HourDetail class="hour-detail-chart" :hourInfo="videoInfo"></HourDetail>
+                                <!-- 学时详情 -->
+                                <div class="hour-detail-box">
+                                    <div class="hour-detail-item">
+                                        <HourDetail class="hour-detail-chart" :hourInfo="onlineInfo"></HourDetail>
+                                        <HourDetail class="hour-detail-chart" :hourInfo="offlineInfo"></HourDetail>
+                                    </div>
+                                    <div class="hour-detail-item">
+                                        <HourDetail class="hour-detail-chart" :hourInfo="verifyInfo"></HourDetail>
+                                        <HourDetail class="hour-detail-chart" :hourInfo="videoInfo"></HourDetail>
+                                    </div>
                                 </div>
                             </div>
-                        </div>
-                        <!-- 活动数量统计 -->
-                        <div class="train-count-wrap" v-show="this.$store.state.config.srvAdrType == 'product'">
-                            <div class="train-count-item" v-for="(item,index) in trainCountList" :key="index">
-                                <img :src="item.img" class="train-count-img" alt="">
-                                <div class="train-count-info">
-                                    <p class="count-label">{{item.text}}</p>
-                                    <p class="count-num">{{`${item.complete}/${item.total}`}}</p>
+                            <!-- 活动数量统计 -->
+                            <div class="train-count-wrap" v-show="!checkHost()">
+                                <div class="train-count-item" v-for="(item,index) in trainCountList" :key="index">
+                                    <img :src="item.img" class="train-count-img" alt="">
+                                    <div class="train-count-info">
+                                        <p class="count-label">{{item.text}}</p>
+                                        <p class="count-num">{{`${item.complete}/${item.total}`}}</p>
+                                    </div>
                                 </div>
                             </div>
                         </div>
+                        <!-- 活动统计 -->
+                        <div class="ac-count-box" v-if="checkHost()">
+                            <p class="chart-title">
+                                {{$t('home.acCount')}}
+                            </p>
+                            <AcCountPie style="margin-top:-20px;" :count="acCount"></AcCountPie>
+                        </div>
                     </div>
+
                 </div>
             </div>
             <div class="text-box">
@@ -160,27 +174,14 @@
                         </vuescroll>
                     </div>
                 </div>
-                <!-- 最近课堂记录 现在没有数据,暂时换成第三方平台连接-->
-                <!-- <div class="recent-box">
+                <!-- 最近课堂记录-->
+                <div class="recent-box">
                     <p class="text-title">{{$t('home.recentRecord')}}</p>
                     <div class="recent-list-wrap">
                         <vuescroll>
                             <EmptyData :textContent="$t('home.noRecord')"></EmptyData>
                         </vuescroll>
                     </div>
-                </div> -->
-                <!-- 第三方平台连接 -->
-                <div class="recent-box">
-                    <p class="text-title">{{$t('platform.ptText')}}</p>
-                    <div class="recent-list-wrap">
-                        <vuescroll>
-                            <EmptyData v-show="!platformList.length"></EmptyData>
-                            <div class="platform-item" v-for="(item,index) in platformList" :key="index" @click="openPlatform(index)">
-                                <div class="platform-img" :style="{backgroundImage: `url(${item.thum + '?' + areaSas})`}"></div>
-                                <p class="platform-name">{{item.name}}</p>
-                            </div>
-                        </vuescroll>
-                    </div>
                 </div>
             </div>
         </vuescroll>
@@ -316,7 +317,7 @@ export default {
         }
     },
     methods: {
-        openPlatform(index){
+        openPlatform(index) {
             window.open(this.platformList[index].url)
         },
         //查看课堂记录统计数据
@@ -489,7 +490,27 @@ export default {
                 path: '/home/settings'
             })
         },
-        //查询资源文件
+        // 查询学校资源平台
+        getSchoolSetting() {
+            let params = {
+                schoolId: this.$store.state.userInfo.schoolCode
+            }
+            this.$api.schoolSetting.getSchoolSetting(params).then(
+                res => {
+                    if (res.setting?.third) {
+                        let d = res.setting.third.find(item => item.tag == 'default')
+                        if (d) {
+                            this.platformList.push(...d.links)
+                        }
+                        // this.schoolPlatform = d || this.schoolPlatform
+                    }
+                },
+                err => {
+
+                }
+            )
+        },
+        //查询区级资源平台
         getAreaSource() {
             let params = {
                 areaId: sessionStorage.getItem('areaId')
@@ -503,7 +524,10 @@ export default {
                     } else if (!res.error && res.file) {
                         if (res.file.third) {
                             let d = res.file.third.find(item => item.tag == 'default')
-                            this.platformList = d.links || this.platformList
+                            if (d) {
+                                this.platformList.push(...d.links)
+                            }
+                            // this.platformList = d.links || this.platformList
                         }
                         this.fullData = res.file
                     }
@@ -553,13 +577,21 @@ export default {
             ).finally(() => {
                 this.isLoading = false
             })
-        }
+        },
+        //判断金牛区
+        checkHost() {
+            let host = window.location.host
+            return host !== 'jinniu.teammodel.cn'
+        },
     },
     created() {
         this.areaSas = this.$store.state.user.userProfile.osblob_sas
         this.getAreaSource()
+        this.getSchoolSetting()
         this.getAcCount()
-        this.getTeacherRecordData()
+        if (this.checkHost()) {
+            this.getTeacherRecordData()
+        }
         if (this.$store.state.userInfo.hasSchool) {
             this.findNotice()
             if (this.$store.state.config.srvAdr == 'China') {

+ 1 - 1
TEAMModelOS/ClientApp/src/view/homepage/TechScore.vue

@@ -157,7 +157,7 @@ export default {
     watch: {
         tScore: {
             handler(n, o) {
-                if (n) {
+                if (n || n == 0) {
                     this.$nextTick(() => {
                         if (!this.techScoreGau) {
                             this.techScoreGau = this.$echarts.init(document.getElementById('tech-score'))

+ 0 - 34
TEAMModelOS/ClientApp/src/view/homepage/WeekCount.vue

@@ -116,40 +116,6 @@ export default {
 
                     }],
                     series: [
-                        // {
-                        //     name: "课例总数",
-                        //     type: "line",
-                        //     symbolSize: 10,
-                        //     symbol: 'circle',
-                        //     smooth: false,
-                        //     itemStyle: {
-                        //         color: "#6f7de3",
-                        //     },
-                        //     lineStyle: {
-                        //         normal: {
-                        //             color: "#6f7de3",
-                        //             type: 'dashed'
-                        //         },
-                        //     },
-                        //     markPoint: {
-                        //         label: {
-                        //             normal: {
-                        //                 textStyle: {
-                        //                     color: '#fff'
-                        //                 }
-                        //             }
-                        //         },
-                        //         data: [{
-                        //             type: 'max',
-                        //             name: '最大值',
-
-                        //         }, {
-                        //             type: 'min',
-                        //             name: '最小值'
-                        //         }]
-                        //     },
-                        //     data: this.getRandomArr(200, 400),
-                        // }, 
                         {
                             name: this.$t('home.tThan80'),
                             type: "line",

+ 24 - 0
TEAMModelOS/ClientApp/src/view/homework/ManageHomeWork.vue

@@ -70,6 +70,10 @@
 							<span>{{ $t('homework.voteResult') }}</span>
 							<div class="hw-box-header-tools">
 								<div>
+									<span style="margin-right: 10px;cursor: pointer;"  @click="exportTable">
+										<Icon type="md-download" size="18" />
+										导出数据
+									</span>
 									<span class="hw-box-header-tools-tool" @click="isShowDetail = true">
 										<Icon type="md-information-circle" size="18" />
 										{{ $t('homework.voteDetails') }}
@@ -198,6 +202,26 @@
 			}
 		},
 		methods: {
+			/* 导出表格 */
+			exportTable(){
+				const params = {
+					title: [this.$t('homework.table.name'),this.$t('stuAccount.account'),this.$t('homework.table.className'),this.$t('homework.table.submitTime'),this.$t('homework.table.columnScore'),this.$t('homework.table.columnComment')],
+					key: ['username','userid','className','submitTime','score','comment'],
+					data: this.tableData.map(i => {
+						return {
+							username:i.username,
+							userid:i.userid,
+							className:i.classes[0].name,
+							submitTime:i.submit ? this.$tools.formatTime(i.submitTime,'yyyy-MM-dd hh:mm') : '-',
+							score:i.score === -1 ? '-' : i.score,
+							comment:i.replies.length ? params.row.replies[0] : '—'
+						}
+					}),
+					autoWidth: true,
+					filename: `【${this.currentVote.name}】${this.$t('homework.table.submitDetail')}`
+				}
+				this.$tools.exportTable(params)
+			},
 			/* 保存活动 */
 			doSave() {
 				this.isBtnLoading = true

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

@@ -135,10 +135,12 @@
             <Divider class="login-divider">{{$t('login.communy.title')}}</Divider>
             <div class="other-login-box" style="margin-top:0px">
                 <!-- 钉钉暂时不加 -->
-                <!-- <div class="other-login-item" @click="oauthLogin('dingding')">
-                    <Icon custom="iconfont icon-dingding" class="other-login-icon" />
-                    <p class="other-login-text">DingDing</p>
-                </div> -->
+                <div class="other-login-item" @click="oauthLogin('dingding')" v-if="isDev && srvAdr == 'China'">
+                    <Icon custom="iconfont icon-dingding"   class="other-login-icon" />
+                    <p class="other-login-text">
+                        {{$t('login.communy.dingding')}}
+                    </p>
+                </div>
                 <!-- facebook -->
                 <div class="other-login-item" @click="oauthLogin('facebook')" v-if="srvAdr == 'Global'">
                     <Icon type="logo-facebook" class="other-login-icon" />
@@ -155,7 +157,7 @@
                 </div>
                 <!-- 微信 -->
                 <div class="other-login-item" @click="oauthLogin('wechat')" v-if="srvAdr == 'China'">
-                    <Icon custom="iconfont icon-wechat" color="#01c923" class="other-login-icon" />
+                    <Icon custom="iconfont icon-wechat" class="other-login-icon" />
                     <p class="other-login-text">
                         {{$t('login.communy.wechat')}}
                     </p>
@@ -283,7 +285,10 @@ export default {
             let flag = false
             if (this.loginForm.id && this.loginForm.pass) flag = true
             return flag
-        }
+        },
+        isDev() {
+            return process.env.NODE_ENV == 'development'
+        },
     },
     created() {
         // 此頁面為老師頁面

+ 142 - 27
TEAMModelOS/ClientApp/src/view/mgtPlatform/MgtPlatform.vue

@@ -2,21 +2,39 @@
     <div class="mgt-platform-container">
         <vuescroll>
             <div class="platform-list-wrap">
-                <div class="platform-item" v-for="(item,index) in platformList.links" :key="index" @click="openThirdPlatform(index)">
-                    <span class="delete-platform-icon" @click.stop="delPlatform(index)" v-show="isArea">
+                <!-- 区级资源平台 -->
+                <div class="platform-item" v-for="(item,index) in areaPlatform.links" :key="item.name" @click="openAreaPlatform(index)">
+                    <span class="platform-type-label">
+                        {{$t('train.mgt.areaLabel')}}
+                    </span>
+                    <span class="delete-platform-icon" @click.stop="delAreaPlatform(index)" v-show="isArea">
+                        <Icon type="md-close" class="add-member-icon" />
+                    </span>
+                    <div class="platform-img" :style="{backgroundImage: `url(${item.thum + '?' + areaSas})`}"></div>
+                    <p class="img-text">
+                        <span>{{$t('platform.platform')}}</span>
+                        {{item.name}}
+                    </p>
+                </div>
+                <!-- 校级资源平台 -->
+                <div class="platform-item" v-for="(item,index) in schoolPlatform.links" :key="item.name" @click="openSchoolPlatform(index)">
+                    <span class="delete-platform-icon" @click.stop="delSchoolPlatform(index)" v-show="!isArea">
                         <Icon type="md-close" class="add-member-icon" />
                     </span>
+                    <span class="platform-type-label school-type">
+                        {{$t('train.mgt.schoolLabel')}}
+                    </span>
                     <div class="platform-img" :style="{backgroundImage: `url(${item.thum + '?' + areaSas})`}"></div>
                     <p class="img-text">
                         <span>{{$t('platform.platform')}}</span>
                         {{item.name}}
                     </p>
                 </div>
-                <div class="add-platform-box" @click="addStatus = true" v-show="platformList.links.length && isArea">
+                <div class="add-platform-box" @click="addStatus = true" v-show="areaPlatform.links.length">
                     <Icon type="md-add-circle" class="add-platform-icon" />
                     <p class="add-platform-text">{{$t('platform.addPlatform')}}</p>
                 </div>
-                <div v-show="!platformList.links.length" style="margin:auto">
+                <div v-show="!areaPlatform.links.length" style="margin:auto">
                     <EmptyData :textContent="$t('platform.noPlatform')" :top="120"></EmptyData>
                     <p class="add-platform" v-show="isArea" @click="addStatus = true">
                         <Icon type="md-add" />
@@ -73,7 +91,11 @@ export default {
         return {
             areaSas: '',
             fullData: {},
-            platformList: {
+            areaPlatform: {
+                tag: 'default',
+                links: []
+            },
+            schoolPlatform: {
                 tag: 'default',
                 links: []
             },
@@ -99,21 +121,24 @@ export default {
         }
     },
     methods: {
-        openThirdPlatform(index) {
-            window.open(this.platformList.links[index].url)
+        openAreaPlatform(index) {
+            window.open(this.areaPlatform.links[index].url)
+        },
+        openSchoolPlatform(index) {
+            window.open(this.schoolPlatform.links[index].url)
         },
-        delPlatform(index) {
+        delAreaPlatform(index) {
             this.$Modal.confirm({
                 title: this.$t('platform.delTitle'),
-                content: `${this.$t('platform.delContent')}${this.platformList.links[index].name}?`,
+                content: `${this.$t('platform.delContent')}${this.areaPlatform.links[index].name}?`,
                 onOk: () => {
-                    this.platformList.links.splice(index, 1)
-                    this.fullData.third = [this.platformList]
+                    this.areaPlatform.links.splice(index, 1)
+                    this.fullData.third = [this.areaPlatform]
                     this.$api.ability.upsertResAndPolicy(this.fullData).then(
                         res => {
                             this.$Message.success(this.$t('platform.delOk'))
                             this.fullData = res.file
-                            this.platformList = this.fullData.third.find(item => item.tag == 'default')
+                            this.areaPlatform = this.fullData.third.find(item => item.tag == 'default')
                             this.addStatus = false
                         },
                         err => {
@@ -122,7 +147,28 @@ export default {
                     )
                 }
             })
-
+        },
+        delSchoolPlatform(index) {
+            this.$Modal.confirm({
+                title: this.$t('platform.delTitle'),
+                content: `${this.$t('platform.delContent')}${this.schoolPlatform.links[index].name}?`,
+                onOk: () => {
+                    this.schoolPlatform.links.splice(index, 1)
+                    let params = {
+                        schoolId: this.$store.state.userInfo.schoolCode,
+                        opt: 'UpsertThird',
+                        third: [this.schoolPlatform]
+                    }
+                    this.$api.schoolSetting.upsertSchoolSetting(params).then(
+                        res => {
+                            this.$Message.success(this.$t('platform.delOk'))
+                        },
+                        err => {
+                            this.$Message.error(this.$t('platform.delErr'))
+                        }
+                    )
+                }
+            })
         },
         uploadPoster(file) {
             console.log(file)
@@ -137,7 +183,7 @@ export default {
                 return false
             }
             let regRule = /[`~!@#$%^&*()\-+=<>?:"{}|,\/;'\\[\]·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、]/g
-            if(regRule.test(file.name)){
+            if (regRule.test(file.name)) {
                 this.$Message.error(this.$t('platform.chartErr'))
                 return false
             }
@@ -181,7 +227,7 @@ export default {
                     } else if (!res.error && res.file) {
                         if (res.file.third) {
                             let d = res.file.third.find(item => item.tag == 'default')
-                            this.platformList = d || this.platformList
+                            this.areaPlatform = d || this.areaPlatform
                         }
                         this.fullData = res.file
                     }
@@ -194,19 +240,42 @@ export default {
         confirmAdd() {
             this.$refs['platform'].validate((valid) => {
                 if (valid) {
-                    this.platformList.links.push(this._.cloneDeep(this.platform))
-                    this.fullData.third = [this.platformList]
-                    this.$api.ability.upsertResAndPolicy(this.fullData).then(
-                        res => {
-                            this.$Message.success(this.$t('platform.saveOk'))
-                            this.fullData = res.file
-                            this.platformList = this.fullData.third.find(item => item.tag == 'default')
-                            this.addStatus = false
-                        },
-                        err => {
-                            this.$Message.error(this.$t('platform.saveErr'))
+                    //区级管理
+                    if (this.isArea) {
+                        this.areaPlatform.links.push(this._.cloneDeep(this.platform))
+                        this.fullData.third = [this.areaPlatform]
+                        this.$api.ability.upsertResAndPolicy(this.fullData).then(
+                            res => {
+                                this.$Message.success(this.$t('platform.saveOk'))
+                                this.fullData = res.file
+                                this.areaPlatform = this.fullData.third.find(item => item.tag == 'default')
+                                this.addStatus = false
+                                this.$refs['platform'].resetFields()
+                            },
+                            err => {
+                                this.$Message.error(this.$t('platform.saveErr'))
+                            }
+                        )
+                    }
+                    //校级管理
+                    else {
+                        this.schoolPlatform.links.push(this._.cloneDeep(this.platform))
+                        let params = {
+                            schoolId: this.$store.state.userInfo.schoolCode,
+                            opt: 'UpsertThird',
+                            third: [this.schoolPlatform]
                         }
-                    )
+                        this.$api.schoolSetting.upsertSchoolSetting(params).then(
+                            res => {
+                                this.$Message.success(this.$t('platform.saveOk'))
+                                this.addStatus = false
+                                this.$refs['platform'].resetFields()
+                            },
+                            err => {
+                                this.$Message.error(this.$t('platform.saveErr'))
+                            }
+                        )
+                    }
                 } else {
                     this.$Message.error(this.$t('platform.formErr'))
                     this.modalLoading = false
@@ -217,13 +286,34 @@ export default {
             })
         },
         cancelAdd() {
+            this.$refs['platform'].resetFields()
+        },
+        getSchoolSetting() {
+            let params = {
+                schoolId: this.$store.state.userInfo.schoolCode
+            }
+            this.$api.schoolSetting.getSchoolSetting(params).then(
+                res => {
+                    if (res.setting?.third) {
+                        let d = res.setting.third.find(item => item.tag == 'default')
+                        this.schoolPlatform = d || this.schoolPlatform
+                    }
+                },
+                err => {
 
+                }
+            )
         }
     },
     created() {
         this.areaSas = this.$store.state.user.userProfile.osblob_sas
         this.getAreaSource()
     },
+    mounted() {
+        if (!this.isArea) {
+            this.getSchoolSetting()
+        }
+    },
     computed: {
         isArea() {
             let areas = this.$store.state.user.userProfile.areas
@@ -234,6 +324,31 @@ export default {
 }
 </script>
 <style lang="less" scoped>
+.platform-type-label {
+    position: absolute;
+    left: -3px;
+    top: 5px;
+    color: white;
+    font-size: 12px;
+    padding: 2px 5px;
+    z-index: 99;
+    transform: rotate(-45deg);
+    &::after {
+        position: absolute;
+        content: " ";
+        left: -13px;
+        top: -10px;
+        z-index: -1;
+        border-right: 30px solid transparent;
+        border-left: 30px solid transparent;
+        border-bottom: 30px solid #ff9900;
+    }
+}
+.school-type {
+    &::after {
+        border-bottom: 30px solid #19be6b;
+    }
+}
 .mgt-platform-container {
     width: 100%;
     height: 100%;

+ 11 - 3
TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.less

@@ -431,8 +431,7 @@
     vertical-align: text-bottom;
 }
 .record-info{
-    margin-left: 30px;
-    
+    // margin-left: 30px;
 }
 .record-info-value{
     color: #17233d;
@@ -454,4 +453,13 @@
 }
 // .record-poster{
 //     width: 120px;
-// }
+// }
+.info-split{
+    margin: 0px 25px;
+    display: inline-block;
+    width: 1px;
+    height: 12px;
+    margin-top: -7px;
+    background-color: #e8eaec;
+    vertical-align: baseline;
+}

+ 5 - 5
TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue

@@ -144,15 +144,16 @@
                                             </div>
                                             <p slot="title" class="record-name" style="padding-left:10px">{{item.name}}</p>
                                             <div slot="description" style="padding-left:10px;margin-top:10px">
-                                                <Time class="record-time" :time="item.startTime" />
                                                 <span class="record-info">
                                                     <span>{{$t('cusMgt.duration')}}</span>
                                                     <span class="record-info-value">{{handleDuration(item.duration)}}</span>
                                                 </span>
+                                                <span class="info-split"></span>
+                                                <Time class="record-time" :time="item.startTime" />
                                                 <div class="record-action-wrap">
                                                     <!-- <Icon class="action-icon" type="ios-stats" :title="$t('cusMgt.socrateReport')" @click.stop="viewReporte(index)" /> -->
                                                     <!-- <Icon class="action-icon" custom="iconfont icon-hi" :title="$t('cusMgt.elNotes')" @click.stop="viewNote(index)" /> -->
-                                                    <Icon class="action-icon" custom="iconfont icon-video" :title="$t('cusMgt.socrateMv')" @click.stop="viewVideo(item.id)" />
+                                                    <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" />
                                                 </div>
                                             </div>
@@ -561,10 +562,10 @@ export default {
             }
         },
         //查看视频
-        viewVideo(id) {
+        viewVideo(item) {
             this.$router.push({
                 name: 'teachCenter',
-                query: { id }
+                query: { id: item.id, name: item.name }
             })
         },
         //查看电子笔记
@@ -1322,7 +1323,6 @@ export default {
         },
         //查看课堂记录详情
         toClassRecoerd(index) {
-            this.listLoading = true
             this.$router.push({
                 name: 'classRecord',
                 params: {

+ 14 - 2
TEAMModelOS/ClientApp/src/view/teachCenter/TeaResCenter.less

@@ -29,8 +29,10 @@
         position: absolute;
         right: 0;
         bottom: 0;
-        min-width: 100%;
-        min-height: 100%;
+        /* min-width: 100%;
+        min-height: 100%; */
+        width: 100%;
+        height: 100%;
         /* height: auto;
         width: auto; */
         // 禁用单击视频暂停播放
@@ -64,4 +66,14 @@
         background-color: rgba(0, 0, 0, 0.82);
         display: flex;
     }
+
+    .no-video {
+        width: 100%;
+        height: 100%;
+        position: absolute;
+        top: 40%;
+        left: 45%;
+        font-size: 20px;
+        color: #fff;
+    }
 }

+ 29 - 8
TEAMModelOS/ClientApp/src/view/teachCenter/TeaResCenter.vue

@@ -2,12 +2,13 @@
     <div class="father">
         <div class="header">
             <Icon type="ios-arrow-back" @click="backTo" />
-            <span>{{ videoInfo.name }}</span>
+            <span>{{ recordInfo.name }}</span>
             <!-- <Icon type="ios-link" /> -->
         </div>
         <!-- 教研中心 -->
         <video id="video1" class="video-js vjs-default-skin" type="video/mp4">
         </video>
+        <div class="no-video" v-if="noVideo">{{ $t('researchCenter.video.noVideo') }}</div>
     </div>
 </template>
 
@@ -43,12 +44,16 @@ export default {
             option: undefined,
             scienceScore: 80,
             Tscore: 74,
-            videoInfo: {
-                name: "测试视频",
-                url: "https://teammodelstorage.blob.core.chinacloudapi.cn/download/firstVideo1.mp4"
-            },
+            videoInfo: undefined,
+            sokratesRecords: [],
+            recordInfo: undefined,
+            noVideo: false,
         }
     },
+    created () {
+        this.recordInfo = this.$route.query
+        this.getRecord()
+    },
     async mounted () {
         this.dataArr = require('@/static/united.json')
         this.categories = this.dataArr.labels
@@ -83,6 +88,7 @@ export default {
             this.numArr.push(det.length)
         }) */
         let status = await this.getPlayer()
+        console.log(status);
         /* if(status) {
             document.getElementsByClassName("vjs-quartet")[0].style.visibility = "hidden"
             document.getElementsByClassName("vjs-column-chart")[0].style.visibility = "hidden"
@@ -154,9 +160,18 @@ export default {
         this.getOther()
     },
     methods: {
+        getRecord() {
+            let userProfile = this.$store.state.user.userProfile
+            this.videoInfo = `${userProfile.blob_uri}/records/${this.recordInfo.id}/Record/CourseRecord.mp4?${userProfile.blob_sas}`
+            let url = `${userProfile.blob_uri}/records/${this.recordInfo.id}/Sokrates/SokratesRecords.json?${userProfile.blob_sas}`
+            this.$tools.getFile(url).then(res => {
+                this.sokratesRecords = JSON.parse(res)
+            })
+        },
         getPlayer() {
             return new Promise((r, j) => {
                 let options = {
+                    // notSupportedMessage: '此视频暂无法播放,请稍后再试',
                     controls: true,
                     preload: "auto",
                     controlBar: {
@@ -182,7 +197,7 @@ export default {
                         src: ""
                     }],
                 }
-                options.sources[0].src = this.videoInfo.url
+                options.sources[0].src = this.videoInfo
                 var that = this
                 this.player = videojs(document.getElementById("video1"), options, function() {
                     try {
@@ -255,6 +270,12 @@ export default {
                         videojs.registerComponent("cloumn", cloumn)
                         that.player.addChild("cloumn")
 
+                        this.on('error', (e) => {
+                            that.player.errorDisplay.close();   //将错误信息不显示
+                            that.noVideo = true
+                            // 自定义显示方式
+                        })
+
                         // 视频开始播放,记录时间
                         this.on('timeupdate', (e) => {
                             // that.nowTime = document.getElementById("video1").firstChild.currentTime/60
@@ -634,7 +655,7 @@ export default {
         getScore() {
             let scoreEcharts = this.$echarts.init(document.getElementById('Interaction'));
             var that = this
-            var color = new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+            var color = new this.$echarts.graphic.LinearGradient(0, 0, 1, 0, [
                 {
                     offset: 0,
                     color: '#B8E4F0',
@@ -746,7 +767,7 @@ export default {
         getOther() {
             let scoreEcharts = this.$echarts.init(document.getElementById('Teaching'));
             var that = this
-            var color = new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+            var color = new this.$echarts.graphic.LinearGradient(0, 0, 1, 0, [
                 {
                     offset: 0,
                     color: '#B8E4F0',

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

@@ -585,7 +585,7 @@ namespace TEAMModelOS.Controllers
         [ProducesDefaultResponseType]
         [HttpPost("qrcode")]
         //[AuthToken(Roles = "teacher")]
-        public async Task<IActionResult> Qrcode(Favorite request)
+        public async Task<IActionResult> Qrcode(JsonElement request)
         {
             return Ok();
         }

+ 56 - 6
TEAMModelOS/Controllers/Client/HiTeachController.cs

@@ -1078,6 +1078,7 @@ namespace TEAMModelOS.Controllers.Client
 
             var client = _azureCosmos.GetCosmosClient();
             List<ClassStudents> students = new List<ClassStudents>();
+            Dictionary<string, string> irsDic = new Dictionary<string, string>(); //key:學生ID或TMID value:irs號碼
             string container = (grant_type.GetString() .Equals("school")) ? "School" : "Teacher";
             //Case 1 取得stulist成員 (有stulist_id則優先取)
             if (grant_type.GetString().Equals("private")  && string.IsNullOrWhiteSpace(stulist) && !string.IsNullOrWhiteSpace(classId)) //若private,且classId不為空,stulist為空,有可能HiTeach無法判別是若classId還是stulist
@@ -1102,6 +1103,7 @@ namespace TEAMModelOS.Controllers.Client
                                 string stuCode = studentObj.GetProperty("code").ToString();
                                 string stuId = studentObj.GetProperty("id").ToString();
                                 int stuType = studentObj.GetProperty("type").GetInt32();
+                                string irs = studentObj.GetProperty("irs").ToString();
                                 //取得學校班級學生ID表
                                 if (stuType.Equals(2))
                                 {
@@ -1124,6 +1126,11 @@ namespace TEAMModelOS.Controllers.Client
                                 {
                                     tmidList.Add(stuId);
                                 }
+                                //IRS號碼
+                                if (!irsDic.ContainsKey(stuId))
+                                {
+                                    irsDic.Add(stuId, irs);
+                                }
                             }
                         }
                     }
@@ -1135,7 +1142,7 @@ namespace TEAMModelOS.Controllers.Client
                     {
                         string stuCode = $"Base-{stuDicRow.Key}";
                         List<string> stuIdList = stuDicRow.Value;
-                        var queryst = $"SELECT c.id, c.name, null AS no, c.schoolId FROM c WHERE ARRAY_CONTAINS({JsonSerializer.Serialize(stuIdList)}, c.id)";
+                        var queryst = $"SELECT c.id, c.name, null AS no, c.schoolId, c.irs FROM c WHERE ARRAY_CONTAINS({JsonSerializer.Serialize(stuIdList)}, c.id)";
                         await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(queryText: queryst, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey(stuCode) }))
                         {
                             using var json = await JsonDocument.ParseAsync(item.ContentStream);
@@ -1153,7 +1160,7 @@ namespace TEAMModelOS.Controllers.Client
                 List<ClassStudents> tmids = new List<ClassStudents>();
                 if (tmidList.Count > 0)
                 {
-                    var querytmct = $"SELECT c.id, c.name, null AS no, null AS schoolId FROM c WHERE ARRAY_CONTAINS({JsonSerializer.Serialize(tmidList)}, c.id)";
+                    var querytmct = $"SELECT c.id, c.name, null AS no, null AS schoolId, c.irs FROM c WHERE ARRAY_CONTAINS({JsonSerializer.Serialize(tmidList)}, c.id)";
                     await foreach (var itemtm in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(queryText: querytmct, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
                     {
                         using var json = await JsonDocument.ParseAsync(itemtm.ContentStream);
@@ -1173,7 +1180,7 @@ namespace TEAMModelOS.Controllers.Client
             //Case 2 取得班級固定成員 條件:有school_code、有classId、無stulist
             if (!string.IsNullOrWhiteSpace(Convert.ToString(school_code)) && students.Count == 0 && !string.IsNullOrWhiteSpace(classId))
             {
-                var query = $"SELECT c.id, c.name, c.no, c.schoolId, c.groupId, c.groupName FROM c WHERE c.classId = '{classId}'";
+                var query = $"SELECT c.id, c.name, c.no, c.schoolId, c.groupId, c.groupName, c.irs FROM c WHERE c.classId = '{classId}'";
                 await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{school_code}") }))
                 {
                     using var jsonst = await JsonDocument.ParseAsync(item.ContentStream);
@@ -1186,6 +1193,17 @@ namespace TEAMModelOS.Controllers.Client
                     }
                 }
             }
+            //IRS號碼補足
+            for (int i = 0; i < students.Count; i++)
+            {
+                if( string.IsNullOrWhiteSpace(students[i].irs) && irsDic.ContainsKey(students[i].id))
+                {
+                    if(!string.IsNullOrWhiteSpace(irsDic[students[i].id]))
+                    {
+                        students[i].irs = irsDic[students[i].id];
+                    }
+                }
+            }
 
             //取得分組資訊
             List<ClassGroups> groups = new List<ClassGroups>();
@@ -1426,12 +1444,12 @@ namespace TEAMModelOS.Controllers.Client
                             examClassResultUpd.info = examClassResultRow.info;
                             examClassResultUpd.progress = examClassResultRow.progress;
                             examClassResultUpd.studentIds = examClassResultRow.studentIds;
-                            examClassResultUpd.studentAnswers = new List<List<string>>();
+                            examClassResultUpd.studentAnswers = new List<List<string>>(); //學生作答Blob位置
                             examClassResultUpd.studentScores = examClassResultRow.studentScores;
                             examClassResultUpd.scope = examClassResultRow.scope;
                             examClassResultUpd.sum = examClassResultRow.sum;
                         }
-                        //examClassResult.studentAnswers 將學生答案上傳blob後轉換內容為blob路徑   //[2021-7-13 不再對Blob做搬運]
+                        //examClassResult.studentAnswers (1)將學生答案上傳blob後轉換內容為blob路徑   //[2021-7-13 不再對Blob做搬運] (2)將學生答案放入examClassResult.ans
                         if (examClassResultRow.studentIds != null && examClassResultRow.studentIds.Count > 0 && examClassResultRow.studentAnswersArray != null && examClassResultRow.studentAnswersArray.Count > 0)
                         {
                             for (int i = 0; i < examClassResultRow.studentAnswersArray.Count; i++)
@@ -1444,10 +1462,13 @@ namespace TEAMModelOS.Controllers.Client
                                 {
                                     studentAnswerCopyErrFlg = true;
                                 }
+                                //studentAnswers
                                 List<string> studenrAnswerRow = new List<string>();
                                 studenrAnswerRow.Add(blob);
                                 examClassResultUpd.studentAnswers.Add(studenrAnswerRow);
                             }
+                            //examClassResult.ans 將學生答案放入
+                            examClassResultUpd.ans = examClassResultRow.studentAnswersArray;
                         }
                         //批註欄位處理
                         Dictionary<string, string> paperStatusNow = recordPaperInfo.Where((Dictionary<string, string> p) => p.TryGetValue("subjectId", out string paperStatusSubjectId) && paperStatusSubjectId.Equals(subjectId)).FirstOrDefault();
@@ -1507,7 +1528,35 @@ namespace TEAMModelOS.Controllers.Client
                             examClassResultUpd.scope = examClassResultRow.scope;
                             examClassResultUpd.sum = examClassResultRow.sum;
                         }
-                        examClassResultUpd.studentAnswers = examClassResultRow.studentAnswersArray; //[2021-7-13 不再對Blob做搬運 學生答案直接寫入DB]
+                        //學生作答Blob位置[2021-7-13 不再對Blob做搬運 學生答案直接寫入DB]
+                        examClassResultUpd.studentAnswers = examClassResultRow.studentAnswersArray; 
+                        //學生作答答案 (從blob取得學生答案、放入ans欄位)
+                        string targetScope = dbExamInfo.scope; //評測對象 school:校本班級  private:私人課程
+                        var targetBlobContainer = _azureStorage.GetBlobContainerClient(id);
+                        string blobCntr = id;
+                        if (targetScope.Equals("school")) //校本
+                        {
+                            string schoolId = dbExamInfo.school;
+                            blobCntr = schoolId;
+                        }
+                        targetBlobContainer = _azureStorage.GetBlobContainerClient(blobCntr);
+                        if (examClassResultRow.studentAnswersArray.Count > 0)
+                        {
+                            foreach(List<string> studentAnswerBlobPath in examClassResultRow.studentAnswersArray)
+                            {
+                                string stuAnswerBlobPath = studentAnswerBlobPath.FirstOrDefault();
+                                if (stuAnswerBlobPath != null)
+                                {
+                                    StringBuilder builder = new StringBuilder();
+                                    builder.Append("exam").Append("/").Append(stuAnswerBlobPath);
+                                    var Download = await targetBlobContainer.GetBlobClient(builder.ToString()).DownloadAsync();
+                                    var json = await JsonDocument.ParseAsync(Download.Value.Content);
+                                    var Record = json.RootElement.ToObject<List<List<string>>>();
+                                    examClassResultUpd.ans.Add(Record);
+                                }
+                            }
+                        }
+
                         //批註欄位處理
                         Dictionary<string, string> paperStatusNow = recordPaperInfo.Where((Dictionary<string, string> p) => p.TryGetValue("subjectId", out string subjectId) && subjectId.Equals(examClassResultUpd.subjectId)).FirstOrDefault();
                         int itemCount = Convert.ToInt32(paperStatusNow["itemcount"]);
@@ -1573,6 +1622,7 @@ namespace TEAMModelOS.Controllers.Client
             public string schoolId { get; set; }
             public string groupId { get; set; }
             public string groupName { get; set; }
+            public string irs { get; set; }
         }
         public class ClassGroups
         {

+ 17 - 32
TEAMModelOS/Controllers/Both/FavoriteController.cs

@@ -14,13 +14,13 @@ using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Models.Cosmos;
 using TEAMModelOS.SDK.Models.Cosmos.Common;
-
+using TEAMModelOS.SDK;
 
 namespace TEAMModelOS.Controllers
 {
     [ProducesResponseType(StatusCodes.Status200OK)]
     [ProducesResponseType(StatusCodes.Status400BadRequest)]
-    //
+    // 收藏结构
     [Route("teacher/favorite")]
     [ApiController]
     public class FavoriteController: ControllerBase
@@ -38,45 +38,32 @@ namespace TEAMModelOS.Controllers
             _option = option?.Value; 
         }
         /// <summary>
-        /// 保存或更新 
+        /// 保存或更新 收藏
         /// </summary>
         /// <param name="request"></param>
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("upsert")]
         [Authorize(Roles = "IES")]
-        [AuthToken(Roles = "teacher")]
-        public async Task<IActionResult> Upsert(Favorite request)
+        [AuthToken(Roles = "teacher,admin")]
+        public async Task<IActionResult> Upsert(JsonElement data  )
         {
             try
             {
+                if (!data.TryGetProperty("favorite", out JsonElement _favorite)) return BadRequest() ;
+                Favorite request = _favorite.ToObject<Favorite>();
+                var val = request.IsValid();
+                if (!val.isVaild  || string.IsNullOrEmpty(request.id)) {
+                    return BadRequest(val);
+                }
                 var client = _azureCosmos.GetCosmosClient();
                 request.pk = "Favorite";
-                request.code = request.pk + "-" + request.code;
+                request.code = request.code.StartsWith("Favorite-") ? request.code : request.pk + "-" + request.code;
                 request.ttl = -1;
                 long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                 request.createTime = now;
-                if (string.IsNullOrEmpty(request.id))
-                {
-
-                    request.id = Guid.NewGuid().ToString();
-                    request = await client.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync(request, new PartitionKey($"{request.code}"));
-                }
-                else
-                {
-                    var response = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync(request.id, new PartitionKey($"{request.code}"));
-                    if (response.Status == 200)
-                    {
-                        using var json = await JsonDocument.ParseAsync(response.ContentStream);
-                        var info = json.ToObject<Favorite>();
-                        request = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync(request, info.id, new PartitionKey($"{info.code}"));
-                    }
-                    else
-                    {
-                        request = await client.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync(request, new PartitionKey($"{request.code}"));
-                    }
-                }
-                return Ok(new { room = request });
+                request = await client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync(request, new PartitionKey($"{request.code}"));
+                return Ok(new { favorite = request });
             }
             catch (Exception e)
             {
@@ -90,7 +77,7 @@ namespace TEAMModelOS.Controllers
         /// <param name="requert"></param>
         /// <returns></returns>
         [ProducesDefaultResponseType]
-        [AuthToken(Roles = "teacher")]
+        [AuthToken(Roles = "teacher,admin")]
         [HttpPost("find")]
         public async Task<IActionResult> Find(JsonElement request)
         {
@@ -99,7 +86,6 @@ namespace TEAMModelOS.Controllers
                 List<Favorite> favorites = new List<Favorite>();
                 if (!request.TryGetProperty("code", out JsonElement code)) { return BadRequest(); }
                 var client = _azureCosmos.GetCosmosClient();
-              
                 await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<Favorite>(queryText: $"select value(c) from c ",
                 requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Favorite-{code}") }))
                 {
@@ -121,17 +107,16 @@ namespace TEAMModelOS.Controllers
         [ProducesDefaultResponseType]
         [HttpPost("delete")]
         [Authorize(Roles = "IES")]
+        [AuthToken(Roles = "teacher,admin")]
         public async Task<IActionResult> Delete(JsonElement requert)
         {
             try
             {
                 var client = _azureCosmos.GetCosmosClient();
-                //id
                 if (!requert.TryGetProperty("id", out JsonElement id)) return BadRequest();
-                //
                 if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
                 var room = await client.GetContainer(Constant.TEAMModelOS, "Teacher").DeleteItemAsync<Favorite>(id.GetString(), new PartitionKey($"Favorite-{code}"));
-                return Ok();
+                return Ok(new { status=200});
             }
             catch (Exception ex)
             {

+ 104 - 0
TEAMModelOS/Controllers/Third/NxController.cs

@@ -0,0 +1,104 @@
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK.DI;
+using System.Text.Json;
+using TEAMModelOS.SDK.Models;
+using Microsoft.AspNetCore.Http;
+using TEAMModelOS.SDK.Extension;
+using Azure.Cosmos;
+using System.Text;
+using TEAMModelOS.SDK.DI.AzureCosmos.Inner;
+using Microsoft.Extensions.Options;
+using Azure.Messaging.ServiceBus;
+using Microsoft.Extensions.Configuration;
+using HTEXLib.COMM.Helpers;
+using TEAMModelOS.SDK;
+using System.IdentityModel.Tokens.Jwt;
+using TEAMModelOS.Services;
+using TEAMModelOS.SDK.Models.Service;
+using System.IO;
+using System.Dynamic;
+using Microsoft.AspNetCore.Authorization;
+using Azure.Storage.Blobs.Models;
+using static TEAMModelOS.SDK.Models.Teacher;
+using System.Web;
+using static TEAMModelOS.Controllers.FixDataController;
+using static TEAMModelOS.SDK.SchoolService;
+using Microsoft.AspNetCore.Hosting;
+namespace TEAMModelOS.Controllers
+{
+    // <summary>
+    /// 
+    /// </summary>
+    ///  
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+    //
+    //[Route("")]
+    //[Route("api/[controller]")]
+    [ApiController]
+    public class NxController : ControllerBase
+    {
+        private readonly SnowflakeId _snowflakeId;
+        private readonly AzureCosmosFactory _azureCosmos;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+        private readonly AzureStorageFactory _azureStorage;
+        private readonly AzureServiceBusFactory _serviceBus;
+        private readonly AzureRedisFactory _azureRedis;
+        private readonly CoreAPIHttpService _coreAPIHttpService;
+        private readonly ThirdApisService _scsApisService;
+        public readonly string type = "nxedu";
+        private readonly HttpTrigger _httpTrigger;
+        private readonly IWebHostEnvironment _environment;
+        /// <summary>
+        /// 机构安全码
+        /// </summary>
+        public string _sc_passKey;
+        /// <summary>
+        /// 机构ID
+        /// </summary>
+        public string _sc_trainComID;
+        /// <summary>
+        /// 机构 AES 密钥
+        /// </summary>
+        public string _sc_privateKey;
+        /// <summary>
+        /// 访问地址
+        /// </summary>
+        public string _sc_url;
+        public IConfiguration _configuration { get; set; }
+        public NxController(IWebHostEnvironment environment, AzureCosmosFactory azureCosmos, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option, AzureStorageFactory azureStorage,
+          AzureRedisFactory azureRedis, AzureServiceBusFactory serviceBus, IConfiguration configuration, CoreAPIHttpService coreAPIHttpService, ThirdApisService scsApisService, HttpTrigger httpTrigger)
+        {
+            _azureCosmos = azureCosmos;
+            _snowflakeId = snowflakeId;
+            _dingDing = dingDing;
+            _option = option?.Value;
+            _azureStorage = azureStorage;
+            _serviceBus = serviceBus;
+            _configuration = configuration;
+            _azureRedis = azureRedis;
+            _coreAPIHttpService = coreAPIHttpService;
+            _scsApisService = scsApisService;
+            _httpTrigger = httpTrigger;
+            _environment = environment;
+        }
+
+        /// <summary>
+        /// 动态地址路由。"config":"scsyxpt","path":"sc{pjx/jinniu}"
+        /// </summary>D:\VisualStudioProjects\TEAMModelOS\TEAMModelOS.SDK\Models\Service\Third\ScYxptModel.cs
+        /// <param name="request"></param>
+        /// <returns></returns>
+
+        [HttpGet("{path}/oauth2")]
+        [AllowAnonymous]
+        public async Task<IActionResult> Oauth2([FromQuery] NxOauth oauth2, string path) { 
+            return Ok(new { oauth2, path });
+        }
+    }
+}

+ 1 - 1
TEAMModelOS/Controllers/Third/ScController.cs

@@ -30,7 +30,7 @@ using static TEAMModelOS.Controllers.FixDataController;
 using static TEAMModelOS.SDK.SchoolService;
 using Microsoft.AspNetCore.Hosting;
 
-namespace TEAMModelOS.Controllers.Third
+namespace TEAMModelOS.Controllers
 {
 
     /// <summary>

+ 4 - 4
TEAMModelOS/TEAMModelOS.csproj

@@ -31,11 +31,11 @@
     <SpaRoot>ClientApp\</SpaRoot>
     <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
     <UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-    <Version>5.2201.19</Version>
-    <AssemblyVersion>5.2201.19.1</AssemblyVersion>
-    <FileVersion>5.2201.19.1</FileVersion>
+    <Version>5.2201.20</Version>
+    <AssemblyVersion>5.2201.20.1</AssemblyVersion>
+    <FileVersion>5.2201.20.1</FileVersion>
     <Description>TEAMModelOS(IES5)版本更新。</Description>
-    <PackageReleaseNotes>版本说明</PackageReleaseNotes>
+    <PackageReleaseNotes>6.0版本说明</PackageReleaseNotes>
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">