Browse Source

Merge branch 'develop5.0-tmd' of http://106.12.23.251:10080/TEAMMODEL/TEAMModelOS into develop5.0-tmd

zhouj1203@hotmail.com 4 years ago
parent
commit
8bfeaccab9
47 changed files with 3030 additions and 1015 deletions
  1. 16 1
      TEAMModelOS.SDK/Models/Cosmos/School/Class.cs
  2. 1 1
      TEAMModelOS.SDK/Models/Cosmos/School/Inner/Semester.cs
  3. 18 3
      TEAMModelOS.SDK/Models/Cosmos/School/Room.cs
  4. 57 17
      TEAMModelOS/ClientApp/src/assets/iconfont/demo_index.html
  5. 10 8
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.css
  6. BIN
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.eot
  7. 1 1
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.js
  8. 8 1
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.json
  9. 0 350
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.svg
  10. BIN
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.ttf
  11. BIN
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff
  12. BIN
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff2
  13. 10 0
      TEAMModelOS/ClientApp/src/common/BaseLayout.vue
  14. 2 2
      TEAMModelOS/ClientApp/src/common/BaseSelectSchool.vue
  15. 9 0
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseJudge.vue
  16. 9 0
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseMultiple.vue
  17. 9 0
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseSingle.vue
  18. 9 0
      TEAMModelOS/ClientApp/src/components/vote/BaseVoteForm.vue
  19. 255 249
      TEAMModelOS/ClientApp/src/locale/lang/en-US/learnActivity.js
  20. 2 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/system.js
  21. 10 3
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/learnActivity.js
  22. 2 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/system.js
  23. 9 3
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/learnActivity.js
  24. 2 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/system.js
  25. 9 0
      TEAMModelOS/ClientApp/src/router/routes.js
  26. 1 1
      TEAMModelOS/ClientApp/src/view/Home.vue
  27. 3 0
      TEAMModelOS/ClientApp/src/view/learnactivity/MgtSchoolEva.less
  28. 86 18
      TEAMModelOS/ClientApp/src/view/learnactivity/MgtSchoolEva.vue
  29. 18 15
      TEAMModelOS/ClientApp/src/view/learnactivity/markpaper/MarkData.vue
  30. 99 85
      TEAMModelOS/ClientApp/src/view/learnactivity/markpaper/MarkSetting.vue
  31. 9 7
      TEAMModelOS/ClientApp/src/view/learnactivity/markpaper/MarkView.vue
  32. 28 13
      TEAMModelOS/ClientApp/src/view/schoolmgmt/SystemSetting/NewSystemSetting.less
  33. 146 44
      TEAMModelOS/ClientApp/src/view/schoolmgmt/SystemSetting/NewSystemSetting.vue
  34. 462 0
      TEAMModelOS/ClientApp/src/view/student-account/ClassMgt.less
  35. 876 0
      TEAMModelOS/ClientApp/src/view/student-account/ClassMgt.vue
  36. 1 1
      TEAMModelOS/ClientApp/src/view/student-account/ImportStudent.vue
  37. 26 0
      TEAMModelOS/ClientApp/src/view/student-account/Index.less
  38. 246 177
      TEAMModelOS/ClientApp/src/view/student-account/Index.vue
  39. 120 0
      TEAMModelOS/ClientApp/src/view/task/index.less
  40. 153 0
      TEAMModelOS/ClientApp/src/view/task/index.vue
  41. 3 0
      TEAMModelOS/Controllers/Client/HiTeachController.cs
  42. 1 1
      TEAMModelOS/Controllers/Common/CommonController.cs
  43. 2 2
      TEAMModelOS/Controllers/School/ClassRoomController.cs
  44. 168 0
      TEAMModelOS/Controllers/School/RoomController.cs
  45. 4 4
      TEAMModelOS/Controllers/School/SchoolController.cs
  46. 110 1
      TEAMModelOS/Controllers/Syllabus/VolumeController.cs
  47. 20 4
      TEAMModelOS/Controllers/Teacher/InitController.cs

+ 16 - 1
TEAMModelOS.SDK/Models/Cosmos/School/Class.cs

@@ -10,6 +10,9 @@ using TEAMModelOS.SDK.DI;
 
 namespace TEAMModelOS.SDK.Models
 {    
+    /// <summary>
+    /// 班级
+    /// </summary>
     public class Class : CosmosEntity
     {
         public Class()
@@ -19,15 +22,27 @@ namespace TEAMModelOS.SDK.Models
             //students = new List<StudentSimple>();
         }
         /// <summary>
-        /// 教室编号
+        /// 班级编号
         /// </summary>
         public string no { get; set; }
 
        // public float? x { get; set; }
        // public float? y { get; set; }
+       /// <summary>
+       /// 班级名称
+       /// </summary>
         public string name { get; set; }
+        /// <summary>
+        /// 教师
+        /// </summary>
         public Teachers teacher { get; set; }
+        /// <summary>
+        /// 学段
+        /// </summary>
         public string periodId { get; set; }
+        /// <summary>
+        /// 年级
+        /// </summary>
         public string gradeId { get; set; }
         //入学年
         public int year { get; set; }

+ 1 - 1
TEAMModelOS.SDK/Models/Cosmos/School/Inner/Semester.cs

@@ -7,7 +7,7 @@ namespace TEAMModelOS.SDK.Models
     public class Semester
     {
         public string name { get; set; }
-        public string count { get; set; }
+        public int start { get; set; }
         public int month { get; set; }
         public int day { get; set; }
         public string id { get; set; }

+ 18 - 3
TEAMModelOS.SDK/Models/Cosmos/School/Room.cs

@@ -2,14 +2,21 @@ using System;
 using System.Collections.Generic;
 using System.Text;
 
-namespace TEAMModelOS.SDK.Models.Cosmos.School
+namespace TEAMModelOS.SDK.Models.Cosmos
 {
     /// <summary>
-    /// 教室
+    /// 教室,只存在于学校。
     /// </summary>
     public class Room : CosmosEntity
     {
+        public Room(){
+            pk = "Room";
+        }
         public string name { get; set; }
+        /// <summary>
+        /// 教室编号
+        /// </summary>
+        public string no { get; set; }
         public float? x { get; set; }
         public float? y { get; set; }
         public string sn { get; set; }
@@ -17,6 +24,14 @@ namespace TEAMModelOS.SDK.Models.Cosmos.School
         /// 教室属性,普通 /专设的教室
         /// </summary>
         public string openType { get; set; }
-        public string scope { get; set; }
+       // public string scope { get; set; }
+        /// <summary>
+        /// TBL IRS 类型区分
+        /// </summary>
+        public string style { get; set; }
+        /// <summary>
+        /// 
+        /// </summary>
+        public string area { get; set; }
     }
 }

+ 57 - 17
TEAMModelOS/ClientApp/src/assets/iconfont/demo_index.html

@@ -2,7 +2,7 @@
 <html>
 <head>
   <meta charset="utf-8"/>
-  <title>IconFont Demo</title>
+  <title>iconfont Demo</title>
   <link rel="shortcut icon" href="//img.alicdn.com/imgextra/i2/O1CN01ZyAlrn1MwaMhqz36G_!!6000000001499-73-tps-64-64.ico" type="image/x-icon"/>
   <link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01EYTRnJ297D6vehehJ_!!6000000008020-55-tps-64-64.svg"/>
   <link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
@@ -13,10 +13,33 @@
   <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
   <!-- 代码高亮 -->
   <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
+  <style>
+    .main .logo {
+      margin-top: 0;
+      height: auto;
+    }
+
+    .main .logo a {
+      display: flex;
+      align-items: center;
+    }
+
+    .main .logo .sub-title {
+      margin-left: 0.5em;
+      font-size: 22px;
+      color: #fff;
+      background: linear-gradient(-45deg, #3967FF, #B500FE);
+      -webkit-background-clip: text;
+      -webkit-text-fill-color: transparent;
+    }
+  </style>
 </head>
 <body>
   <div class="main">
-    <h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">&#xe86b;</a></h1>
+    <h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
+      <img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
+      
+    </a></h1>
     <div class="nav-tabs">
       <ul id="tabs" class="dib-box">
         <li class="dib active"><span>Unicode</span></li>
@@ -31,6 +54,12 @@
       <div class="content unicode" style="display: block;">
           <ul class="icon_lists dib-box">
           
+            <li class="dib">
+              <span class="icon iconfont">&#xe6ac;</span>
+                <div class="name">做任务</div>
+                <div class="code-name">&amp;#xe6ac;</div>
+              </li>
+          
             <li class="dib">
               <span class="icon iconfont">&#xe629;</span>
                 <div class="name">专业课程</div>
@@ -686,24 +715,20 @@
 
           <p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
           <ul>
-            <li>兼容性最好,支持 IE6+,及所有现代浏览器。</li>
             <li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
-            <li>但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。</li>
+            <li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
           </ul>
           <blockquote>
-            <p>注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式</p>
+            <p>注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
           </blockquote>
           <p>Unicode 使用步骤如下:</p>
           <h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
 <pre><code class="language-css"
 >@font-face {
   font-family: 'iconfont';
-  src: url('iconfont.eot');
-  src: url('iconfont.eot?#iefix') format('embedded-opentype'),
-      url('iconfont.woff2') format('woff2'),
-      url('iconfont.woff') format('woff'),
-      url('iconfont.ttf') format('truetype'),
-      url('iconfont.svg#iconfont') format('svg');
+  src: url('iconfont.woff2?t=1620299264680') format('woff2'),
+       url('iconfont.woff?t=1620299264680') format('woff'),
+       url('iconfont.ttf?t=1620299264680') format('truetype');
 }
 </code></pre>
           <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@@ -729,6 +754,15 @@
       <div class="content font-class">
         <ul class="icon_lists dib-box">
           
+          <li class="dib">
+            <span class="icon iconfont icon-task"></span>
+            <div class="name">
+              做任务
+            </div>
+            <div class="code-name">.icon-task
+            </div>
+          </li>
+          
           <li class="dib">
             <span class="icon iconfont icon-profession"></span>
             <div class="name">
@@ -739,11 +773,11 @@
           </li>
           
           <li class="dib">
-            <span class="icon iconfont icon-Attachment"></span>
+            <span class="icon iconfont icon-general"></span>
             <div class="name">
               通用
             </div>
-            <div class="code-name">.icon-Attachment
+            <div class="code-name">.icon-general
             </div>
           </li>
           
@@ -1709,10 +1743,8 @@
         <p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
         <p>与 Unicode 使用方式相比,具有如下特点:</p>
         <ul>
-          <li>兼容性良好,支持 IE8+,及所有现代浏览器。</li>
           <li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
           <li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
-          <li>不过因为本质上还是使用的字体,所以多色图标还是不支持的。</li>
         </ul>
         <p>使用步骤如下:</p>
         <h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
@@ -1730,6 +1762,14 @@
       <div class="content symbol">
           <ul class="icon_lists dib-box">
           
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-task"></use>
+                </svg>
+                <div class="name">做任务</div>
+                <div class="code-name">#icon-task</div>
+            </li>
+          
             <li class="dib">
                 <svg class="icon svg-icon" aria-hidden="true">
                   <use xlink:href="#icon-profession"></use>
@@ -1740,10 +1780,10 @@
           
             <li class="dib">
                 <svg class="icon svg-icon" aria-hidden="true">
-                  <use xlink:href="#icon-Attachment"></use>
+                  <use xlink:href="#icon-general"></use>
                 </svg>
                 <div class="name">通用</div>
-                <div class="code-name">#icon-Attachment</div>
+                <div class="code-name">#icon-general</div>
             </li>
           
             <li class="dib">

File diff suppressed because it is too large
+ 10 - 8
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.css


BIN
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.eot


File diff suppressed because it is too large
+ 1 - 1
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.js


+ 8 - 1
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.json

@@ -5,6 +5,13 @@
   "css_prefix_text": "icon-",
   "description": "",
   "glyphs": [
+    {
+      "icon_id": "5241258",
+      "name": "做任务",
+      "font_class": "task",
+      "unicode": "e6ac",
+      "unicode_decimal": 59052
+    },
     {
       "icon_id": "5924477",
       "name": "专业课程",
@@ -15,7 +22,7 @@
     {
       "icon_id": "7470974",
       "name": "通用",
-      "font_class": "Attachment",
+      "font_class": "general",
       "unicode": "e6bd",
       "unicode_decimal": 59069
     },

File diff suppressed because it is too large
+ 0 - 350
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.svg


BIN
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.ttf


BIN
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff


BIN
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff2


+ 10 - 0
TEAMModelOS/ClientApp/src/common/BaseLayout.vue

@@ -370,6 +370,16 @@ export default {
                     permission: '',
                     child: [],
                     menuName: 'myCourse'
+                },
+                {
+                    icon: 'iconfont icon-task',
+                    name: this.$t('system.menu.taskList'),
+                    router: '/home/taskList',
+                    tag: '',
+                    role: 'teacher',
+                    permission: '',
+                    child: [],
+                    menuName: 'taskList'
                 }
             ]
         },

+ 2 - 2
TEAMModelOS/ClientApp/src/common/BaseSelectSchool.vue

@@ -2,7 +2,7 @@
 	<div class="base-school-select">
 		<div v-if="!joinSchools || !joinSchools.length">{{ $t('utils.noJoinSchool') }}</div>
 		<Dropdown @on-click="onSchoolSelect" v-else>
-			<img class="school-logo" :src="curSchool.logo || defaultLogo" />
+			<img class="school-logo" :src="curSchool.picture || defaultLogo" />
 			<a href="javascript:void(0)" :class="['base-user-post', joinSchools && joinSchools.length === 1 ? 'single-school' : '']">
 				{{ curSchool.name }}
 				<Icon type="ios-arrow-down"></Icon>
@@ -11,7 +11,7 @@
 				<div v-for="(item,index) in joinSchools" :key="index">
 					<DropdownItem :name="index">
 						<div class="school-item">
-							<img :src="item.logo || defaultLogo" alt="">
+							<img :src="item.picture || defaultLogo" alt="">
 							<span>{{ item.name }}</span>
 						</div>
 					</DropdownItem>

+ 9 - 0
TEAMModelOS/ClientApp/src/components/questionnaire/BaseJudge.vue

@@ -131,6 +131,15 @@
 								this.optionsContent.push(option)
 							}
 						}
+						// 选项编辑器失焦隐藏工具栏
+						editor.config.onblur = function() {
+							let allToolbars = document.getElementsByClassName('qn-option-editor')
+							for (let i = 0; i < allToolbars.length; i++) {
+								if (allToolbars[i].children.length) {
+									allToolbars[i].children[0].style.visibility = 'hidden'
+								}
+							}
+						}
 						editor.create()
 						this.optionEditors.push(editor);
 						this.$refs["singleOption" + newIndex][0].dataset.editorId = editor.id

+ 9 - 0
TEAMModelOS/ClientApp/src/components/questionnaire/BaseMultiple.vue

@@ -130,6 +130,15 @@
 								this.optionsContent.push(option)
 							}
 						}
+						// 选项编辑器失焦隐藏工具栏
+						editor.config.onblur = function() {
+							let allToolbars = document.getElementsByClassName('qn-option-editor')
+							for (let i = 0; i < allToolbars.length; i++) {
+								if (allToolbars[i].children.length) {
+									allToolbars[i].children[0].style.visibility = 'hidden'
+								}
+							}
+						}
 						editor.create()
 						this.optionEditors.push(editor);
 						this.$refs["singleOption" + newIndex][0].dataset.editorId = editor.id

+ 9 - 0
TEAMModelOS/ClientApp/src/components/questionnaire/BaseSingle.vue

@@ -125,6 +125,15 @@
 								this.optionsContent.push(option)
 							}
 						}
+						// 选项编辑器失焦隐藏工具栏
+						editor.config.onblur = function() {
+							let allToolbars = document.getElementsByClassName('qn-option-editor')
+							for (let i = 0; i < allToolbars.length; i++) {
+								if (allToolbars[i].children.length) {
+									allToolbars[i].children[0].style.visibility = 'hidden'
+								}
+							}
+						}
 						editor.create()
 						this.optionEditors.push(editor);
 						this.$refs["singleOption" + newIndex][0].dataset.editorId = editor.id

+ 9 - 0
TEAMModelOS/ClientApp/src/components/vote/BaseVoteForm.vue

@@ -352,6 +352,7 @@
 			optionClick(index) {
 				console.log(index)
 				let allToolbars = document.getElementsByClassName('option-editor')
+				console.log(allToolbars)
 				let that = this
 				for (let i = 0; i < allToolbars.length; i++) {
 					allToolbars[i].children[0].style.visibility = 'hidden'
@@ -401,6 +402,14 @@
 								this.voteOptionsContent.push(option)
 							}
 						}
+						editor.config.onblur = function() {
+							let allToolbars = document.getElementsByClassName('option-editor')
+							for (let i = 0; i < allToolbars.length; i++) {
+								if (allToolbars[i].children.length) {
+									allToolbars[i].children[0].style.visibility = 'hidden'
+								}
+							}
+						}
 						editor.create()
 					})
 				} else {

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

@@ -1,262 +1,268 @@
-export default {
+export default{
     //MgtSchoolEva.vue
-    mgtScEv: {
-        listLabel: '評測清單',
-        period: '學段:',
-        create: '新建',
-        delete: '删除',
-        edit: '編輯',
-        createTime: '施測時間:',
-        pending: '待發佈',
-        going: '進行中',
-        finish: '已結束',
-        endTime: '結束時間:',
-        stop: '立即結束',
-        evType: '測試類型:',
-        stuCount: '施測人數:',
-        nodata: '暫無評測',
-        tab1: '評測數據',
-        tab2: '評測試卷',
-        autoTips1: '此功能僅用於展示情景快速類比學生作答數據,且學生作答為隨機生成,僅供參考!',
-        autoTips2: '此功能僅用於展示情景快速類比教師評分數據,且分數為隨機生成,僅供參考!',
-        autoScore: '一鍵評分',
-        autoAnswer: '一鍵作答',
-        evSubject: '測試科目:',
-        returnTop: '返回頂部',
-        mockOk: '類比成功',
-        mockErr: '類比失敗',
-        stopTitle: '結束評測',
-        stopContent: '結束後學生將不能繼續作答,是否立即結束',
-        stopOk: '評測已結束!',
-        deleteTitle: '删除評測',
-        deleteContent: '是否確認删除',
-        deleteOk: '删除成功',
-        deleteErr: '删除失敗',
-        noJoin: '此帳號暫未加入任何學校!',
-        myEv: '我發佈的評測',
-        teaEv: '任課老師發佈的評測',
-        markSetting: '閱卷配寘',
-        markData: '閱卷數據'
+    mgtScEv:{
+        listLabel:'评测列表',
+        period:'学段:',
+        create:'新建',
+        delete:'删除',
+        edit:'编辑',
+        createTime:'施测时间:',
+        pending:'待发布',
+        going:'进行中',
+        finish:'已结束',
+        endTime:'结束时间:',
+        stop:'立即结束',
+        evType:'测试类型:',
+        stuCount:'施测人数:',
+        nodata:'暂无评测',
+        tab1:'评测数据',
+        tab2:'评测试卷',
+        autoTips1:'此功能仅用于展示情景快速模拟学生作答数据,且学生作答为随机生成,仅供参考!',
+        autoTips2:'此功能仅用于展示情景快速模拟教师评分数据,且分数为随机生成,仅供参考!',
+        autoScore:'一键评分',
+        autoAnswer:'一键作答',
+        evSubject:'测试科目:',
+        returnTop:'返回顶部',
+        mockOk:'模拟成功',
+        mockErr:'模拟失败',
+        stopTitle:'结束评测',
+        stopContent:'结束后学生将不能继续作答,是否立即结束',
+        stopOk:'评测已结束!',
+        deleteTitle:'删除评测',
+        deleteContent:'是否确认删除',
+        deleteOk:'删除成功',
+        deleteErr:'删除失败',
+        noJoin:'此账号暂未加入任何学校!',
+        myEv:'我发布的评测',
+        teaEv:'任课老师发布的评测',
+        markSetting:'阅卷设置',
+        markData:'阅卷数据',
+        ftStatus:'状态:',
+        ftType:'类型:',
+        ftMode:'模式:',
+        search:'搜索'
     },
 
-    //創建評測校本/個人
-    createEv: {
-        createLabel: '創建評測',
-        publishEv: '發佈評測',
-        return: '返回上級',
-        baseInfo: '基礎資訊',
-        evName: '評測名稱',
-        evPeriod: '測試學段',
-        evMode: '評測模式',
-        evType: '評測類型',
-        examType: '考試類別',
-        courseType: '課程類別',
-        cusLabel1: '校本課程',
-        cusLabel2: '個人課程',
-        evTarget: '施測對象',
-        publishType: '發佈管道',
-        startTime: '開始時間',
-        sTimeHolder: '請選擇開始時間',
-        endTime: '結束時間',
-        eTimeHolder: '請選擇結束時間',
-        addSubject: '添加學科',
-        noSubject: '暫無科目,請添加科目',
-        noSubject1: '*請先選擇測試學段',
-        papersLabel: '試卷庫',
-        perviewLabel: '試卷預覽',
-        importLabel: '導入說明',
-        answerPreview: '作答預覽',
-        errTips1: '評測名稱不能為空!',
-        errTips2: '測試類型不能為空!',
-        errTips3: '評量模式不能為空!',
-        errTips4: '請設定類別!',
-        errTips5: '請設定測試類型!',
-        errTips6: '請設定測試對象!',
-        errTips7: '請設定發佈管道!',
-        errTips8: '請設定發佈時間!',
-        errTips9: '請設定結束時間!',
-        errTips10: '請設定測試學段!',
-        stPaperTitle: '挑選試卷',
-        stPaperContent: '是否確認挑選',
-        inDev: '功能正在開發中,敬請期待!',
-        formWarning: '請先完善評測基礎資訊!',
-        paperWarning: '請挑選或導入試卷!',
-        paperWarning1: '還沒有試卷,請挑選或導入試卷!',
-        pdWarning: '請添加測試科目!',
-        publishOk: '評測發佈成功!',
-        togglePeriod: '切換學段',
-        togglePdTip1: '您已添加',
-        togglePdTip2: '的測試科目,如果現在切換學段會清空已選科目,確定切換學段嗎?',
-        toggleOkText: '切換',
-        delPdTitle: '删除科目',
-        delPdContent: '是否確認删除',
-        delOk: '删除成功',
-        pdTips: '請先選擇測試學段!',
-        defaultPaper: '(請先挑選或導入試卷)',
+    //CreateEv
+    createEv:{
+        createLabel:'创建评测',
+        publishEv:'发布评测',
+        return:'返回上级',
+        baseInfo:'基础信息',
+        evName:'评测名称',
+        evPeriod:'测试学段',
+        evMode:'评测模式',
+        evType:'评测类型',
+        examType:'考试类别',
+        courseType:'课程类别',
+        cusLabel1:'校本课程',
+        cusLabel2:'个人课程',
+        evTarget:'施测对象',
+        publishType:'发布方式',
+        startTime:'开始时间',
+        sTimeHolder:'请选择开始时间',
+        endTime:'结束时间',
+        eTimeHolder:'请选择结束时间',
+        addSubject:'添加学科',
+        noSubject:'暂无科目,请添加科目',
+        noSubject1:'* 请先选择测试学段',
+        papersLabel:'试卷库',
+        perviewLabel:'试卷预览',
+        importLabel:'导入说明',
+        answerPreview:'作答预览',
+        errTips1:'评测名称不能为空!',
+        errTips2:'测试类型不能为空!',
+        errTips3:'评量模式不能为空!',
+        errTips4:'请设置类别!',
+        errTips5:'请设置测试类型!',
+        errTips6:'请设置测试对象!',
+        errTips7:'请设置发布方式!',
+        errTips8:'请设置发布时间!',
+        errTips9:'请设置结束时间!',
+        errTips10:'请设置测试学段!',
+        stPaperTitle:'挑选试卷',
+        stPaperContent:'是否确认挑选',
+        inDev:'功能正在开发中,敬请期待!',
+        formWarning:'请先完善评测基础信息!',
+        paperWarning:'请挑选或导入试卷!',
+        paperWarning1:'还没有试卷,请挑选或导入试卷!',
+        pdWarning:'请添加测试科目!',
+        publishOk:'评测发布成功!',
+        togglePeriod:'切换学段',
+        togglePdTip1:'您已添加',
+        togglePdTip2:'的测试科目,如果现在切换学段会清空已选科目,确定切换学段吗?',
+        toggleOkText:'切换',
+        delPdTitle:'删除科目',
+        delPdContent:'是否确认删除',
+        delOk:'删除成功',
+        pdTips:'请先选择测试学段!',
+        defaultPaper:'(请先挑选或导入试卷)',
     },
-    //ManualPaper.vue
-    manual: {
-        source: '來源:',
-        sourceP: '個人試卷庫',
-        sourceS: '校本試卷庫',
-        pdLabel: '學段:',
-        subjectLabel: '學科:',
-        gradeLabel: '年級:',
-        fitPd: '適用學段:',
-        fitSubject: '適用科目:',
-        quCount: '題量:',
-        useCount: '使用次數:',
-        stdPaper: '已選試卷',
-        stPaper: '選擇試卷',
-        previewPaper: '預覽試卷',
-        noPaper: '暫無對應的試卷',
-        noPaper1: '暫無試卷'
+    // ManualPaper.vue
+    manual:{
+        source:'来源:',
+        sourceP:'个人试卷库',
+        sourceS:'校本试卷库',
+        pdLabel:'学段:',
+        subjectLabel:'学科:',
+        gradeLabel:'年级:',
+        fitPd:'适用学段:',
+        fitSubject:'适用科目:',
+        quCount:'题量:',
+        useCount:'使用次数:',
+        stdPaper:'已选试卷',
+        stPaper:'选择试卷',
+        previewPaper:'预览试卷',
+        noPaper:'暂无对应的试卷',
+        noPaper1:'暂无试卷'
     },
-    //PaperScore.vue、Scoring.vue
-    score: {
-        stuName: '學生姓名:',
-        score: '總分:',
-        scoreUnit: '分',
-        saveScore: '保存打分',
-        showAns: '顯示答案',
-        hideAns: '隱藏答案',
-        showQu: '顯示題幹',
-        hideQu: '隱藏題幹',
-        quIndex: '題號:',
-        quIndex1: '題號',
-        fullScore: '滿分',
-        zeroScore: '零分',
-        zeroScore1: '0分',
-        stuAns: '【學生作答】',
-        mark: '批註',
-        quAns: '【答ㅤ案】',
-        noAnswer: '未設定答案',
-        anaLabel: '【解ㅤ析】',
-        noAna: '暫無解析',
-        kdLabel: '【知識點】',
-        noKd: '暫未綁定知識點',
-        sQuLabel1: '【小題',
-        sQuLabel2: '】',
-        quIndexLabel: '【題號',
-        nextStu: '下一位學生>>>',
-        markOk: '批註成功!',
-        markErr: '批註失敗!',
-        isFullTips: '已經是小題滿分了',
-        isZeroTips: '已經是零分了',
-        saveScoreOk: '成績保存成功!',
-        saveSocreErr: '成績保存失敗!',
-        zero: '零',
-        one: '一',
-        two: '二',
-        three: '三',
-        four: '四',
-        five: '五',
-        six: '六',
-        seven: '七',
-        eight: '八',
-        nine: '九',
-        ten: '十',
-        hundred: '百',
-        thousand: '千',
-        tenThd: '萬',
-        hMillion: '億',
-        noStuAns: '未作答',
-        noStuAns1: '暫未作答',
-        trueAns: '正確',
-        falseAns: '錯誤',
+    // PaperScore.vue、Scoring.vue
+    score:{
+        stuName:'学生姓名:',
+        score:'总分:',
+        scoreUnit:'分',
+        saveScore:'保存打分',
+        showAns:'显示答案',
+        hideAns:'隐藏答案',
+        showQu:'显示题干',
+        hideQu:'隐藏题干',
+        quIndex:'题号:',
+        quIndex1:'题号',
+        fullScore:'满分',
+        zeroScore:'零分',
+        zeroScore1:'0分',
+        stuAns:'【学 生 作 答】',
+        mark:'批注',
+        quAns:'【答ㅤ案】',
+        noAnswer:'未设置答案',
+        anaLabel:'【解ㅤ析】',
+        noAna:'暂无解析',
+        kdLabel:'【知识点】',
+        noKd:'暂未绑定知识点',
+        sQuLabel1:'【小题',
+        sQuLabel2:'】',
+        quIndexLabel:'【题号',
+        nextStu:'下一位学生>>>',
+        markOk:'批注成功!',
+        markErr:'批注失败!',
+        isFullTips:'已经是小题满分了',
+        isZeroTips:'已经是零分了',
+        saveScoreOk:'成绩保存成功!',
+        saveSocreErr:'成绩保存失败!',
+        zero:'零',
+        one:'一',
+        two:'二',
+        three:'三',
+        four:'四',
+        five:'五',
+        six:'六',
+        seven:'七',
+        eight:'八',
+        nine:'九',
+        ten:'十',
+        hundred:'百',
+        thousand:'千',
+        tenThd:'万',
+        hMillion:'亿',
+        noStuAns:'未作答',
+        noStuAns1:'暂未作答',
+        trueAns:'正确',
+        falseAns:'错误',
         //Scoring.vue
-        subjectLabel: '學科:',
-        gradeLabel: '年級:',
-        classLabel: '班級:',
-        stuLabel: '學生:',
-        scoreView: '分數概覽',
-        scoring: '試卷評分',
-        classNoStu: '班級暫無學生',
-        status1: '暫未作答',
-        status2: '前往評分',
-        status3: '查看分數',
-        column1: '姓名',
-        column2: '總分',
-        column3: '狀態',
-        finishScore: '已完成所有學生作答的評分!',
-        unableScore: '學生尚未作答,無法評分',
-        stStuWarning: '請先選擇學生!',
-        lastQu: '上一',
-        nextQu: '下一',
+        subjectLabel:'学科:',
+        gradeLabel:'年级:',
+        classLabel:'班级:',
+        stuLabel:'学生:',
+        scoreView:'分数概览',
+        scoring:'试卷评分',
+        classNoStu:'班级暂无学生',
+        status1:'暂未作答',
+        status2:'前往评分',
+        status3:'查看分数',
+        column1:'姓名',
+        column2:'总分',
+        column3:'状态',
+        finishScore:'已完成所有学生作答的评分!',
+        unableScore:'学生尚未作答,无法评分',
+        stStuWarning: '请先选择学生!',
+        lastQu: '上一',
+        nextQu: '下一',
     },
 
     //SimpleAnalysis.vue
-    simple: {
-        totalPeople: '總人數',
-        missExam: '缺考數',
-        classLabel: '班級',
-        sjLabel: '學科',
-        avgScore: '平均分',
-        classStuCount: '班級人數',
-        answered: '已作答',
-        unanswer: '未作答',
-        scored: '已評分',
-        unscore: '未評分',
-        noPublish: '評測尚未發佈,暫無統計資料',
-        calcing: '成績數據結算中,',
-        clickFresh: '點此重繪',
-        inCalc: '數據結算中,請稍後查看',
-        total: '總分',
-        avgScore: '均分統計',
-        totalLabel: '總量',
-        scoreMat: '分數段統計'
+    simple:{
+        totalPeople:'总人数',
+        missExam:'缺考数',
+        classLabel:'班级',
+        sjLabel:'学科',
+        avgScore:'平均分',
+        classStuCount:'班级人数',
+        answered:'已作答',
+        unanswer:'未作答',
+        scored:'已评分',
+        unscore:'未评分',
+        noPublish:'评测尚未发布,暂无统计数据',
+        calcing:'成绩数据结算中,',
+        clickFresh:'点此刷新',
+        inCalc:'数据结算中,请稍后查看',
+        total:'总分',
+        avgScore:'均分统计',
+        totalLabel:'总量',
+        scoreMat:'分数段统计'
     },
 
-    mark: {
-        baseSetting: '基礎設定',
-        markMode: '閱卷模式',
-        full: '完整閱卷',
-        question: '指定題目',
-        markNum: '閱卷次數',
-        allocation: '分配管道',
-        random: '隨機分配',
-        class: '按班分配',
-        scoreDiff: '分差',
-        markRole: '閱卷角色',
-        errRole: '異常處理:',
-        arb: '仲裁教師:',
-        markRole: '閱卷教師:',
-        noTea: '暫無教師',
-        remove: '移除',
-        addTea: '添加閱卷老師',
-        quDistrub: '題目分配',
-        quIndex: '題號',
-        markNum: '閱卷人數',
-        markTea: '閱卷教師',
-        stage: '活動階段',
-        test: '施測',
-        complete: '已完成',
-        scan: '掃描',
-        success: '成功',
-        fail: '失敗',
-        miss: '缺考',
-        mark: '閱卷',
-        markProg: '閱卷進度',
-        data: '資料統計',
-        dataView: '數據概覽',
-        scanOk: '掃描成功',
-        scanErr: '掃描失敗',
-        arbPaper: '仲裁試卷',
-        subData: '各科概覽',
-        assigned: '已分配',
-        unassigned: '未分配',
-        teaProgress: '教師閱卷進度',
-        schedule: '調度',
-        subject: '科目',
-        stuNum: '考試人數',
-        scanProg: '掃描進度',
-        assignStatus: '閱卷分配',
-        errDeclare: '异常申報',
-        arbDeclare: '仲裁申報',
-        markProg: '閱卷進度',
-        name: '姓名',
-        progress: '進度',
-        action: '操作'
-
+    mark:{
+        baseSetting:'基础设置',
+        markMode:'阅卷模式',
+        full:'完整阅卷',
+        question:'指定题目',
+        markNum:'阅卷次数',
+        allocation:'分配方式',
+        random:'随机分配',
+        class:'按班分配',
+        scoreDiff:'分差',
+        markRole:'阅卷角色',
+        errRole:'异常处理:',
+        arb:'仲裁教师:',
+        markRole:'阅卷教师:',
+        noTea:'暂无教师',
+        remove:'移除',
+        addTea:'添加阅卷老师',
+        quDistrub:'题目分配',
+        quIndex:'题号',
+        markNum:'阅卷人数',
+        markTea:'阅卷教师',
+        stage:'活动阶段',
+        test:'施测',
+        complete:'已完成',
+        scan:'扫描',
+        success:'成功',
+        fail:'失败',
+        miss:'缺考',
+        mark:'阅卷',
+        markProg:'阅卷进度',
+        data:'数据统计',
+        dataView:'数据概览',
+        scanOk:'扫描成功',
+        scanErr:'扫描失败',
+        arbPaper:'仲裁试卷',
+        subData:'各科概览',
+        assigned:'已分配',
+        unassigned:'未分配',
+        teaProgress:'教师阅卷进度',
+        schedule:'调度',
+        subject:'科目',
+        stuNum:'考试人数',
+        scanProg:'扫描进度',
+        assignStatus:'阅卷分配',
+        errDeclare:'异常申报',
+        arbDeclare:'仲裁申报',
+        markProg:'阅卷进度',
+        name:'姓名',
+        markTea:'阅卷老师',
+        progress:'进度',
+        action:'操作',
+        addTeaTitle:'添加阅卷老师',
+        markNum:'阅卷量'
     }
 }

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

@@ -34,7 +34,8 @@ export default {
         selfLearn:'自主学习',
         homework:'作业活动',
         acRecord: '活动记录',
-        cusMgt:'课程管理'
+        cusMgt:'课程管理',
+        taskList:'任务列表'
     },
     compt: {
         cusWare: '课件',

+ 10 - 3
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/learnActivity.js

@@ -35,8 +35,12 @@ export default{
         noJoin:'此账号暂未加入任何学校!',
         myEv:'我发布的评测',
         teaEv:'任课老师发布的评测',
-        markSetting:'阅卷配置',
-        markData:'阅卷数据'
+        markSetting:'阅卷设置',
+        markData:'阅卷数据',
+        ftStatus:'状态:',
+        ftType:'类型:',
+        ftMode:'模式:',
+        search:'搜索'
     },
 
     //CreateEv
@@ -255,7 +259,10 @@ export default{
         arbDeclare:'仲裁申报',
         markProg:'阅卷进度',
         name:'姓名',
+        markTea:'阅卷老师',
         progress:'进度',
-        action:'操作'
+        action:'操作',
+        addTeaTitle:'添加阅卷老师',
+        markNum:'阅卷量'
     }
 }

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

@@ -34,7 +34,8 @@ export default {
         selfLearn:'自主学习',
         homework:'作业活动',
         acRecord: '活动记录',
-        cusMgt:'课程管理'
+        cusMgt:'课程管理',
+        taskList:'任务列表'
     },
     compt: {
         cusWare: '课件',

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

@@ -36,7 +36,11 @@ export default {
         myEv: '我發佈的評測',
         teaEv: '任課老師發佈的評測',
         markSetting: '閱卷配寘',
-        markData: '閱卷數據'
+        markData: '閱卷數據',
+        ftStatus: '狀態:',
+        ftType: '類型:',
+        ftMode: '模式:',
+        search: '蒐索'
     },
 
     //創建評測校本/個人
@@ -255,8 +259,10 @@ export default {
         arbDeclare: '仲裁申報',
         markProg: '閱卷進度',
         name: '姓名',
+        markTea:'閱卷老師',
         progress: '進度',
-        action: '操作'
-
+        action: '操作',
+        addTeaTitle: '添加閱卷老師',
+        markNum: '閱卷量'
     }
 }

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

@@ -34,7 +34,8 @@ export default {
         selfLearn: '自主學習',
         homework: '工作活動',
         acRecord: '活動記錄',
-        cusMgt: '課程管理'
+        cusMgt: '課程管理',
+        taskList:'任務清單'
     },
     compt: {
         cusWare: '課件',

+ 9 - 0
TEAMModelOS/ClientApp/src/router/routes.js

@@ -340,6 +340,15 @@ export const routes = [
 				isKeep: true
 			}
 		},
+		{
+			path: 'taskList',
+			name: 'taskList',
+			component: resolve => require(['@/view/task/index.vue'], resolve),
+			meta: {
+				activeName: 'taskList',
+				isKeep: true
+			}
+		},
 		//自定义名单管理页面
 		{
 			path: 'MgtStuList',

+ 1 - 1
TEAMModelOS/ClientApp/src/view/Home.vue

@@ -186,7 +186,7 @@ body {
 
 #content {
     height: 100%;
-    /*background: #2B2B2E;*/
+    background: #242328;
     overflow: hidden;
 }
 

+ 3 - 0
TEAMModelOS/ClientApp/src/view/learnactivity/MgtSchoolEva.less

@@ -233,4 +233,7 @@
 }
 .mock-tea-scoring{
     margin-right: 40px;
+}
+.filter-item{
+    margin: 10px 5px;
 }

+ 86 - 18
TEAMModelOS/ClientApp/src/view/learnactivity/MgtSchoolEva.vue

@@ -15,9 +15,41 @@
                             <DropdownItem :name="item.id">{{ item.name }}</DropdownItem>
                         </DropdownMenu>
                     </Dropdown>
-                    <Icon type="md-add" class=" to-create-icon" @click="goToCreate" :title="$t('learnActivity.mgtScEv.create')" v-if="$access.can('admin.*|schoolAc-upd')" />
-                    <Icon type="md-trash" v-show="evaListShow.length" class="to-create-icon" :title="$t('learnActivity.mgtScEv.delete')" @click="deleteEvaluation" v-if="$access.can('admin.*|schoolAc-upd')" />
-                    <Icon type="md-create" v-show="evaListShow.length && evaListShow[curEvaIndex] && evaListShow[curEvaIndex].progress == 'pending'" class="to-create-icon" @click="editEvaluation" :title="$t('learnActivity.mgtScEv.edit')" v-if="$access.can('admin.*|schoolAc-upd')" />
+                    <div style="float:right" v-if="!isSearch">
+                        <Icon type="md-add" class=" to-create-icon" @click="goToCreate" :title="$t('learnActivity.mgtScEv.create')" v-if="$access.can('admin.*|schoolAc-upd')" />
+                        <Icon type="md-trash" v-show="evaListShow.length" class="to-create-icon" :title="$t('learnActivity.mgtScEv.delete')" @click="deleteEvaluation" v-if="$access.can('admin.*|schoolAc-upd')" />
+                        <Icon type="md-create" v-show="evaListShow.length && evaListShow[curEvaIndex] && evaListShow[curEvaIndex].progress == 'pending'" class="to-create-icon" @click="editEvaluation" :title="$t('learnActivity.mgtScEv.edit')" v-if="$access.can('admin.*|schoolAc-upd')" />
+                        <!-- 筛选 -->
+                        <Poptip style="float:right" trigger="hover" :offset="-10" theme="light">
+                            <Icon type="ios-funnel" class="to-create-icon" :color="filter.status || filter.type || filter.mode ? '#2d8cf0':'#fff'" />
+                            <div slot="content">
+                                <div class="filter-item">
+                                    <span>{{$t('learnActivity.mgtScEv.ftStatus')}}</span>
+                                    <Select v-model="filter.status" style="width:100px" size="small" clearable @on-change="filterEv">
+                                        <Option value="pending">{{$t('learnActivity.mgtScEv.pending')}}</Option>
+                                        <Option value="going">{{$t('learnActivity.mgtScEv.going')}}</Option>
+                                        <Option value="finish">{{$t('learnActivity.mgtScEv.finish')}}</Option>
+                                    </Select>
+                                </div>
+                                <div class="filter-item">
+                                    <span>{{$t('learnActivity.mgtScEv.ftType')}}</span>
+                                    <Select v-model="filter.type" style="width:100px" size="small" clearable @on-change="filterEv">
+                                        <Option v-for="(item,index) in $GLOBAL.EV_TYPE()" :value="item.value" :key="index">{{ item.label }}</Option>
+                                    </Select>
+                                </div>
+                                <div class="filter-item">
+                                    <span>{{$t('learnActivity.mgtScEv.ftMode')}}</span>
+                                    <Select v-model="filter.mode" style="width:100px" size="small" clearable @on-change="filterEv">
+                                        <Option v-for="(item,index) in $GLOBAL.EV_MODE()" :value="item.value" :key="index">{{ item.label }}</Option>
+                                    </Select>
+                                </div>
+                            </div>
+                        </Poptip>
+                        <Icon type="md-search" class="to-create-icon" @click="isSearch = !isSearch" :title="$t('learnActivity.mgtScEv.search')" />
+                    </div>
+                    <div v-else class="dark-iview-input" style="float:right;width:calc(100% - 150px);padding-right:10px;">
+                        <Input icon="ios-close" v-model="keyword" :placeholder="$t('schoolBaseInfo.codeSearchHolder')" autofocus style="width:100%" @on-click="closeKeySearch" @on-change="filterByName" />
+                    </div>
                 </div>
                 <div class="evaluation-list-main">
                     <vuescroll>
@@ -63,11 +95,17 @@
                     <span :class="curBarIndex == 1 ? 'evalustion-bar-item line-bottom-active line-bottom':'evalustion-bar-item line-bottom'" @click="selectBar(1)">
                         {{$t('learnActivity.mgtScEv.tab2')}}
                     </span>
-                    <span v-show="evaListShow[curEvaIndex] && evaListShow[curEvaIndex].source == '2'" :class="curBarIndex == 2 ? 'evalustion-bar-item line-bottom-active line-bottom':'evalustion-bar-item line-bottom'" @click="selectBar(2)">
+                    <!-- <span v-show="evaListShow[curEvaIndex] && evaListShow[curEvaIndex].source == '2'" :class="curBarIndex == 2 ? 'evalustion-bar-item line-bottom-active line-bottom':'evalustion-bar-item line-bottom'" @click="selectBar(2)">
                         {{$t('learnActivity.mgtScEv.markSetting')}}
                     </span>
                     <span v-show="evaListShow[curEvaIndex] && evaListShow[curEvaIndex].source == '2'" :class="curBarIndex == 3 ? 'evalustion-bar-item line-bottom-active line-bottom':'evalustion-bar-item line-bottom'" @click="selectBar(3)">
                         {{$t('learnActivity.mgtScEv.markData')}}
+                    </span> -->
+                    <span :class="curBarIndex == 2 ? 'evalustion-bar-item line-bottom-active line-bottom':'evalustion-bar-item line-bottom'" @click="selectBar(2)">
+                        {{$t('learnActivity.mgtScEv.markSetting')}}
+                    </span>
+                    <span :class="curBarIndex == 3 ? 'evalustion-bar-item line-bottom-active line-bottom':'evalustion-bar-item line-bottom'" @click="selectBar(3)">
+                        {{$t('learnActivity.mgtScEv.markData')}}
                     </span>
                     <!--取消一键作答和一键评分功能-->
                     <!--<div style="float:right;" v-if="$access.ability('admin','mock-eva').validateAll" v-show="evaListShow[curEvaIndex] && evaListShow[curEvaIndex].progress == 'going'">
@@ -134,6 +172,8 @@ export default {
     inject: ['reload'],
     data() {
         return {
+            keyword: '',
+            isSearch: false,
             answerLoading: false,
             scoreLoading: false,
             split1: 0.2,
@@ -150,10 +190,51 @@ export default {
             filterPeriod: undefined,
             schoolBase: {
                 period: []
+            },
+            filter: {
+                status: '',
+                mode: '',
+                type: ''
             }
         }
     },
     methods: {
+        filterByName() {
+            let curPdEv = this.evaluationList.filter(item => item.period.id === this.filterPeriod)
+            this.evaListShow = curPdEv.filter(item => {
+                return item.name.indexOf(this.keyword) > -1
+            })
+
+        },
+        closeKeySearch() {
+            this.isSearch = false
+            this.keyword = ''
+            this.filterByName()
+        },
+        //根据学段筛选评测
+        filterByPeriod() {
+            this.curEvaIndex = 0
+            sessionStorage.setItem('evPeriod', this.filterPeriod)
+            if (this.filterPeriod) {
+                this.evaListShow = this.evaluationList.filter(item => item.period.id === this.filterPeriod)
+            } else {
+                this.evaListShow = [...this.evaluationList]
+            }
+            if (this.evaListShow.length) {
+                this.selectEvaluation(0)
+            }
+        },
+
+        //筛选评测
+        filterEv() {
+            let curPdEv = this.evaluationList.filter(item => item.period.id === this.filterPeriod)
+            this.evaListShow = curPdEv.filter(item => {
+                let status = !this.filter.status || (this.filter.status == item.progress)
+                let type = !this.filter.type || (this.filter.type == item.type)
+                let mode = !this.filter.mode || (this.filter.type == item.source)
+                return status && type && mode
+            })
+        },
         // 模拟教师评分数据
         mockScoring() {
             this.scoreLoading = true
@@ -377,25 +458,12 @@ export default {
                         }
 
                     } else {
-                        this$Message.error('API ERROR!')
+                        this.$Message.error('API ERROR!')
                     }
                 }
             )
         },
-        //根据学段筛选评测
-        filterByPeriod() {
-            this.curEvaIndex = 0
-            sessionStorage.setItem('evPeriod', this.filterPeriod)
-            if (this.filterPeriod) {
-                this.evaListShow = this.evaluationList.filter(item => item.period.id === this.filterPeriod)
-            } else {
-                this.evaListShow = [...this.evaluationList]
-            }
-            if (this.evaListShow.length) {
-                this.selectEvaluation(0)
-            }
 
-        },
         selectEvaluation(index) {
             this.curSubIndex = 0
             this.curEvaIndex = index

+ 18 - 15
TEAMModelOS/ClientApp/src/view/learnactivity/markpaper/MarkData.vue

@@ -70,7 +70,7 @@
                         <template slot-scope="{ row }" slot="progress">
                             <div style="display: flex;justify-content: center;">
                                 <i-circle :percent="20" :size="40" :stroke-width="8" :trail-width="7" stroke-color="#ff5500">
-                                    <span>20%</span>
+                                    <span style="font-size:12px">20%</span>
                                 </i-circle>
                             </div>
                         </template>
@@ -207,7 +207,7 @@ export default {
                     align: 'center'
                 },
                 {
-                    title: this.$t('learnActivity.mark.name'),
+                    title: this.$t('learnActivity.mark.markTea'),
                     key: 'name',
                     align: 'center'
                 },
@@ -303,7 +303,9 @@ export default {
 }
 
 .setting-content {
-    background: #404042;
+    background: #2b2a2f;
+    box-shadow: 1px 1px 13px #141414;
+    border: 1px solid rgba(98, 97, 101, 0.4);
     padding: 15px 10px;
     border-radius: 5px;
     margin-right: 12px;
@@ -315,8 +317,8 @@ export default {
     padding-right: 15px;
 }
 .block-title {
-    color: white;
-    border-left: 2px solid #1cc0f3;
+    color: rgb(190, 190, 190);
+    // border-left: 2px solid #1cc0f3;
     line-height: 12px;
     padding-left: 4px;
     user-select: none;
@@ -356,14 +358,6 @@ export default {
 .count-content {
     display: flex;
 }
-.chart-wrap {
-    flex: 1;
-    color: #fff;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-}
 .mark-step {
     padding: 0px 40px 0px 20px;
 }
@@ -372,14 +366,14 @@ export default {
 .step-content {
     .ivu-steps .ivu-steps-title,
     .ivu-steps .ivu-steps-head {
-        background: #404042;
+        background: #2b2a2f;
     }
     .ivu-steps-item.ivu-steps-status-finish .ivu-steps-title,
     .ivu-steps-item.ivu-steps-status-process .ivu-steps-title {
         color: white;
     }
     .ivu-steps-item.ivu-steps-status-finish .ivu-steps-head-inner {
-        background-color: #404042;
+        background-color: #2b2a2f;
         border-color: #1cc0f3;
     }
     .ivu-steps-item.ivu-steps-status-finish .ivu-steps-tail > i:after {
@@ -395,4 +389,13 @@ export default {
         color: white;
     }
 }
+.mark-data-wrap .ivu-table:before{
+    height: 0px;
+}
+.sub-info-table .ivu-table td{
+    border-color: #323232;
+}
+.sub-info-table .ivu-table-header thead tr th{
+    border-color: #323232;
+}
 </style>

+ 99 - 85
TEAMModelOS/ClientApp/src/view/learnactivity/markpaper/MarkSetting.vue

@@ -1,34 +1,17 @@
 <template>
     <div class="mark-setting-wrap dark-iview-form">
         <vuescroll>
-            <div class="setting-block">
-                <p class="block-title">
+            <!-- 基础设置 -->
+            <div class="setting-block" style="display:none">
+                <!-- <p class="block-title">
                     {{$t('learnActivity.mark.baseSetting')}}
-                </p>
+                </p> -->
                 <div class="setting-content">
                     <Form :model="setting" label-colon :label-width="80">
                         <Row>
                             <Col :md="24" :lg="24" :xl="12" :xxl="12">
-                            <FormItem :label="$t('learnActivity.mark.markMode')" class="setting-item-wrap">
-                                <RadioGroup v-model="setting.mode">
-                                    <Radio :label="$t('learnActivity.mark.full')"></Radio>
-                                    <Radio :label="$t('learnActivity.mark.question')"></Radio>
-                                </RadioGroup>
-                            </FormItem>
-                            </Col>
-                            <Col :md="24" :lg="24" :xl="12" :xxl="12">
-                            <FormItem :label="$t('learnActivity.mark.markNum')" class="setting-item-wrap">
-                                <InputNumber :max="2" :min="1" v-model="setting.num"></InputNumber>
-                            </FormItem>
-                            </Col>
-                        </Row>
-                        <Row>
-                            <Col :md="24" :lg="24" :xl="12" :xxl="12">
-                            <FormItem :label="$t('learnActivity.mark.allocation')" class="setting-item-wrap">
-                                <RadioGroup v-model="setting.mode">
-                                    <Radio :label="$t('learnActivity.mark.random')"></Radio>
-                                    <Radio :label="$t('learnActivity.mark.class')"></Radio>
-                                </RadioGroup>
+                            <FormItem label="阅卷次数" class="setting-item-wrap">
+                                <InputNumber :max="2" :min="1" v-model="setting.point"></InputNumber>
                             </FormItem>
                             </Col>
                             <Col :md="24" :lg="24" :xl="12" :xxl="12">
@@ -42,13 +25,14 @@
             </div>
 
             <div class="setting-block">
-                <p class="block-title">
+                <!-- <p class="block-title">
                     {{$t('learnActivity.mark.markRole')}}
-                </p>
+                </p> -->
                 <div class="setting-content">
                     <Row>
                         <Col :md="24" :lg="24" :xl="12" :xxl="12">
-                        <div class="role-item-wrap">
+                        <!-- 异常处理老师 -->
+                        <div class="role-item-wrap" style="display:none">
                             <span class="role-label">{{$t('learnActivity.mark.errRole')}}</span>
                             <Select v-model="setting.err" style="width:400px" multiple>
                                 <Option value="beijing">New York</Option>
@@ -58,7 +42,8 @@
                         </div>
                         </Col>
                         <Col :md="24" :lg="24" :xl="12" :xxl="12">
-                        <div class="role-item-wrap">
+                        <!-- 仲裁老师 -->
+                        <div class="role-item-wrap" style="display:none">
                             <span class="role-label">{{$t('learnActivity.mark.arb')}}</span>
                             <Select v-model="setting.err1" style="width:400px" multiple>
                                 <Option value="beijing">New York</Option>
@@ -68,6 +53,7 @@
                         </div>
                         </Col>
                     </Row>
+                    <!-- 阅卷老师设置 -->
                     <div class="role-item-wrap dark-iview-table">
                         <span class="role-label" style="vertical-align: top;">{{$t('learnActivity.mark.markRole')}}</span>
                         <div class="scan-tea-table">
@@ -78,8 +64,11 @@
                                 <template slot-scope="{ row }" slot="action">
                                     <Button type="error" size="small">{{$t('learnActivity.mark.remove')}}</Button>
                                 </template>
+                                <template slot-scope="{ row }" slot="num">
+                                    <span>{{`${row.num}/24`}}</span>
+                                </template>
                             </Table>
-                            <span class="add-tea-btn">
+                            <span class="add-tea-btn" @click="addTeaStatus = true">
                                 <Icon type="md-add" />
                                 {{$t('learnActivity.mark.addTea')}}
                             </span>
@@ -87,10 +76,11 @@
                     </div>
                 </div>
             </div>
-            <div class="setting-block">
-                <p class="block-title">
+            <!-- 题号分配 -->
+            <div class="setting-block" style="display:none">
+                <!-- <p class="block-title">
                     {{$t('learnActivity.mark.quDistrub')}}
-                </p>
+                </p> -->
                 <div class="setting-content dark-iview-table">
                     <Table :columns="quCol" :data="quData" border :no-data-text="$t('learnActivity.mark.noTea')">
                         <template slot-scope="{ row }" slot="quNo">
@@ -106,6 +96,16 @@
                 </div>
             </div>
         </vuescroll>
+        <Modal v-model="addTeaStatus" :title="$t('learnActivity.mark.addTeaTitle')" class-name="dark-iview-modal dark-iview-table" @on-ok="okAddTea" :width="1000">
+            <Table ref="sltTea" :columns="teacherCol" :data="teacherList" style="margin-top:10px" @on-selection-change="(selection)=>{sltTeachers = selection}" height="600">
+                <template slot-scope="{ row }" slot="picture">
+                    <PersonalPhoto :name="row.name" :picture="row.picture" />
+                </template>
+                <template slot-scope="{ row }" slot="job">
+                    <span>{{row.job || '--'}}</span>
+                </template>
+            </Table>
+        </Modal>
     </div>
 </template>
 <script>
@@ -125,6 +125,37 @@ export default {
                 point: 2,//分差(仲裁条件)
                 quRule: [],//题目分配规则
             },
+            addTeaStatus: false,
+            teacherList: [],
+            sltTeachers: [],
+            teacherCol: [
+                {
+                    type: 'selection',
+                    width: 60,
+                    align: 'center'
+                },
+                {
+                    title: ' ',
+                    slot: 'picture',
+                    align: 'center ',
+                    width: '120'
+                },
+                {
+                    title: this.$t('cusMgt.teaName'),
+                    key: 'name',
+                    align: 'center '
+                },
+                {
+                    title: 'id',
+                    key: 'id',
+                    align: 'center '
+                },
+                {
+                    title: this.$t('cusMgt.job'),
+                    slot: 'job',
+                    align: 'center '
+                }
+            ],
             teaCol: [
                 {
                     title: ' ',
@@ -132,18 +163,18 @@ export default {
                     align: 'center'
                 },
                 {
-                    title: '姓名',
-                    key: 'name',
+                    title: 'id',
+                    key: 'id',
                     align: 'center'
                 },
                 {
-                    title: '手机',
-                    key: 'phone',
+                    title: this.$t('learnActivity.mark.name'),
+                    key: 'name',
                     align: 'center'
                 },
                 {
-                    title: '阅卷量',
-                    key: 'num',
+                    title: this.$t('learnActivity.mark.markNum'),
+                    slot: 'num',
                     align: 'center'
                 },
                 {
@@ -152,23 +183,7 @@ export default {
                     align: 'center'
                 },
             ],
-            teaData: [
-                {
-                    name: '测试老师',
-                    phone: '13096300695',
-                    num: '100/563'
-                },
-                {
-                    name: '测试老师',
-                    phone: '13096300695',
-                    num: '100/563'
-                },
-                {
-                    name: '测试老师',
-                    phone: '13096300695',
-                    num: '100/563'
-                }
-            ],
+            teaData: [],
             quCol: [
                 {
                     title: this.$t('learnActivity.mark.quIndex'),
@@ -199,33 +214,6 @@ export default {
                         'jefftest',
                         '李芷萱',
                     ]
-                },
-                {
-                    quNo: [4, 5, 6],
-                    teachers: [
-                        'JK',
-                        '尹航',
-                        '向奕然',
-                        '高嘉妍',
-                        '刘雨菡',
-                        'jefftest',
-                        '李芷萱',
-                        '刘雨菡',
-                        'jefftest',
-                        '李芷萱',
-                    ]
-                },
-                {
-                    quNo: [7, 8],
-                    teachers: [
-                        'JK',
-                        '尹航',
-                        '向奕然',
-                        '高嘉妍',
-                        '刘雨菡',
-                        'jefftest',
-                        '李芷萱',
-                    ]
                 }
             ]
         }
@@ -234,10 +222,34 @@ export default {
         MarkProgress, CptCount, ScanProgress, PersonalPhoto
     },
     methods: {
-
+        //确认添加老师
+        okAddTea() {
+            let ids = this.teaData.map(item => {
+                return item.id
+            })
+            this.sltTeachers.forEach(item => {
+                if (ids.indexOf(item.id) == -1) {
+                    this.teaData.push(item)
+                }
+            })
+            this.teaData.map(item => {
+                item.num = 24 / this.teaData.length
+            })
+            this.cancel()
+        },
+        cancel() {
+            this.sltTeachers = []
+            this.$refs.sltTea.selectAll(false)
+        },
+        
     },
     created() {
-
+        this.$store.dispatch('teachers/getTeacherList').then(res => {
+            this.teacherList = this.$store.state.teachers.teacherList.filter(item => {
+                return item.status == 'join'
+            })
+            console.log(this.teacherList)
+        })
     }
 }
 </script>
@@ -252,7 +264,9 @@ export default {
 }
 
 .setting-content {
-    background: #404042;
+    background: #2b2a2f;
+    box-shadow: 1px 1px 13px #141414;
+    // border: 1px solid rgba(98, 97, 101, 0.4);
     padding: 10px;
     border-radius: 5px;
     margin-right: 12px;
@@ -317,7 +331,7 @@ export default {
     .role-label {
         color: #a5a5a5;
         display: inline-block;
-        width: 120px;
+        // width: 120px;
         text-align: right;
         padding-right: 10px;
     }

+ 9 - 7
TEAMModelOS/ClientApp/src/view/learnactivity/markpaper/MarkView.vue

@@ -1,9 +1,11 @@
 <template>
+    <!-- 未做多语言 -->
     <div class="mark-area">
         <!-- 头部基础信息 -->
         <div class="mark-header" v-show="markMode == 'paper'">
             <span class="quit-marking-text">
-                <Icon custom="iconfont icon-quit2" class="quit-marking-icon" title="退出阅卷" @click="test"/>
+                <!-- <Icon custom="iconfont icon-quit2" class="quit-marking-icon" title="退出阅卷" @click="test"/> -->
+                <Icon type="ios-arrow-back" class="quit-marking-icon" title="退出阅卷" @click="test" />
                 <!-- 退出阅卷 -->
             </span>
             <span class="info-label">考试名称:</span>
@@ -17,7 +19,7 @@
             <div class="btn-wrap">
                 <!-- <Button type="text" custom-icon="iconfont icon-exception" class="action-btn" @click="test">异常申报</Button> -->
                 <span class="action-btn">
-                    <Icon custom="iconfont icon-exception" class="action-btn-icon"/>
+                    <Icon custom="iconfont icon-exception" class="action-btn-icon" />
                     异常申报
                 </span>
             </div>
@@ -55,7 +57,7 @@
                 </Poptip>
                 <Icon custom="iconfont icon-fresh" class="tool-icon" title="清除批注" @click="clear" />
                 <Icon custom="iconfont icon-review" class="tool-icon" title="重阅" />
-                <Icon :custom="isFull ? 'iconfont icon-cancel-full' : 'iconfont icon-full-screen'" class="tool-icon" :title="isFull ? '取消全屏' : '全屏'" @click="togglefull"/>
+                <Icon :custom="isFull ? 'iconfont icon-cancel-full' : 'iconfont icon-full-screen'" class="tool-icon" :title="isFull ? '取消全屏' : '全屏'" @click="togglefull" />
                 <!-- <Icon custom="iconfont icon-exception" class="tool-icon exception-icon" title="异常申报" color="#ed4014" /> -->
                 <!-- <Icon v-for="(item,index) in iconList" :key="index" :custom="item.icon" :class="['tool-icon', activeIcon == index ? 'tool-icon-active':'']" :title="item.title" @click="(item.click)(index)" :color="item.color" /> -->
             </div>
@@ -221,11 +223,11 @@ export default {
             curImg: undefined,
             counter: 0,
             markMode: 'paper', //阅卷模式
-            isFull:false, //是否为全屏模式
+            isFull: false, //是否为全屏模式
         }
     },
     methods: {
-        togglefull(){
+        togglefull() {
             this.$router.push({
                 name: this.isFull ? 'MarkView' : 'FullMarkView'
             })
@@ -849,7 +851,7 @@ export default {
         //模拟按题阅卷和整体阅卷
         let routeData = this.$route
         // this.mode = routeData.params.type
-        if(routeData.name == 'FullMarkView') this.isFull = true
+        if (routeData.name == 'FullMarkView') this.isFull = true
         this.mode = 1
 
         //监听删除按键,删除图形
@@ -1022,7 +1024,7 @@ export default {
     margin-left: 10px;
     cursor: pointer;
 }
-.action-btn-icon{
+.action-btn-icon {
     display: inline-block;
     margin-right: 5px;
 }

+ 28 - 13
TEAMModelOS/ClientApp/src/view/schoolmgmt/SystemSetting/NewSystemSetting.less

@@ -14,7 +14,7 @@
         padding: 0px 20px;
         .school-tools {
             font-size: var(--font-size-normal);
-            margin-right: 30px;
+            // margin-right: 30px;
             margin-top: 8px;
             float: right;
         }
@@ -67,25 +67,26 @@
 .badge-wrap{
     position: relative;
     width: 100px;
-    min-height: 100px;
     &:hover{
         .upd-mask{
-            display: block;
+            opacity: 1;
         }
     }
     .upd-mask{
         position: absolute;
         left: 0px;
         top: 0px;
+        bottom: 0px;
         width: 100px;
-        height: 100%;
         border-radius: 4px;
-        display: none;
-        background: rgba(68,68,68,.8);
+        display: flex;
+        background: rgba(68, 68, 68, 0.8);
+        justify-content: center;
+        align-items: center;
+        opacity: 0;
         .upd-badge{
             cursor: pointer;
             text-align: center;
-            margin-top: 35%;
             font-size: 20px;
         }
     }
@@ -528,7 +529,7 @@
     .arrow-box{
         position: absolute;
         top: 2px;
-        margin-left: 2px;
+        margin-left: 1px;
     }
     .line-box{
         display: flex;
@@ -536,8 +537,8 @@
     }
     .time-dot {
         position: relative;
-        width: 20px;
-        height: 20px;
+        width: 18px;
+        height: 18px;
         border-radius: 50%;
         padding: 5px;
         border: 2px solid #959595;
@@ -547,8 +548,8 @@
 
     .time-inner-dot {
         display: inline-block;
-        width: 8px;
-        height: 8px;
+        width: 6px;
+        height: 6px;
         background: #959595;
         border-radius: 50%;
         position: absolute;
@@ -563,7 +564,7 @@
         width: 35px;
         margin-top: 9px;
         border-top: 2px solid #606060;
-        width: ~"calc(100% - 20px)";
+        width: ~"calc(100% - 18px)";
     }
     .arrow-item{
         display: block;
@@ -596,4 +597,18 @@
 .profession-content{
     width: 100%;
     
+}
+.semester-start-warning{
+    color: #ed4014;
+    margin-left: 15px;
+}
+.year-start-tag{
+    font-size: 12px;
+    color: #1cc0f3;
+    border: 1px solid #1cc0f3;
+    padding: 1px 2px;
+    border-radius: 2px;
+    margin-left: 15px;
+    display: inline-block;
+    transform: scale(0.8);
 }

+ 146 - 44
TEAMModelOS/ClientApp/src/view/schoolmgmt/SystemSetting/NewSystemSetting.vue

@@ -14,17 +14,19 @@
         </div>
         <!-- 通用设置 -->
         <div class="sm-system-body base-info-wrap" v-show="tab == 'common'">
+            <!-- 校徽区域 -->
             <div class="base-info-item">
                 <span class="setting-label"></span>
                 <div class="badge-wrap">
                     <img class="school-badge" :src="schoolSetting.picture || defBadge" width="100">
                     <div class="upd-mask">
-                        <Upload action="" class="upd-badge" :before-upload="customUpload">
+                        <Upload action="/blob/public-upload" class="upd-badge" :before-upload="customUpload" :on-success="success" :show-upload-list="false">
                             <Icon type="md-create" :title="$t('schoolBaseInfo.updBadge')" />
                         </Upload>
                     </div>
                 </div>
             </div>
+            <!-- 基础信息区域 -->
             <div class="base-info-item">
                 <span class="setting-label">{{$t('schoolBaseInfo.schoolNameLabel')}}</span>
                 <div class="editable school-name dark-iview-input disabled-iview-select text-cursor-disabled" @click.stop>
@@ -87,6 +89,9 @@
                             <div class="setting-content semester-content">
                                 <p class="block-title bf-color1">
                                     {{$t('schoolBaseInfo.semesterSetting')}}
+                                    <span class="semester-start-warning" v-show="startWarning">
+                                        <Icon type="md-warning" />请设置入学期
+                                    </span>
                                     <span class="block-action-box">
                                         <Icon v-if="$access.ability('admin','schoolSetting-upd').validateAll" type="md-add" @click.stop="addSemester()" class="action-btn-icon" />
                                     </span>
@@ -97,18 +102,20 @@
                                     </span>
                                     <span class="term-item-start" @click.stop>
                                         <span>{{$t('schoolBaseInfo.startDate')}}</span>
-                                        <Select v-model="item.month" style="width:60px" :placeholder="$t('schoolBaseInfo.monthHolder')" :disabled="editSemIndex !== index">
+                                        <Select v-model="item.month" style="width:70px" :placeholder="$t('schoolBaseInfo.monthHolder')" :disabled="editSemIndex !== index">
                                             <Option v-for="(item,index) in monthList" :value="(index + 1)" :key="index" @click.native="countSemDays">{{ item }}</Option>
                                         </Select>
                                         <span> / </span>
-                                        <Select v-model="item.day" style="width:60px" :placeholder="$t('schoolBaseInfo.dayHolder')" :disabled="editSemIndex !== index">
+                                        <Select v-model="item.day" style="width:70px" :placeholder="$t('schoolBaseInfo.dayHolder')" :disabled="editSemIndex !== index">
                                             <Option v-for="(item,index) in dayList" :value="(index + 1)" :key="index" @click.native="countSemDays">{{ item }}</Option>
                                         </Select>
                                     </span>
                                     <span class="term-item-students-num">{{$t('schoolBaseInfo.semesterDuration')+ semDays[index] + $t('schoolBaseInfo.dayUnit')  }}</span>
+                                    <span class="year-start-tag" v-show="item.start == '1'">入学期</span>
                                     <div class="action-btx-box hover-show-icon">
                                         <Icon v-if="$access.ability('admin','schoolSetting-upd').validateAll" type="md-trash" @click.stop="showComfirmDelSemester()" :title="$t('schoolBaseInfo.delete')" class="action-btn-icon" />
-                                        <Icon v-if="$access.ability('admin','schoolSetting-upd').validateAll" type="md-create" @click.stop="editSemIndex = curSemIndex" :title="$t('schoolBaseInfo.editLabel')" class="action-btn-icon" />
+                                        <!-- <Icon v-if="$access.ability('admin','schoolSetting-upd').validateAll" type="md-create" @click.stop="editSemIndex = curSemIndex" :title="$t('schoolBaseInfo.editLabel')" class="action-btn-icon" /> -->
+                                        <Icon v-if="$access.ability('admin','schoolSetting-upd').validateAll" type="md-create" @click.stop="setEditSem(index)" :title="$t('schoolBaseInfo.editLabel')" class="action-btn-icon" />
                                     </div>
                                 </div>
                                 <!-- 时间轴UI -->
@@ -275,6 +282,7 @@
                 </div>
             </Split>
         </div>
+        <!-- 添加校区 -->
         <Modal v-model="campusStatus" class="campus-modal dark-iview-modal" @on-cancel="selectedCampusIndex = -1" @on-ok="confirmCampus" @click.native="initStatus">
             <p slot="header" style="color:#DDDDDD;letter-spacing:2px;font-weight:400;">{{$t('schoolBaseInfo.setCampus')}}</p>
             <p v-for="(item,index) in schoolSetting.campuses" class="campus-name-item dark-iview-input disabled-iview-select text-cursor-disabled" :key="index" @click.stop="selectedCampusIndex = index">
@@ -285,6 +293,7 @@
             </p>
             <Icon type="md-add-circle" size="40" style="margin:auto;cursor:pointer;margin-top:30px;" @click="addCampus" />
         </Modal>
+        <!-- 添加学科 -->
         <Modal v-model="addSubStatus" class="dark-iview-modal dark-iview-form dark-iview-input" :title="$t('schoolBaseInfo.addSubject')" @on-cancel="cancelSubject" @on-ok="confirmSubject">
             <Form ref="subjectInfo" :model="subjectInfo" class="add-subject-form" label-colon>
                 <!-- 学科类型 -->
@@ -324,12 +333,43 @@
                 </FormItem>
             </Form>
         </Modal>
+        <!-- 添加学期 -->
+        <Modal v-model="addSemStatus" class="dark-iview-modal dark-iview-form dark-iview-input" title="添加学期" @on-cancel="cancelSemester" @on-ok="confirmSemester">
+            <Form ref="semesterInfo" :model="semtInfo" class="add-subject-form" label-colon :label-width="80" label-position="left">
+                <!-- 学科类型 -->
+                <FormItem prop="name" label="名称">
+                    <Input v-model="semtInfo.name" style="width:200px" :placeholder="$t('schoolBaseInfo.nameWarning')"></Input>
+                </FormItem>
+                <!-- 开始时间 -->
+                <FormItem prop="name" label="开始于">
+                    <Select v-model="semtInfo.month" style="width:90px" :placeholder="$t('schoolBaseInfo.monthHolder')">
+                        <Option v-for="(item,index) in monthList" :value="(index + 1)" :key="index" @click.native="countSemDays">{{ item }}</Option>
+                    </Select>
+                    <span style="display:inline-block;width:20px;text-align:center"> / </span>
+                    <Select v-model="semtInfo.day" style="width:90px" :placeholder="$t('schoolBaseInfo.dayHolder')">
+                        <Option v-for="(item,index) in dayList" :value="(index + 1)" :key="index" @click.native="countSemDays">{{ item }}</Option>
+                    </Select>
+                </FormItem>
+                <!-- 是否为入学期 -->
+                <FormItem prop="name" label="入学期">
+                    <RadioGroup v-model="semtInfo.start">
+                        <Radio :label="1">
+                            <span>是</span>
+                        </Radio>
+                        <Radio :label="0" style="margin-left:30px">
+                            <span>否</span>
+                        </Radio>
+                    </RadioGroup>
+                </FormItem>
+
+            </Form>
+        </Modal>
 
     </div>
 </template>
 
 <script>
-import BlobTool from '@/utils/blobTool.js'
+// import BlobTool from '@/utils/blobTool.js'
 import Draggable from 'vuedraggable'
 import TimeSetting from '@/view/newcourse/TimeSetting.vue'
 import '@/utils/Math.uuid'
@@ -339,6 +379,13 @@ export default {
     },
     data() {
         return {
+            semtInfo: {
+                id: '',
+                name: '',
+                month: '',
+                day: '',
+                start: ''
+            },
             defBadge: undefined,
             subjectInfo: {
                 type: '',
@@ -347,6 +394,7 @@ export default {
                 isNew: '0'
             },
             addSubStatus: false,
+            addSemStatus: false,
             tab: 'common',
             addTypeStatus: false,
             typeItem: {
@@ -400,6 +448,51 @@ export default {
         }
     },
     methods: {
+        setEditSem(index) {
+            this.semtInfo.name = this.schoolSetting.period[this.curPriodIndex].semesters[index].name
+            this.semtInfo.month = this.schoolSetting.period[this.curPriodIndex].semesters[index].month
+            this.semtInfo.day = this.schoolSetting.period[this.curPriodIndex].semesters[index].day
+            this.semtInfo.start = this.schoolSetting.period[this.curPriodIndex].semesters[index].start
+            this.semtInfo.id = this.schoolSetting.period[this.curPriodIndex].semesters[index].id
+            this.addSemStatus = true
+            console.log('456',this.semtInfo.name)
+        },
+        confirmSemester() {
+            console.log('123',this.semtInfo.id)
+            if (this.semtInfo.id) { //编辑
+                let s = this.schoolSetting.period[this.curPriodIndex].semesters.find(item => {
+                    return item.id == this.semtInfo.id
+                })
+                s.name = this.semtInfo.name
+                s.month = this.semtInfo.month
+                s.day = this.semtInfo.day
+                s.start = this.semtInfo.start
+            } else { //新增
+                this.semtInfo.id = this.guid()
+                this.schoolSetting.period[this.curPriodIndex].semesters.push(this._.cloneDeep(this.semtInfo))
+            }
+
+            //根据时间进行排序
+            if (this.schoolSetting.period[this.curPriodIndex].semesters.length > 1) {
+                this.schoolSetting.period[this.curPriodIndex].semesters.sort((a, b) => {
+                    if (a.month == b.month) {
+                        return a.day - b.day
+                    } else {
+                        return a.month - b.month
+                    }
+                })
+            }
+            this.countSemDays()
+        },
+        cancelSemester() {
+            this.semtInfo = {
+                id: '',
+                name: '',
+                month: '',
+                day: '',
+                start: ''
+            }
+        },
         customUpload(file) {
             let format = ['png', 'jpg', 'jpeg'] //头像文件格式
             let extension = file.name.substring(file.name.lastIndexOf('.') + 1, file.name.length)
@@ -411,24 +504,11 @@ export default {
                 })
                 return false
             }
-            //上传文件 头像上传到公共容器 “0-public” , 文件路径“header”
-            let blobUrl = JSON.parse(decodeURIComponent(localStorage.school_profile, "utf-8")).blob_uri
-            let urlString = blobUrl.substring(0, blobUrl.lastIndexOf('/'))
-            let containerName = '0-public' //公共资源目录,暂未开放上传权限
-            // let containerName = 'download'
-            console.log(blobUrl, urlString, containerName)
-            let blob = new BlobTool(urlString, containerName, '', 'school')
-            console.log(blob)
-            blob.upload(file, 'header').then(
-                res => {
-                    console.log(res)
-                    this.schoolSetting.picture = res.url
-                },
-                err => {
-                    console.log(err)
-                }
-            )
-            return false
+            return true
+            // 公共容器只开放了公共读权限,没有公共写的权限,所以需要将文件通过后端上传
+        },
+        success(response, file, fileList) {
+            this.schoolSetting.picture = response.url
         },
         /**
          * 初始化状态
@@ -581,7 +661,7 @@ export default {
         //计算时间轴选中颜色
         timeLineColor(index) {
             let len = this.schoolSetting.period[this.curPriodIndex].semesters.length
-            let curIndex = -1
+            let curIndex = -1 //当前选中学期
             if (this.schoolSetting.period[this.curPriodIndex].semesters[this.curSemIndex].month <= (index + 1)) {
                 if (this.curSemIndex < len - 1) {
                     if (this.schoolSetting.period[this.curPriodIndex].semesters[this.curSemIndex + 1].month > (index + 1)) {
@@ -590,12 +670,19 @@ export default {
                 }
             }
             let curMonth = this.schoolSetting.period[this.curPriodIndex].semesters[this.curSemIndex].month
-            let nextMonth = -1
+            let nextMonth = -1 //下个学期的月份
             if (this.curSemIndex == len - 1) {
                 nextMonth = this.schoolSetting.period[this.curPriodIndex].semesters[0].month
             } else {
                 nextMonth = this.schoolSetting.period[this.curPriodIndex].semesters[this.curSemIndex + 1].month
             }
+            if (curMonth == nextMonth) {
+                return {
+                    color: (index + 1) == curMonth ? this.colorList[this.curSemIndex] : '#606060',
+                    text: this.schoolSetting.period[this.curPriodIndex].semesters[this.curSemIndex].name,
+                    showArrow: (index + 1) == curMonth
+                }
+            }
             if (curIndex != -1) {
                 return {
                     color: this.colorList[curIndex],
@@ -1092,25 +1179,26 @@ export default {
         },
         // 添加学期
         addSemester() {
-            let semLen = this.schoolSetting.period[this.curPriodIndex].semesters.length
-            if (semLen < this.TERM_MAX_LENGTH) {
-                let defMonth = semLen == 0 ? 1 : this.schoolSetting.period[this.curPriodIndex].semesters[semLen - 1].month + 1
-                this.schoolSetting.period[this.curPriodIndex].semesters.push({
-                    name: this.$t('schoolBaseInfo.persetSemester') + (this.schoolSetting.period[this.curPriodIndex].semesters.length + 1),
-                    month: defMonth,
-                    day: 26,
-                    id: this.guid()
-                })
-                this.countSemDays()
-                this.$nextTick(() => {
-                    setTimeout(() => {
-                        this.curSemIndex = this.schoolSetting.period[this.curPriodIndex].semesters.length - 1
-                        this.editSemIndex = this.curSemIndex
-                    }, 200)
-                })
-            } else {
-                this.$Message.info(this.$t('schoolBaseInfo.ssTips7'))
-            }
+            this.addSemStatus = true
+            // let semLen = this.schoolSetting.period[this.curPriodIndex].semesters.length
+            // if (semLen < this.TERM_MAX_LENGTH) {
+            //     let defMonth = semLen == 0 ? 1 : this.schoolSetting.period[this.curPriodIndex].semesters[semLen - 1].month + 1
+            //     this.schoolSetting.period[this.curPriodIndex].semesters.push({
+            //         name: this.$t('schoolBaseInfo.persetSemester') + (this.schoolSetting.period[this.curPriodIndex].semesters.length + 1),
+            //         month: defMonth,
+            //         day: 26,
+            //         id: this.guid()
+            //     })
+            //     this.countSemDays()
+            //     this.$nextTick(() => {
+            //         setTimeout(() => {
+            //             this.curSemIndex = this.schoolSetting.period[this.curPriodIndex].semesters.length - 1
+            //             this.editSemIndex = this.curSemIndex
+            //         }, 200)
+            //     })
+            // } else {
+            //     this.$Message.info(this.$t('schoolBaseInfo.ssTips7'))
+            // }
         },
         getLocalDefaultData() {
             let data = require('@/static/baseDataDefault.json')
@@ -1257,6 +1345,20 @@ export default {
             } else {
                 return []
             }
+        },
+        // 设置入学期提示
+        startWarning() {
+            let flag = true
+            if (this.schoolSetting.period && this.schoolSetting.period[this.curPriodIndex].semesters) {
+                this.schoolSetting.period[this.curPriodIndex].semesters.forEach(item => {
+                    if (item.start == 1) {
+                        flag = false
+                    }
+                })
+            } else {
+                flag = false
+            }
+            return flag
         }
 
     }

+ 462 - 0
TEAMModelOS/ClientApp/src/view/student-account/ClassMgt.less

@@ -0,0 +1,462 @@
+@main-bgColor: rgb(40,40,40); //主背景颜色
+@borderColor: #424242; //边框颜色
+@primary-textColor: #fff; //文本主颜色
+@second-textColor: #a5a5a5; //文本副级颜色
+@third-textColor: #dddddd;//其他颜色
+@fourth-textColor: #1cc0f3;
+@primary-fontSize: 14px;
+@second-fontSize: 16px;
+@large-fontSize: 20px;
+.class-mgt-container {
+    height: 100%;
+    width: 100%;
+    display: flex;
+    flex-direction: row;
+
+    .class-list-wrap {
+        width: 400px;
+        height: 100%;
+        border-right: 1px solid @borderColor;
+    }
+
+    .class-info-wrap {
+        width: ~"calc(100% - 400px)";
+        height: 100%;
+        padding-left:15px;
+    }
+}
+.class-list-header{
+    width:100%;
+    height:45px;
+    line-height:45px;
+    border-bottom:1px solid @borderColor;
+    padding-left:15px;
+    color:@second-textColor;
+}
+.action-btn {
+    float: right;
+    display: flex;
+    align-items: center;
+    margin-right: 15px;
+    &-icon {
+        color: white;
+        font-size: 16px;
+        margin-right: 12px;
+        margin-left: 10px;
+        cursor: pointer;
+
+        &.hide-icon {
+            display: none;
+        }
+    }
+}
+.class-info-header{
+    width:100%;
+    height:45px;
+    line-height:45px;
+    border-bottom:1px solid @borderColor;
+}
+.class-info-content{
+    width:100%;
+    height:~"calc(100% - 45px)";
+    position:relative;
+}
+.main-header-tab {
+    color: @second-textColor;
+    margin-right: 15px;
+    cursor: pointer;
+    position: relative;
+    display: inline-block;
+    line-height: 25px;
+}
+
+.border(right) {
+    border-right: 1px solid @borderColor;
+}
+.border(top) {
+    border-top: 1px solid @borderColor;
+}
+.border(left) {
+    border-left: 1px solid @borderColor;
+}
+.border(bottom) {
+    border-bottom: 1px solid @borderColor;
+}
+.container-left {
+    width: 59%;
+    height:100%;
+    .border(right);
+
+    &-title {
+        width: 100%;
+        padding-left: 15px;
+        height: 50px;
+        .border(bottom);
+        line-height: 50px;
+        padding-right: 35px;
+    }
+}
+.container-right {
+    width: 41%;
+    height:100%;
+
+    &-title {
+        width: 100%;
+        height: 45px;
+        line-height: 45px;
+        .border(bottom);
+    }
+}
+.first-title {
+    font-size: @primary-fontSize + 1;
+    color: @second-textColor;
+    font-weight:900;
+}
+
+.label-style {
+    font-size: @primary-fontSize - 1;
+    color: @second-textColor;
+    float: right;
+    margin-right: 40px;
+    cursor: pointer;
+}
+.label-style .label-icon{
+    margin-right:15px;
+}
+.save-btn {
+    margin-top: 5px;
+    /*color: black;*/
+    float: right;
+    margin-right: 30px;
+}
+.school-plan-wrap {
+    height: 100%;
+    width: 100%;
+    display: flex;
+    flex-flow: row;
+    align-items: center;
+    justify-content: center;
+}
+.school-plan-wrap p{
+    position:absolute;
+    top:0px;
+    right:0px;
+    padding:8px 35px 6px 20px;
+    .border(bottom);
+    color:white;
+    cursor:pointer;
+}
+.school-plan-wrap .label-icon {
+    margin-right: 15px;
+
+}
+.container-left-wrap{
+    width:100%;
+    height:~"calc(100% - 50px)";
+    display:flex;
+    flex-direction:row;
+}
+.container-left-box {
+    width: 38%;
+    height: 100%;
+    .border(right);
+    
+    .list-order {
+        padding: 5px 0px 5px 15px;
+        color: white;
+
+        .label-icon {
+            margin-right: 10px;
+        }
+    }
+}
+.container-right-box {
+    width: 62%;
+    height: 100%;
+    padding-left:15px;
+}
+.class-search-input{
+    width:~"calc(100% - 15px)";
+    margin-left:10px;
+    height:45px;
+    line-height:45px;
+}
+.class-list {
+    width: 100%;
+    height:~"calc(100% - 50px)";
+    padding-left: 15px;
+    
+}
+.active-item-bg {
+    background-image: linear-gradient(90deg, rgba(30,30,30,0) 0%, rgba(110,110,110,.2) 50%, rgba(110,110,110,.4) 100%);
+}
+.class-list-item {
+    padding: 8px 0px;
+    .border(bottom);
+    cursor:pointer;
+    position:relative;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;    
+    &:hover {
+        .active-item-bg,
+        .period-btn-edit {
+            display: inline-block;
+        }
+    }
+}
+.class-name {
+    font-size: @large-fontSize;
+    color: white;
+    font-weight: 500;
+}
+.second-text-color {
+    color: @second-textColor;
+    font-size: 12px;
+}
+.third-text-color{
+    color:@third-textColor;
+}
+.fourth-text-color {
+    color: #1cc0f3 !important;
+    /*text-shadow:1px 1px 1px white;*/
+}
+.class-hiteach-code {
+    margin-top:5px;
+}
+.class-type {
+    margin-top:6px;
+    margin-bottom:4px;
+    align-items: center;
+    display: flex;
+    span{
+        color: rgb(28, 192, 243);
+    }
+}
+.iconHi{
+    display: inline-block;
+    margin-right: 5px;
+    width: 14px;
+    height: 14px;
+}
+.iconBoard {
+    width: 14px;
+    height: 14px;
+    background: rgb(165, 165, 165);
+    border-radius: 16%;
+    display: inline-flex;
+    justify-content: center;
+    align-items: center;
+    margin-right: 5px;
+}
+.primary-text-color{
+    color:@primary-textColor;
+}
+
+.class-attr-wrap{
+    width:35%;
+    height:100%;
+    .border(right);
+    &-label{
+        display:inline-block;
+        color:@second-textColor;
+        font-size:@second-fontSize - 4px;
+    }
+}
+.hiteach-code-wrap {
+    width: 100%;
+    height: 100%;
+    position: relative;
+    &-header {
+        width: ~"calc(100% - 30px)";
+        margin-left: 20px;
+
+        p {
+            padding: 10px 0px;
+            color: @second-textColor;
+            .border(bottom);
+        }
+    }
+
+    &-list {
+        .border(top);
+        width: 100%;
+        height: ~"calc(100% - 72px)";
+        padding-left: 25px;
+        h1 {
+            font-weight: 400;
+        }
+
+        ul {
+            list-style: none;
+
+            li {
+                color: #dbdbdb;
+                display: flex;
+                align-items: center;
+                margin-bottom: 5px;
+            }
+        }
+    }
+}
+#school-plan {
+    background: none;
+}
+.school-plan-zoom {
+    position: absolute;
+    right: 150px;
+    top: 10px;
+    -webkit-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    .ivu-icon {
+        margin-right: 10px;
+        cursor: pointer;
+    }
+
+    span {
+        color: white;
+        font-size: 16px;
+        margin-right: 15px;
+        display: inline-block;
+        letter-spacing: 3px;
+        cursor: pointer;
+    }
+}
+.school-plan-box {
+    width: ~"calc(100% - 60px)";
+    max-height: 90%;
+    overflow: scroll;
+    text-align: center;
+
+    &::-webkit-scrollbar { /*滚动条整体样式*/
+        width: 5px; /*高宽分别对应横竖滚动条的尺寸*/
+        height: 8px;
+    }
+
+    &::-webkit-scrollbar-thumb { /*滚动条里面小方块*/
+        -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
+        background: rgb(124,124,124);
+    }
+
+    &::-webkit-scrollbar-track { /*滚动条里面轨道*/
+        -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
+        background: rgba(68,68,68,.5);
+    }
+}
+.hiteach-collapse{
+    border-bottom: 1px solid #424242;
+    position: relative;
+    cursor: pointer;
+    &-main{
+        display: flex;
+        align-items: center;
+        padding: 20px 0 20px 20px;
+        &:hover{
+            background-image: linear-gradient(90deg, rgba(30,30,30,0) 0%, rgba(110,110,110,.2) 50%, rgba(110,110,110,.4) 100%);
+        }
+        .arrowIcon{
+            position: absolute;
+            right: 5px;
+            top: 20px;
+        }
+        .proIcon{
+            width: 60px;
+            height: 60px;
+            margin-right: 30px;
+        }
+        .proCont{
+            font-size: 12px;
+            letter-spacing: 1px;
+            ul li{
+                .title{
+                    display: inline-block;
+                    margin-right: 12px;
+                    font-size: 16px;
+                    font-weight: 500;
+                    color: #bdbdbd;
+                    color:white;
+                }
+                .serialType{
+                    margin-right: 12px;
+                    padding: 2px 5px;
+                    background: #1cc0f3;
+                    border-radius: 3px;
+                    color: white;
+                }
+                .tag{
+                    display: inline-block;
+                    border: 1px solid #8d8d8d;
+                    padding: 3px 10px;
+                    color: #8d8d8d;
+                    margin-top: 5px;
+                    margin-right: 10px;
+                    border-radius: 5px;
+                    &.active{
+                        color: #1cc0f3!important;
+                        border-color: #1cc0f3!important;
+                    }
+                }
+            }
+        }
+    }
+    .hiteach-collapse-sub{
+        display: flex;
+        align-items: center;
+        border-top: 1px solid rgb(66, 66, 66);
+        margin-left: 20px;
+        letter-spacing: 1px;
+        font-size: 12px;
+        padding: 20px;        
+        &:hover{
+            background-image: linear-gradient(90deg, #2a2a2e, #293942);
+        }
+        &-detail{
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            width: 100%;
+        }
+        &.linked{
+            ul li{
+                color: #888888;
+            }            
+            cursor: not-allowed;
+        }
+        &-linkBtn{
+            cursor: pointer;
+            border-radius: 5px;
+            padding: 5px 12px;
+            font-size: 12px;
+            background-color: #1cc0f3;
+            color: white;
+            text-align: center;
+            font-weight: 700;
+            margin-right: 70px;
+            border-color: transparent;
+            &:hover{
+                background-color: #0ba2d1;
+            }
+        }
+    }
+}
+
+.class-id-tag {
+    color: aqua;
+    font-size: 14px;
+    margin-right: 5px;
+    border: 1px solid aqua;
+    padding: 1px 3px;
+    border-radius: 3px;
+    vertical-align:middle;
+}
+.item-tools{
+    display:none;
+}
+
+.reset-no-btn{
+    display: inline-block;
+    margin-left: 10px;
+    cursor: pointer;
+}

+ 876 - 0
TEAMModelOS/ClientApp/src/view/student-account/ClassMgt.vue

@@ -0,0 +1,876 @@
+<template>
+    <div class="class-mgt-container">
+        <Loading v-show="isListLoading"></Loading>
+        <div class="class-list-wrap">
+            <!--班级列表-->
+            <div class="class-list-header">
+                <Dropdown class="sort-dropdown" trigger="click" placement="bottom-start" @on-click="function(e){ filterPeriod = e }" @on-visible-change="dropdownStates" v-if="$store.state.user.schoolProfile.school_base">
+                    <span style="cursor: pointer;">
+                        <!-- {{$t('schoolBaseInfo.pdLabel')}} -->
+                        <b class="title">{{ filterPeriodName }}</b>
+                        <Icon type="ios-arrow-down" style="margin-left:8px;"></Icon>
+                    </span>
+                    <DropdownMenu slot="list" v-for="(item,index) in periods" :value="item.id" :key="index">
+                        <DropdownItem :name="item.id">{{ item.name }}</DropdownItem>
+                    </DropdownMenu>
+                </Dropdown>
+                <Dropdown class="sort-dropdown" trigger="click" placement="bottom-start" @on-click="function(e){ filterYear = e }" style="margin-left:15px">
+                    <span style="cursor: pointer;">
+                        <!-- {{$t('schoolBaseInfo.pdLabel')}} -->
+                        <!-- <b class="title">{{ filterYear + '级' }}</b> -->
+                        <b class="title">{{ filterYear}}</b>
+                        <Icon type="ios-arrow-down" style="margin-left:8px;"></Icon>
+                    </span>
+                    <DropdownMenu slot="list" v-for="(item,index) in years" :value="item.value" :key="index">
+                        <DropdownItem :name="item.label">{{ item.label }}</DropdownItem>
+                    </DropdownMenu>
+                </Dropdown>
+                <div v-if="!isSearch" style="float:right;">
+                    <Icon class="action-btn-icon" type="ios-search" @click="isSearch = true" />
+                    <Icon v-if="$access.can('admin.*|classroom-upd')" class="action-btn-icon" type="md-trash" @click.stop="showConfirmDelete()" />
+                    <Icon v-if="$access.can('admin.*|classroom-upd')" class="action-btn-icon" type="md-add" @click="addClassroom()" />
+                </div>
+                <div v-else class="dark-iview-input" style="float:right;width:calc(100% - 200px);padding-right:10px;">
+                    <Input icon="ios-close" v-model="keyword" :placeholder="$t('schoolBaseInfo.codeSearchHolder')" autofocus style="width:100%" @on-click="closeKeySearch" @on-change="filterClassname" />
+                </div>
+            </div>
+            <div class="class-list">
+                <vuescroll>
+                    <div class="class-list-item" v-for="(item,index) in classroomListShow" :key="index" @click="chooseClassroom(index)" :class="curClassIndex == index ? 'block-bg block-bg-active':'block-bg'">
+                        <div class="class-list-item-left">
+                            <!-- <p style="color: #a5a5a5;">{{$jsFn.getGradeName(schoolBase,item.gradeId)}}</p> -->
+                            <p style="color: #a5a5a5;">2020级</p>
+                            <p class="class-name">
+                                <span class="class-id-tag">
+                                    {{item.no}}
+                                </span>
+                                <span>
+                                    {{item.name}}
+                                </span>
+                            </p>
+                            <p class="class-type">
+                            <p class="second-text-color">
+                                <span>{{ $t('schoolBaseInfo.headmaster') }}</span>
+                                <span class="primary-text-color">{{item.teacher.name}}</span>
+                                <span style="margin-left:15px">学生人数:</span>
+                                <span class="primary-text-color">40人</span>
+                            </p>
+                        </div>
+                    </div>
+                    <EmptyData v-if="classroomListShow.length == 0" style="padding-top:120px;"></EmptyData>
+                </vuescroll>
+            </div>
+        </div>
+        <div class="class-info-wrap">
+            <div class="class-info-header common-save-btn">
+                <span :class="currentTabIndex == 0 ? 'main-header-tab line-bottom line-bottom-active':'main-header-tab line-bottom'" @click="selectTab(0)">
+                    {{$t('schoolBaseInfo.tab1')}}
+                </span>
+                <span :class="currentTabIndex == 2 ? 'main-header-tab line-bottom line-bottom-active':'main-header-tab line-bottom'" @click="selectTab(2)">
+                    {{$t('schoolBaseInfo.tab2')}}
+                </span>
+                <!-- 编辑教室 -->
+                <Button v-if="$access.can('admin.*|classroom-upd')" class="save-btn" :loading="isSaveLoading" :disabled="!updated" icon="ios-albums-outline" @click="saveClassroom()" v-show="currentTabIndex == 0">
+                    {{$t('schoolBaseInfo.saveInfo')}}
+                </Button>
+                <!-- 添加学生 -->
+                <Button v-if="$access.can('admin.*|student-upd')" class="save-btn" :loading="isSaveLoading" icon="md-add" @click="addStuStatus = true" v-show="currentTabIndex == 2">
+                    {{$t('schoolBaseInfo.addStuBtn')}}
+                </Button>
+                <!-- 移除学生 -->
+                <Button v-if="$access.can('admin.*|student-upd')" class="save-btn" style="margin-right:10px;" :loading="isSaveLoading" icon="md-remove-circle" @click="removeStudent(-1)" v-show="currentTabIndex == 2">
+                    {{$t('schoolBaseInfo.delStuBtn')}}
+                </Button>
+            </div>
+            <div class="class-info-content">
+                <!--基础信息-->
+                <div v-show="currentTabIndex == 0" style="display:flex;flex-direction:row;width:100%;height:100%;">
+                    <!--班级属性-->
+                    <div class="class-attr-wrap disabled-iview-select dark-iview-select">
+                        <vuescroll>
+                            <Form v-if="classroomListShow[curClassIndex]" ref="classInfo" :model="classroomListShow[curClassIndex]" :rules="classValidate" style="padding-top:20px;">
+                                <FormItem prop="name" :label="$t('schoolBaseInfo.classroomName')" @click.native.stop class="requird-color">
+                                    <span slot="label" class="class-attr-wrap-label">名称</span>
+                                    <Input @on-change="watchUpdate" :disabled="editStatus" v-model="classroomListShow[curClassIndex].name" clearable :placeholder="$t('schoolBaseInfo.classroomNameHolder')" />
+                                </FormItem>
+                                <FormItem prop="no" @click.native.stop class="requird-color">
+                                    <span slot="label" class="class-attr-wrap-label">编码</span>
+                                    <Input @on-change="watchUpdate" :disabled="editStatus" v-model="classroomListShow[curClassIndex].no" clearable :placeholder="$t('schoolBaseInfo.classroomCodeHolder')" />
+                                </FormItem>
+                                <FormItem prop="gradeId" :label="$t('schoolBaseInfo.setGrade')" @click.native.stop class="requird-color">
+                                    <span slot="label" class="class-attr-wrap-label">学级</span>
+                                    <Select @on-change="watchUpdate" :disabled="editStatus" v-model="classroomListShow[curClassIndex].gradeId" clearable>
+                                        <Option v-for="(item,index) in $jsFn.getPeriod($store.state.user.schoolProfile.school_base,classroomListShow[curClassIndex].periodId).grades" :value="item.id" :key="index">
+                                            {{ item.name }}
+                                        </Option>
+                                    </Select>
+                                </FormItem>
+                                <FormItem prop="teacher" :label="$t('schoolBaseInfo.headmaster')" @click.native.stop class="requird-color">
+                                    <span slot="label" class="class-attr-wrap-label">{{$t('schoolBaseInfo.headmaster')}}</span>
+                                    <Select @on-change="watchUpdate" :disabled="editStatus" v-model="classroomListShow[curClassIndex].teacher.id" clearable filterable>
+                                        <Option v-for="(item,index) in $store.state.teachers.teacherList.filter(item=>item.status == 'join')" :value="item.id" :key="index" @click.native="classroomListShow[curClassIndex].teacher = {id:item.id, name:item.name}">
+                                            {{ item.name }}
+                                        </Option>
+                                    </Select>
+                                </FormItem>
+                                <FormItem prop="profession" @click.native.stop class="requird-color">
+                                    <span slot="label" class="class-attr-wrap-label">专业</span>
+                                    <Select @on-change="watchUpdate" :disabled="editStatus" v-model="classroomListShow[curClassIndex].marjorId" clearable not-found-text="暂未设置专业">
+                                        <Option v-for="(item,index) in $jsFn.getPeriod($store.state.user.schoolProfile.school_base,classroomListShow[curClassIndex].periodId).majors" :value="item.id" :key="index">
+                                            {{ item.name }}
+                                        </Option>
+                                    </Select>
+                                </FormItem>
+                                <FormItem prop="profession" @click.native.stop class="requird-color">
+                                    <span slot="label" class="class-attr-wrap-label">默认教室</span>
+                                    <Select @on-change="watchUpdate" :disabled="editStatus" v-model="classroomListShow[curClassIndex].roomId" clearable not-found-text="暂无教室">
+                                        <Option v-for="(item,index) in $jsFn.getPeriod($store.state.user.schoolProfile.school_base,classroomListShow[curClassIndex].periodId).majors" :value="item.id" :key="index">
+                                            {{ item.name }}
+                                        </Option>
+                                    </Select>
+                                </FormItem>
+                            </Form>
+                        </vuescroll>
+                    </div>
+                </div>
+
+                <!--学生名单-->
+                <div id="sut-list-box" class="dark-iview-table dark-iview-input" style="width:100%;height:100%;" v-show="currentTabIndex == 2">
+                    <vuescroll style="height:100%;" v-if="classroomListShow[curClassIndex]">
+                        <Table :columns="studentColumn" :data="students" @on-selection-change="(selections)=>{delSelections = selections}" :height="tableHeight" class="system-classroom-table" :loading="stuLoading" :no-data-text="$t('schoolBaseInfo.noStu')">
+                            <Loading slot="loading" :top="0" bgColor="rgba(103, 103, 103, 0.27)"></Loading>
+                            <template slot-scope="{ row }" slot="picture">
+                                <PersonalPhoto :name="row.name" :picture="row.picture" />
+                            </template>
+                            <template slot-scope="{ row,index }" slot="no">
+                                <span v-show="editIndex !== index">{{row.no}}</span>
+                                <Input v-model="students[index].no" v-show="editIndex == index" style="width: 60px;" type="number" />
+                                <Icon type="md-checkmark" v-show="editIndex == index" @click="confirmSetNo()" class="reset-no-btn" />
+                                <Icon type="md-close" v-show="editIndex == index" @click="cancelSetNo()" class="reset-no-btn" />
+                            </template>
+                            <template slot-scope="{ row ,index}" slot="action">
+                                <div class="item-tools" v-if="$access.can('admin.*|student-upd')">
+                                    <Icon type="md-create" size="18" color="white" @click="resetNo(index)" :title="$t('schoolBaseInfo.editSeat')" />
+                                    <Icon type="md-remove-circle" size="18" color="white" style="margin-left:10px" @click="removeStudent(index)" :title="$t('schoolBaseInfo.delStuBtn')" />
+                                </div>
+                            </template>
+                        </Table>
+                    </vuescroll>
+                </div>
+            </div>
+        </div>
+        <Modal v-model="addStuStatus" :title="$t('schoolBaseInfo.addStuBtn')" width="1200" @on-ok="confirmAddStu" class-name="dark-iview-modal">
+            <StudentList @getSelectInfo="(selction)=>{selections = selction}"></StudentList>
+        </Modal>
+    </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import PersonalPhoto from "@/components/public/personalPhoto/Index.vue"
+import StudentList from '@/components/coursemgt/StudentList.vue'
+export default {
+    components: {
+        PersonalPhoto, StudentList
+    },
+    data() {
+        // 验证只能是字母和数字
+        const validateCode = (rule, value, callback) => {
+            if (!value) {
+                return callback(new Error(this.$t('schoolBaseInfo.classNoErr')))
+            }
+            let zg = /^[0-9a-zA-Z]+$/
+            if (zg.test(value)) {
+                callback()
+            } else {
+                callback(new Error(this.$t('schoolBaseInfo.classNoErr1')))
+            }
+        }
+        return {
+            filterYear:'',
+            // years:[2021,2020,2019,2018,2017,2016,2015,2014],
+            studentColumn: [
+                {
+                    title: ' ',
+                    type: 'selection',
+                    width: 60,
+                    align: 'center'
+                },
+                {
+                    title: ' ',
+                    slot: 'picture',
+                    align: 'center ',
+                    width: '150'
+                },
+                {
+                    title: this.$t('courseManage.classroom.studentTableC2'),
+                    key: 'name',
+                    align: 'center '
+                },
+                {
+                    title: this.$t('courseManage.classroom.studentTableC7'),
+                    key: 'id',
+                    align: 'center',
+                    sortable: true
+                },
+                {
+                    title: this.$t('courseManage.classroom.studentTableC1'),
+                    slot: 'no',
+                    align: 'center',
+                    sortable: true
+                },
+                {
+                    title: ' ',
+                    slot: 'action',
+                    align: 'center',
+                    width: '150'
+                }
+            ],
+            editIndex: -1,
+            resetNoBef: 0,
+            schoolBase: {
+                period: []
+            },
+            delSelections: [],//需要移除的学生
+            selections: [],//添加的学生
+            addStuStatus: false,
+            stuLoading: false,
+            orderBy: 'id',
+            updateBefore: '',
+            filterPeriod: undefined,
+            editStatus: true,//可切换编辑状态
+            noStatus: false,
+            isSearch: false,
+            currentTabIndex: 0,
+            isListLoading: false,
+            isSaveLoading: false,
+            isInit: true,
+            updated: false,
+            classroomList: [],
+            classroomListShow: [],
+            curClassIndex: 0,
+            keyword: '',
+            serchCode: '',
+            attributeList: [
+                {
+                    value: '1',
+                    label: this.$t('schoolBaseInfo.classAttr1')
+                },
+                {
+                    value: '2',
+                    label: this.$t('schoolBaseInfo.classAttr2')
+                }
+            ],
+            classValidate: {
+                no: [
+                    { required: true, validator: validateCode, trigger: 'change' }
+                ],
+                name: [
+                    { required: true, message: this.$t('schoolBaseInfo.nameWarning'), trigger: 'change' }
+                ],
+                openType: [
+                    { required: true, message: this.$t('schoolBaseInfo.typeWarning'), trigger: 'change' }
+                ],
+                gradeId: [
+                    { required: true, message: this.$t('schoolBaseInfo.gradeWarning'), trigger: 'change' }
+                ]
+            }
+        }
+    },
+    computed: {
+        ...mapGetters({
+            periods: 'user/getPeriods', // 學制s
+        }),
+        filterPeriodName: function () {
+            let data = this.periods
+            let pId = this.filterPeriod
+            let name = ''
+            if (pId !== '') {
+                let temp = data.filter(item => {
+                    return pId == item.id
+                })
+                if (temp.length > 0) name = temp[0].name
+            }
+            return name
+        },
+
+        students() {
+            if (this.currentTabIndex == '2') {
+                if (this.classroomListShow[this.curClassIndex] && this.classroomListShow[this.curClassIndex].students) {
+                    return this.classroomListShow[this.curClassIndex].students
+                } else {
+                    let params = {
+                        'school_code': this.$store.state.userInfo.schoolCode,
+                        'ids': [this.classroomListShow[this.curClassIndex].id],
+                        'scope': 'school'
+                    }
+                    this.stuLoading = true
+                    this.$api.schoolSetting.getClassroomStudent(params).then(
+                        res => {
+                            if (res.stus.length > 0) {
+                                this.$set(this.classroomListShow[this.curClassIndex], 'students', res.stus[0])
+                            }
+                        },
+                        err => {
+                            this.$Message.error(this.$t('schoolBaseInfo.findStuErr'))
+                        }
+                    ).finally(() => {
+                        this.stuLoading = false
+                    })
+                }
+            } else {
+                return []
+            }
+        },
+
+        years(){
+            if(this.schoolBase && this.schoolBase.period.length && this.filterPeriod){
+                let pData = this.schoolBase.period.find(item=>{
+                    return item.id == this.filterPeriod
+                })
+                if(pData){
+                    let date = new Date()
+                    let year = date.getFullYear()
+                    let month = date.getMonth() + 1
+                    let start = pData.semesters.find(item => {
+                        return item.start == 1
+                    })
+                    // 根据入学月份确定当前年级和学级的关系
+                    if (start && month < start.month) {
+                        year--
+                    }
+                    let res = pData.grades.map(item=>{
+                        return {
+                            label:`${item.name}(${year}级)`,
+                            value:year--
+                        }
+                    })
+                    this.filterYear = res[0].label
+                    return res
+                }else{
+                    return []
+                }
+            }
+            return []
+        }
+    },
+    methods: {
+        resetNo(index) {
+            this.editIndex = index
+            this.resetNoBef = this.students[index].no
+        },
+        confirmSetNo() {
+            this.$Message.warning('暂未对接API')
+            this.editIndex = -1
+        },
+        cancelSetNo() {
+            this.students[this.editIndex].no = this.resetNoBef
+            this.editIndex = -1
+        },
+        //移除班级里面的学生
+        removeStudent(index) {
+            let requestParams = {
+                schoolId: this.$store.state.userInfo.schoolCode,
+                students: [],
+                grant_type: 'remove'
+            }
+            let names = []
+            if (index > -1) {
+                requestParams.students.push(this.students[index].id)
+                names = [this.students[index].name]
+            } else if (this.delSelections.length > 0) {
+                requestParams.students = this.delSelections.map(item => {
+                    return item.id
+                })
+                names = this.delSelections.map(item => {
+                    return item.name
+                })
+            }
+            if (requestParams.students.length) {
+                this.$Modal.confirm({
+                    title: this.$t('schoolBaseInfo.removeTile'),
+                    content: `${this.$t('schoolBaseInfo.removeContent')}${names.join(', ')}?`,
+                    onOk: () => {
+                        this.$api.stuAccount.removeStudent(requestParams).then(
+                            res => {
+                                this.$Message.success(this.$t('schoolBaseInfo.removeOk'))
+                                if (index > -1) {
+                                    this.students.splice(index, 1)
+                                } else {
+                                    for (let i = 0; i < this.students.length; i) {
+                                        if (requestParams.students.indexOf(this.students[i].id) > -1) {
+                                            this.students.splice(i, 1)
+                                            i--
+                                        }
+
+                                    }
+                                    this.students.forEach()
+                                }
+                            },
+                            err => {
+                                this.$Message.error(this.$t('schoolBaseInfo.removeErr'))
+                            }
+                        )
+                    }
+                })
+            }
+        },
+        //确认添加学生
+        confirmAddStu() {
+            if (this.selections.length > 0) {
+                console.log(this.selections)
+                let data = this._.cloneDeep(this.selections)
+                data.forEach(item => {
+                    item.classId = this.classroomListShow[this.curClassIndex].id
+                    item.className = this.classroomListShow[this.curClassIndex].name
+                    item.classNo = this.classroomListShow[this.curClassIndex].no
+                })
+
+                this.listLoading = true
+                this.$api.stuAccount.updateStudent({
+                    students: data,
+                    grant_type: 'update',
+                    schoolId: this.$store.state.userInfo.schoolCode
+                }).then(
+                    (res) => {
+                        if (!res.error) {
+                            this.selections.length = 0
+                            this.students.push(...data)
+                            this.$Message.success(this.$t('schoolBaseInfo.addOk'))
+                        } else {
+                            this.$Message.error(this.$t('schoolBaseInfo.addErr'))
+                        }
+                    },
+                    (err) => {
+                        this.$Message.error(this.$t('schoolBaseInfo.addErr'))
+                    }
+                ).finally(() => {
+                    this.listLoading = false
+                    this.baseEditStatus = !this.baseEditStatus
+                })
+            }
+        },
+
+        dropdownStates(flag) {
+            if (!flag) this.filterByPeriod()
+        },
+        restOrderBy(flag) {
+            if (!flag) this.filterByPeriod()
+        },
+        closeKeySearch() {
+            this.isSearch = false
+            this.keyword = ''
+            this.filterClassname()
+        },
+        watchUpdate(data) {
+            if (data) {
+                this.updated = true
+            }
+        },
+        dataSort(data) {
+            switch (this.orderBy) {
+                case 'id': // no=>编号 排序
+                    data.sort(function (a, b) {
+                        let nameA = a.no.toUpperCase(); // ignore upper and lowercase
+                        let nameB = b.no.toUpperCase(); // ignore upper and lowercase
+                        if (nameA < nameB) {
+                            return -1;
+                        }
+                        if (nameA > nameB) {
+                            return 1;
+                        }
+
+                        // names must be equal
+                        return 0;
+                    })
+                    break;
+                case 'total':
+                    data.sort(function (a, b) {
+                        return b.studCount - a.studCount;
+                    })
+                    break;
+            }
+            return data
+        },
+        filterByPeriod() {
+            this.curClassIndex = 0
+            if (this.filterPeriod) {
+                this.classroomListShow = this.classroomList.filter(item => item.periodId == this.filterPeriod || !item.periodId)
+            } else {
+                this.classroomListShow = [...this.classroomList]
+            }
+            // 排序
+            this.classroomListShow = this.dataSort(this.classroomListShow)
+
+        },
+        filterClassname() {
+            if (this.keyword == '' || this.keyword == undefined) {
+                this.filterByPeriod()
+            } else {
+                let filterRes = []
+                if (this.filterPeriod) {
+                    filterRes = this.classroomList.filter(item => item.periodId == this.filterPeriod)
+                } else {
+                    filterRes = [...this.classroomList]
+                }
+                this.classroomListShow = filterRes.filter(item => item.name.indexOf(this.keyword) != -1)
+                // 排序
+                this.classroomListShow = this.dataSort(this.classroomListShow)
+                this.curClassIndex = 0
+                this.updateBefore = JSON.stringify(this.classroomListShow[this.curClassIndex])
+            }
+        },
+        selectTab(index) {
+            this.currentTabIndex = index
+        },
+        saveClassroom() {
+            this.$refs['classInfo'].validate((valid) => {
+                if (!valid) {
+                    this.$Message.error(this.$t('schoolBaseInfo.formWarning'))
+                } else {
+                    let option = this.classroomListShow[this.curClassIndex].option
+                    if (!option) {
+                        option = 'update'
+                    } else {
+                        this.classroomListShow[this.curClassIndex]['code'] = this.$store.state.userInfo.schoolCode
+                    }
+                    delete this.classroomListShow[this.curClassIndex].option
+                    this.isSaveLoading = true
+                    this.isListLoading = true
+                    if (this.classroomListShow[this.curClassIndex].openType == '2') {
+                        this.classroomListShow[this.curClassIndex].teacher.id = ''
+                        this.classroomListShow[this.curClassIndex].teacher.name = ''
+                    }
+                    this.$api.schoolSetting.classUpsert({
+                        classroom: this.classroomListShow[this.curClassIndex],
+                        option: option,
+                        school_code: this.$store.state.userInfo.schoolCode
+                    }).then(
+                        res => {
+                            if (res) {
+                                if (res.error) {
+                                    this.classroomListShow[this.curClassIndex].option = option
+                                    this.$Message.error(res.v)
+                                } else {
+                                    this.$Message.success(this.$t('schoolBaseInfo.csTips3'))
+                                    this.updated = false
+                                    if (option == 'insert') {
+                                        this.classroomListShow[this.curClassIndex].code = 'Class-' + this.classroomListShow[this.curClassIndex].code
+                                        this.classroomList.unshift(this.classroomListShow[this.curClassIndex])
+                                        this.$store.dispatch('user/addSchoolClasses', this.classroomListShow[this.curClassIndex]);
+                                    }
+                                }
+                            } else {
+                                this.$Message.error('API error!')
+                            }
+                        },
+                        err => {
+                            this.$Message.error('API error!')
+                        }
+                    ).finally(
+                        () => {
+                            this.isSaveLoading = false
+                            this.isListLoading = false
+                        }
+                    )
+                }
+            })
+        },
+        getClassroom() {
+            this.isListLoading = true
+            this.$store.dispatch('user/getSchoolProfile').then(
+                (res) => {
+                    if (res) {
+                        this.classroomList = res.school_classes
+                        this.schoolBase = res.school_base
+                        if (this.classroomList.length > 0) {
+                            this.updateBefore = JSON.stringify(this.classroomList[0])
+                        }
+                        this.filterClassname()
+                        // 預設搜尋給第一個
+                        if (this.periods) this.filterPeriod = this.periods[0].id
+                        this.filterByPeriod()
+                    }
+                },
+                (err) => {
+                    this.$Message.error('API error!')
+                }
+            ).finally(() => {
+                setTimeout(() => {
+                    this.isListLoading = false
+                }, 500)
+            })
+        },
+        /**显示确认删除班级对话框 */
+        showConfirmDelete() {
+            if (this.$access.can('admin.*|classroom-upd')) {
+                this.$Modal.confirm({
+                    title: this.$t('schoolBaseInfo.delClass'),
+                    content: this.$t('schoolBaseInfo.delete') + this.classroomListShow[this.curClassIndex].name + this.$t('schoolBaseInfo.delContent'),
+                    onOk: () => {
+                        this.delClassroom(this.curClassIndex)
+                    }
+                })
+            } else {
+                this.$Message.warning(this.$t('schoolBaseInfo.authWarning'))
+            }
+        },
+        delClassroom(index) {
+            this.isListLoading = true
+            if (this.classroomListShow[index].option !== 'insert') {
+                this.$api.schoolSetting.delClassroom({
+                    id: this.classroomListShow[index].id,
+                    scope: this.classroomListShow[index].scope,
+                    school_code: this.$store.state.userInfo.schoolCode
+                }).then(
+                    (res) => {
+                        if (res.error == null) {
+                            if (this.curClassIndex >= index && index > 0) {
+                                this.curClassIndex = 0
+                                this.updateBefore = JSON.stringify(this.classroomListShow[this.curClassIndex])
+                            }
+                            let originIndex = -1
+                            for (let i in this.classroomList) {
+                                if (this.classroomList[i].id == this.classroomListShow[index].id) {
+                                    originIndex = i
+                                    break
+                                }
+                            }
+                            this.$api.schoolSetting.hiteachUnlinkByClassId({
+                                classId: this.classroomListShow[index].id,
+                                school_code: this.$store.state.userInfo.schoolCode
+                            })                             
+                            this.$store.dispatch('user/delSchoolClasses', this.classroomListShow[index].id);
+                            this.classroomList.splice(originIndex, 1)
+                            this.classroomListShow.splice(index, 1)
+                            this.$Message.success(this.$t('schoolBaseInfo.csTips7'))
+                            this.updated = false
+                        }
+                    },
+                    (err) => {
+                        this.$Message.error('API error!')
+                    }
+                ).finally(() => {
+                    this.isListLoading = false
+                })
+            } else {
+                if (this.curClassIndex >= index && index > 0) {
+                    this.curClassIndex = 0
+                    this.updateBefore = JSON.stringify(this.classroomListShow[this.curClassIndex])
+                }
+                this.classroomListShow.splice(index, 1)
+                this.isListLoading = false
+                this.updated = false
+            }
+        },
+        chooseClassroom(index) {
+            if (index != this.curClassIndex) {
+                if (this.updated) {
+                    let config = {
+                        title: this.$t('schoolBaseInfo.saveWarning'),
+                        content: this.$t('schoolBaseInfo.saveClassWarning'),
+                        okText: this.$t('schoolBaseInfo.leaveText'),
+                        onOk: () => {
+                            if (this.classroomListShow[this.curClassIndex].option == 'insert') {
+                                this.delClassroom(this.curClassIndex)
+                            } else {
+                                this.updated = false
+                                this.$set(this.classroomListShow, this.curClassIndex, JSON.parse(this.updateBefore))
+                                this.curClassIndex = index
+                                this.updateBefore = JSON.stringify(this.classroomListShow[this.curClassIndex])
+                            }
+                        }
+                    }
+                    this.$Modal.confirm(config)
+                } else {
+                    this.curClassIndex = index
+                    this.updateBefore = JSON.stringify(this.classroomListShow[this.curClassIndex])
+                }
+            }
+        },
+        addClassroom() {
+            if (this.$access.can('admin.*|classroom-upd')) {
+                this.keyword = ''
+                this.classroomListShow.unshift({
+                    id: this.$jsFn.uuid(),
+                    name: this.$t('schoolBaseInfo.presetClassroomName') + (this.classroomList.length + 1),
+                    no: '',
+                    teacher: {
+                        id: '',
+                        name: ''
+                    },
+                    periodId: this.filterPeriod,
+                    gradeId: '',
+                    scope: 'school',
+                    option: 'insert'
+                })
+                this.curClassIndex = 0
+                this.updateBefore = JSON.stringify(this.classroomListShow[this.curClassIndex])
+            } else {
+                this.$Message.warning(this.$t('schoolBaseInfo.authWarning'))
+            }
+        },
+
+    },
+    mounted() {
+        this.filterClassname()
+        this.tableHeight = document.getElementById('class-mgt-list').clientHeight - 45
+    },
+    beforeRouteLeave(to, from, next) {
+        if (this.updated) {
+            let config = {
+                title: this.$t('schoolBaseInfo.saveWarning'),
+                content: this.$t('schoolBaseInfo.saveClassWarning'),
+                okText: this.$t('schoolBaseInfo.leaveText'),
+                onOk: () => {
+                    next()
+                },
+                onCancel: () => {
+                    next(false)
+                }
+            }
+            this.$Modal.confirm(config)
+        } else {
+            next()
+        }
+    },
+    created() {
+        this.$store.dispatch('user/getSchoolProfile').then(
+            res => {
+                this.schoolBase = res.school_base
+            }
+        )
+        if (this.$access.can('admin.*|classroom-upd')) this.editStatus = this.noStatus
+        this.getClassroom()
+        this.$store.dispatch('teachers/getTeacherList').then(res => { })
+    }
+}
+</script>
+<style lang="less" scoped>
+@import "./ClassMgt.less";
+</style>
+<style>
+.class-mgt-container .ivu-table-row-hover .item-tools {
+    display: inline-block;
+    cursor: pointer;
+}
+.class-info-content
+    .ivu-select-single
+    .ivu-select-selection
+    .ivu-select-placeholder,
+.class-info-content
+    .ivu-select-single
+    .ivu-select-selection
+    .ivu-select-selected-value {
+    color: white;
+}
+
+.class-search-input .ivu-input {
+    height: 30px;
+    background: none;
+    line-height: 30px;
+    border: none;
+    color: white;
+    font-size: 15px;
+}
+
+.class-attr-wrap .ivu-input {
+    width: calc(100% - 10px);
+    background: none;
+    border: none;
+    border-radius: 0px;
+    font-size: 16px;
+    color: white;
+    margin-left: 2px;
+    border-bottom: 1px solid #424242;
+}
+
+.class-attr-wrap .ivu-select {
+    width: calc(100% - 10px);
+    color: white;
+}
+
+.class-attr-wrap .ivu-select-selected-value {
+    font-size: 16px !important;
+}
+
+.class-attr-wrap .ivu-select-selection {
+    background: none;
+    border-color: #424242;
+}
+
+.class-attr-wrap .ivu-divider {
+    background-color: #424242;
+}
+
+</style>
+<style lang="less">
+.gradient {
+    @keyframes Itemfadein {
+        0% {
+            opacity: 0;
+            transform: translate(-40px);
+        }
+        100% {
+            opacity: 1;
+            transform: translate(0px);
+        }
+    }
+    animation: 0.5s Itemfadein;
+}
+
+.sort-dropdown {
+    .title {
+        color: white;
+        font-size: 14px;
+    }
+    .ivu-select-dropdown {
+        background-color: #2d2d2d;
+        border-radius: 2px;
+        border: 1px #464646 solid;
+        .ivu-dropdown-menu {
+            li {
+                color: #ccc;
+                font-size: 12px !important;
+                &:hover {
+                    color: #2d2d2d;
+                }
+            }
+        }
+    }
+}
+.requird-color {
+    .ivu-form-item-label:before {
+        color: #1cc0f3;
+    }
+}
+.hiteach-collapse {
+    //     background: transparent;
+    //     color: white;
+    //     border-top: none;
+    //     .ivu-collapse-item{
+    //         .ivu-collapse-header{
+    //             height: 200px;
+    //             line-height: 200px;
+    //             display: flex;
+    //             align-items: center;
+    //             padding-left: 15px;
+    .ivu-tag-border {
+        background: transparent !important;
+        margin-right: 10px;
+        border-radius: 5px;
+        letter-spacing: 1px;
+    }
+    //             .ivu-icon-ios-arrow-forward{
+    //                 position: absolute;
+    //                 right: 2px;
+    //                 font-size: 30px;
+    //                 color: white;
+    //             }
+    //         }
+    //         .ivu-collapse-content{
+    //             background: transparent;
+    //         }
+    //     }
+}
+</style>

+ 1 - 1
TEAMModelOS/ClientApp/src/view/student-account/ImportStudent.vue

@@ -12,7 +12,7 @@
             </Upload>
             <p class="import-tips" style="margin-top:40px;">{{$t('stuAccount.importTips1')}}</p>
             <p class="import-tips">{{$t('stuAccount.importTips2') + $t('stuAccount.importTips3')}}</p>
-            <a style="margin-top:10px;color:turquoise;display:inline-block;" href="https://teammodelstorage.blob.core.chinacloudapi.cn/teammodelcontest/20191107/%E5%AD%A6%E7%94%9F%E8%B4%A6%E5%8F%B7%E5%90%8D%E5%8D%95%20%E2%80%94%E6%AD%A3%E7%A1%AE%E6%95%B0%E6%8D%AE.xlsx">(下载名单模板)</a>
+            <a style="margin-top:10px;color:turquoise;display:inline-block;" href="https://teammodelstorage.blob.core.chinacloudapi.cn/download/%E5%AD%A6%E7%94%9F%E5%90%8D%E5%8D%95%E6%A8%A1%E6%9D%BF.xlsx">(下载名单模板)</a>
         </div>
         <div class="form-body" style="background:none;" v-else>
             <div class="ivu-upload-list-file">

+ 26 - 0
TEAMModelOS/ClientApp/src/view/student-account/Index.less

@@ -116,4 +116,30 @@
     line-height: 33px;
     font-size: 18px;
     font-weight: 600;
+}
+.stu-mgt-header{
+    height: 50px;
+    border-bottom: 1px solid #353535;
+    padding: 0 20px;
+    .tab-box {
+        display: inline-block;
+        width: 30%;
+        min-width: 303px;
+        .pane{
+            font-weight: bold;
+            margin-right: 50px;
+            color: #777777;
+            line-height: 50px;
+            padding: 5px 0;
+            cursor: pointer;
+            vertical-align: middle;
+            &.active{
+                color: #e2e2e2;
+                border-bottom: 1px #777777 solid;
+            }
+        }
+    }
+}
+.class-mgt-wrap{
+    height: ~"calc(100% - 50px)";
 }

+ 246 - 177
TEAMModelOS/ClientApp/src/view/student-account/Index.vue

@@ -1,105 +1,118 @@
 <style lang="less" scoped>
-@import './Index.less';
+@import "./Index.less";
 </style>
 <style lang="less">
-@import './IndexIview.less';
+@import "./IndexIview.less";
 </style>
 
 <template>
     <div class="sc-container">
         <Loading v-if="isloading == true"></Loading>
-        <!--菜单栏-->
-        <div class="sc-menu">
-            <div class="sc-menu-left dark-iview-select">
-                <!-- 學制Select -->
-                <Select v-model="searchPeriod" style="width: 120px" :placeholder="$t('stuAccount.periodHolder')" @on-change="filterData">
-                    <Option v-for="(item, index) in periods" :value="item.id" :key="index">{{ item.name }}</Option>
-                </Select>
-                <!-- 學級Select -->
-                <Select v-model="searchGrade" style="width: 120px; margin-left: 5px" :placeholder="$t('stuAccount.gradeHolder')" :not-found-text="$t('stuAccount.sltPdFirst')" clearable @on-change="filterData">
-                    <Option v-for="(item, index) in filterGrades" :value="item.id" :key="index">{{ item.name }}</Option>
-                </Select>
-                <!-- 教室Select -->
-                <Select v-model="searchClassroom" ref="classroom" style="width: 150px; margin-left: 5px" :placeholder="$t('stuAccount.classroomHolder')" clearable @on-change="filterData" :not-found-text="searchGrade ? $t('stuAccount.noClass') : $t('stuAccount.sltGdFirst')">
-                    <Option v-for="(item, index) in filterClasses" :value="item.id" :key="index">{{ item.name }}</Option>
-                    <Option value="noclass">{{$t('stuAccount.noRelClass')}}</Option>
-                </Select>
-                <!-- 字串模糊搜尋 -->
-                <Input v-model="searchText" clearable :placeholder="$t('stuAccount.searchHolder')" style="width: 220px; margin-left: 20px" search @on-search="filterData" @on-clear="filterData" />
-            </div>
-            <div class="sc-menu-right sc-text-no-select" v-if="authorizationStatus == false">
-                <ul v-if="$access.can('admin.*|student-upd')">
-                    <!--授權管理開關-->
-                    <li @click="showAuthorization()">
-                        <Icon custom="iconfont icon-auth-key" color="white" size="18" />
-                        <span>{{ $t('stuAccount.menuAuth') }}</span>
-                    </li>
-                    <!--授權管理開關-->
-                    <li @click="importStudent()">
-                        <Icon type="md-arrow-round-up" color="white" size="18" />
-                        <span>{{ $t('stuAccount.importStu') }}</span>
-                    </li>
-                    <li @click="addStudent()">
-                        <Icon type="md-add" color="white" size="18" />
-                        <span>{{ $t('stuAccount.addStu') }}</span>
-                    </li>
-                    <li @click="delStudent(-1)" :class="selections.length > 0 ? '' : 'sc-disable-cursor'">
-                        <Icon type="md-trash" :color="selections.length > 0 ? 'white' : '#606060'" size="18" />
-                        <span>{{ $t('stuAccount.delStu') }}</span>
-                    </li>
-                    <li @click="editStudent()" :class="selections.length > 0 ? '' : 'sc-disable-cursor'">
-                        <Icon type="md-create" :color="selections.length > 0 ? 'white' : '#606060'" size="18" />
-                        <span>{{ $t('stuAccount.editInfo') }}</span>
-                    </li>
-                    <li @click="resetPW(-1)" :class="selections.length > 0 ? '' : 'sc-disable-cursor'">
-                        <Icon custom="iconfont icon-reset" :color="selections.length > 0 ? 'white' : '#606060'" size="18" />
-                        <span>{{$t('stuAccount.resetPw')}}</span>
-                    </li>
-                </ul>
+        <!-- tab切换 -->
+        <div class="stu-mgt-header">
+            <div class="tab-box">
+                <span class="pane" @click="tab = 'list'" :class="{ active: tab === 'list' }">
+                    学生管理
+                </span>
+                <span class="pane" @click="tab = 'class'" :class="{ active: tab === 'class' }">
+                    班级管理
+                </span>
             </div>
         </div>
-        <!--学生账号table-->
-        <div class="sc-content dark-iview-table"
-             style="position: relative; padding-left: 20px"
-             :style="{width: authorizationStatus == true ? '70%' : '100%',transition: 'all 0.7s'}">
-            <Scroll :on-reach-bottom="scrollLoad" height="750" :distance-to-edge="[15, 15]">
-                <Table ref="selection" :columns="tableColumns" :data="tableShowData" :loading="tableLoading" @on-selection-change="getSelectInfo">
-                    <template slot-scope="{ row }" slot="status">
-                        <Icon custom="iconfont icon-auth-key"
-                              size="25"
-                              :style="{
+        <!-- 账号管理 -->
+        <div v-show="tab == 'list'">
+            <!--菜单栏-->
+            <div class="sc-menu">
+                <div class="sc-menu-left dark-iview-select">
+                    <!-- 學制Select -->
+                    <Select v-model="searchPeriod" style="width: 120px" :placeholder="$t('stuAccount.periodHolder')" @on-change="filterData">
+                        <Option v-for="(item, index) in periods" :value="item.id" :key="index">{{ item.name }}</Option>
+                    </Select>
+                    <!-- 學級Select -->
+                    <Select v-model="searchGrade" style="width: 150px; margin-left: 5px" :placeholder="$t('stuAccount.gradeHolder')" :not-found-text="$t('stuAccount.sltPdFirst')" clearable @on-change="filterData">
+                        <Option v-for="(item, index) in years" :value="item.value" :key="index">{{ item.label }}</Option>
+                    </Select>
+                    <!-- 教室Select -->
+                    <Select v-model="searchClassroom" ref="classroom" style="width: 150px; margin-left: 5px" :placeholder="$t('stuAccount.classroomHolder')" clearable @on-change="filterData" :not-found-text="searchGrade ? $t('stuAccount.noClass') : $t('stuAccount.sltGdFirst')">
+                        <Option v-for="(item, index) in filterClasses" :value="item.id" :key="index">{{ item.name }}</Option>
+                        <Option value="noclass">{{$t('stuAccount.noRelClass')}}</Option>
+                    </Select>
+                    <!-- 字串模糊搜尋 -->
+                    <Input v-model="searchText" clearable :placeholder="$t('stuAccount.searchHolder')" style="width: 220px; margin-left: 20px" search @on-search="filterData" @on-clear="filterData" />
+                </div>
+                <div class="sc-menu-right sc-text-no-select" v-if="authorizationStatus == false">
+                    <ul v-if="$access.can('admin.*|student-upd')">
+                        <!--授權管理開關-->
+                        <li @click="showAuthorization()">
+                            <Icon custom="iconfont icon-auth-key" color="white" size="18" />
+                            <span>{{ $t('stuAccount.menuAuth') }}</span>
+                        </li>
+                        <!--授權管理開關-->
+                        <li @click="importStudent()">
+                            <Icon type="md-arrow-round-up" color="white" size="18" />
+                            <span>{{ $t('stuAccount.importStu') }}</span>
+                        </li>
+                        <li @click="addStudent()">
+                            <Icon type="md-add" color="white" size="18" />
+                            <span>{{ $t('stuAccount.addStu') }}</span>
+                        </li>
+                        <li @click="delStudent(-1)" :class="selections.length > 0 ? '' : 'sc-disable-cursor'">
+                            <Icon type="md-trash" :color="selections.length > 0 ? 'white' : '#606060'" size="18" />
+                            <span>{{ $t('stuAccount.delStu') }}</span>
+                        </li>
+                        <li @click="editStudent()" :class="selections.length > 0 ? '' : 'sc-disable-cursor'">
+                            <Icon type="md-create" :color="selections.length > 0 ? 'white' : '#606060'" size="18" />
+                            <span>{{ $t('stuAccount.editInfo') }}</span>
+                        </li>
+                        <li @click="resetPW(-1)" :class="selections.length > 0 ? '' : 'sc-disable-cursor'">
+                            <Icon custom="iconfont icon-reset" :color="selections.length > 0 ? 'white' : '#606060'" size="18" />
+                            <span>{{$t('stuAccount.resetPw')}}</span>
+                        </li>
+                    </ul>
+                </div>
+            </div>
+            <!--学生账号table-->
+            <div class="sc-content dark-iview-table" style="position: relative; padding-left: 20px" :style="{width: authorizationStatus == true ? '70%' : '100%',transition: 'all 0.7s'}">
+                <Scroll :on-reach-bottom="scrollLoad" height="750" :distance-to-edge="[15, 15]">
+                    <Table ref="selection" :columns="tableColumns" :data="tableShowData" :loading="tableLoading" @on-selection-change="getSelectInfo">
+                        <template slot-scope="{ row }" slot="status">
+                            <Icon custom="iconfont icon-auth-key" size="25" :style="{
                 color: aclassOneInfoNum != undefined && (aclassOneInfoNum.staIds.includes(row.id) == true || aclassOneInfoNum.dyncIds.includes(row.id)) == true ? '#00f492' : '#565656'
               }" />
-                    </template>
-                    <template slot-scope="{ row, index }" slot="header">
-                        <!--<span class="name-header" :style="{background:bgColor[index % 12]}">{{getFirstChart(row.name)}}</span>-->
-                        <PersonalPhoto :name="row.name" :picture="row.picture" :color="bgColor[index % 12]" />
-                    </template>
-                    <template slot-scope="{ row }" slot="gradeId" v-if="authorizationStatus == false">
-                        <span>{{ getGradeName(row.gradeId) }}</span>
-                    </template>
-                    <template slot-scope="{ row }" slot="classId">
-                        <span>{{ row.className }}</span>
-                    </template>
-                    <template slot-scope="{ row }" slot="no">
-                        <span>{{ row.no }}</span>
-                    </template>
-                    <template slot-scope="{ row }" slot="gradeName">
-                        <span>{{ row.gradeName }}</span>
-                    </template>
-                    <template slot-scope="{ row }" slot="action" v-if="authorizationStatus == false">
-                        <div class="item-tools" v-if="$access.can('admin.*|student-upd')">
-                            <Icon type="md-create" size="18" color="white" @click="editStudent(row)" title="修改" />
-                            <Icon custom="iconfont icon-reset" size="18" color="white" @click="resetPW(row)" :title=" $t('stuAccount.resetPw')" />
-                            <Icon type="md-trash" size="18" color="white" @click="delStudent(row)" :title="$t('stuAccount.delStu')" />
-                        </div>
-                    </template>
-                </Table>
-            </Scroll>
+                        </template>
+                        <template slot-scope="{ row, index }" slot="header">
+                            <!--<span class="name-header" :style="{background:bgColor[index % 12]}">{{getFirstChart(row.name)}}</span>-->
+                            <PersonalPhoto :name="row.name" :picture="row.picture" :color="bgColor[index % 12]" />
+                        </template>
+                        <template slot-scope="{ row }" slot="gradeId" v-if="authorizationStatus == false">
+                            <span>{{ getGradeName(row.gradeId) }}</span>
+                        </template>
+                        <template slot-scope="{ row }" slot="classId">
+                            <span>{{ row.className }}</span>
+                        </template>
+                        <template slot-scope="{ row }" slot="no">
+                            <span>{{ row.no }}</span>
+                        </template>
+                        <template slot-scope="{ row }" slot="gradeName">
+                            <span>{{ row.gradeName }}</span>
+                        </template>
+                        <template slot-scope="{ row }" slot="action" v-if="authorizationStatus == false">
+                            <div class="item-tools" v-if="$access.can('admin.*|student-upd')">
+                                <Icon type="md-create" size="18" color="white" @click="editStudent(row)" title="修改" />
+                                <Icon custom="iconfont icon-reset" size="18" color="white" @click="resetPW(row)" :title=" $t('stuAccount.resetPw')" />
+                                <Icon type="md-trash" size="18" color="white" @click="delStudent(row)" :title="$t('stuAccount.delStu')" />
+                            </div>
+                        </template>
+                    </Table>
+                </Scroll>
 
-            <AclassOneAuth :students="students" :selected="selections" @closeAuth="closeAuth" :closefromBtn="closefromBtn" />
+                <AclassOneAuth :students="students" :selected="selections" @closeAuth="closeAuth" :closefromBtn="closefromBtn" />
+            </div>
+        </div>
+        <!-- 班级管理 -->
+        <div v-show="tab == 'class'" class="class-mgt-wrap" id="class-mgt-list">
+            <ClassMgt></ClassMgt>
         </div>
-
         <Modal v-model="addStudentStatus" width="520" class-name="add-student dark-iview-modal" :mask-closable="false">
             <add-student v-if="addStudentStatus" :schoolCode="$store.state.user.schoolCode" :isShow="addStudentStatus" :editStudentInfo="editStudentInfo" @saveStudentInfo="closeAddStudent" :bizType="bizType"></add-student>
             <div slot="footer"></div>
@@ -127,11 +140,11 @@
 <script>
 import PersonalPhoto from '@/components/public/personalPhoto/Index.vue'
 import AddStudent from './AddStudent'
+import ClassMgt from './ClassMgt'
 import ImportStudent from './ImportStudent'
 import Authorization from './Authorization'
 import AclassOneAuth from './AclassOneAuth'
 import { mapGetters, mapMutations } from 'vuex'
-import Loading from '@/common/Loading.vue'
 export default {
     components: {
         AddStudent,
@@ -139,10 +152,11 @@ export default {
         Authorization,
         PersonalPhoto,
         AclassOneAuth,
-        Loading
+        ClassMgt
     },
     data() {
         return {
+            tab: 'list',
             totalNum: 0,
             bgColor: ['#4ECDC4', '#F99406', '#075CD0', '#F7CA17', '#F2774B', '#67809F', '#BF55ED', '#00B169', '#F72459', '#F15A22', '#03C9A8', '#9A1294'],
             classroomList: [],
@@ -151,7 +165,9 @@ export default {
             searchPeriod: '',
             searchGrade: '',
             searchClassroom: '',
-            schoolData: {},
+            schoolBase: {
+                period: []
+            },
             tableLoading: true,
             searchText: '',
             currentPage: 1,
@@ -184,11 +200,11 @@ export default {
             if (row != -1) {
                 this.$Modal.confirm({
                     title: this.$t('cusMgt.resetPw'),
-                    content: '<p>' + this.$t('cusMgt.resetPwContent1') + " <strong style='color:red;'>" + row.name + '</strong>'+ this.$t('cusMgt.resetPwContent1') +'?</p>',
+                    content: '<p>' + this.$t('cusMgt.resetPwContent1') + " <strong style='color:red;'>" + row.name + '</strong>' + this.$t('cusMgt.resetPwContent1') + '?</p>',
                     onOk: () => {
                         let ids = []
                         row.pw = row.id
-                        row.year = row.year ? row.year.toString() :''
+                        row.year = row.year ? row.year.toString() : ''
                         delete row.no
                         ids.push(row)
                         this.tableLoading = true
@@ -209,10 +225,10 @@ export default {
                 if (this.selections.length > 0) {
                     this.$Modal.confirm({
                         title: this.$t('cusMgt.resetPw'),
-                        content: '<p>' + this.$t('cusMgt.resetPwContent3') + " <strong style='color:red;'>" + this.selections.length + '</strong>'+ this.$t('cusMgt.resetPwContent4') +'</p>',
+                        content: '<p>' + this.$t('cusMgt.resetPwContent3') + " <strong style='color:red;'>" + this.selections.length + '</strong>' + this.$t('cusMgt.resetPwContent4') + '</p>',
                         onOk: () => {
                             this.tableLoading = true
-                            let apiData = this.selections.map( (item) =>{
+                            let apiData = this.selections.map((item) => {
                                 let d = item
                                 d.pw = d.id
                                 delete d.no
@@ -290,7 +306,7 @@ export default {
                 data.studentInfos.year = parseInt(data.studentInfos.year)
                 newStudents.push(data.studentInfos)
             } else if (data.action == 2) {  // 修改
-                newStudents = data.studentInfos.map(function(item) {
+                newStudents = data.studentInfos.map(function (item) {
                     let temp = item
                     temp.pw = '******'
                     temp.year = parseInt(temp.year)
@@ -304,7 +320,7 @@ export default {
         },
         closeImportStudent(data) {
             // 給一個 PW 讓AddStudent.vue 的Watch 可以動作
-            let newStudents = data.map(function(item) {
+            let newStudents = data.map(function (item) {
                 let temp = item
                 temp.pw = '******'
                 temp.year = parseInt(temp.year)
@@ -324,7 +340,7 @@ export default {
                 this.isloading = false
             }, 1000)
         },
-   
+
         addStudent() {
             this.bizType = 1
             this.$refs.selection.clearCurrentRow()
@@ -340,63 +356,63 @@ export default {
             this.isloading = true
             setTimeout(() => {
                 this.tableColumns = [
-                {
-                    type: 'selection',
-                    width: 80,
-                    align: 'center'
-                },
-                {
-                    slot: 'header',
-                    title: ' ',
-                    align: 'center',
-                    width: 120
-                },
-                {
-                    key: 'id',
-                    title: this.$t('stuAccount.account'),
-                    align: 'center',
-                    sortable: true,
-                    sortMethod: (a, b, type) => {
-                        if (type == 'asc') {
-                            return a.localeCompare(b)
-                        } else {
-                            return b.localeCompare(a)
+                    {
+                        type: 'selection',
+                        width: 80,
+                        align: 'center'
+                    },
+                    {
+                        slot: 'header',
+                        title: ' ',
+                        align: 'center',
+                        width: 120
+                    },
+                    {
+                        key: 'id',
+                        title: this.$t('stuAccount.account'),
+                        align: 'center',
+                        sortable: true,
+                        sortMethod: (a, b, type) => {
+                            if (type == 'asc') {
+                                return a.localeCompare(b)
+                            } else {
+                                return b.localeCompare(a)
+                            }
                         }
-                    }
-                },
-                {
-                    key: 'name',
-                    title: this.$t('stuAccount.stuName'),
-                    align: 'center',
-                    sortable: true
-                },
-                {
-                    slot: 'classId',
-                    title: this.$t('stuAccount.classroomName'),
-                    align: 'center',
-                    sortable: true
-                },
-                {
-                    key: 'no',
-                    title: this.$t('stuAccount.seatNo'),
-                    align: 'center',
-                    width: 120,
-                    sortable: true,
-                    sortMethod: (a, b, type) => {
-                        if (type == 'desc') {
-                            return parseInt(a) > parseInt(b) ? -1 : 1
-                        } else {
-                            return parseInt(a) < parseInt(b) ? -1 : 1
+                    },
+                    {
+                        key: 'name',
+                        title: this.$t('stuAccount.stuName'),
+                        align: 'center',
+                        sortable: true
+                    },
+                    {
+                        slot: 'classId',
+                        title: this.$t('stuAccount.classroomName'),
+                        align: 'center',
+                        sortable: true
+                    },
+                    {
+                        key: 'no',
+                        title: this.$t('stuAccount.seatNo'),
+                        align: 'center',
+                        width: 120,
+                        sortable: true,
+                        sortMethod: (a, b, type) => {
+                            if (type == 'desc') {
+                                return parseInt(a) > parseInt(b) ? -1 : 1
+                            } else {
+                                return parseInt(a) < parseInt(b) ? -1 : 1
+                            }
                         }
+                    },
+                    {
+                        slot: 'status',
+                        title: this.$t('stuAccount.authStatus'),
+                        align: 'center',
+                        width: 150,
+                        sortable: true
                     }
-                },
-                {
-                    slot: 'status',
-                    title: this.$t('stuAccount.authStatus'),
-                    align: 'center',
-                    width: 150,
-                    sortable: true
-                }
                 ]
                 this.isloading = false
             }, 1000)
@@ -459,7 +475,7 @@ export default {
                 if (this.selections.length > 0) {
                     this.$Modal.confirm({
                         title: this.$t('stuAccount.tips2Title'),
-                        content: '<p>' + this.$t('stuAccount.tips2Content3') + " <strong style='color:red;'>" + this.selections.length + '</strong>'+ this.$t('stuAccount.tips2Content4') +'</p>',
+                        content: '<p>' + this.$t('stuAccount.tips2Content3') + " <strong style='color:red;'>" + this.selections.length + '</strong>' + this.$t('stuAccount.tips2Content4') + '</p>',
                         onOk: () => {
                             this.tableLoading = true
                             let delIds = this.selections.map(item => {
@@ -517,15 +533,34 @@ export default {
                     sortable: true
                 },
                 {
-                    slot: 'gradeId',
-                    title: this.$t('stuAccount.grade'),
+                    key: 'stuId',
+                    title: '学号',
+                    align: 'center',
+                    sortable: true
+                },
+                // {
+                //     slot: 'gradeId',
+                //     title: this.$t('stuAccount.grade'),
+                //     align: 'center',
+                //     width: 140,
+                //     sortable: true
+                // },
+                {
+                    key: 'year',
+                    title: '学级',
                     align: 'center',
                     width: 140,
                     sortable: true
                 },
+                // {
+                //     slot: 'classId',
+                //     title: this.$t('stuAccount.classroomName'),
+                //     align: 'center',
+                //     sortable: true
+                // },
                 {
                     slot: 'classId',
-                    title: this.$t('stuAccount.classroomName'),
+                    title: '班级',
                     align: 'center',
                     sortable: true
                 },
@@ -547,7 +582,7 @@ export default {
                     slot: 'status',
                     title: this.$t('stuAccount.authStatus'),
                     align: 'center',
-                    width: 100,
+                    width: 120,
                     sortable: true
                 },
                 {
@@ -564,7 +599,7 @@ export default {
                 res => {
                     this.tableLoading = false
                     // 給一個 PW 讓AddStudent.vue 的Watch 可以動作
-                    let newStudents = res.students.map(function(item) {
+                    let newStudents = res.students.map(function (item) {
                         let temp = item
                         temp.pw = '******'
                         return temp
@@ -587,9 +622,9 @@ export default {
             )
         },
         /** 取得年級Name */
-        getGradeName: function(gradeId) {
+        getGradeName: function (gradeId) {
             if (gradeId != null) {
-                let gradeData = this.grades.filter(function(item) {
+                let gradeData = this.grades.filter(function (item) {
                     return item.id == gradeId
                 })
                 return gradeData[0].name
@@ -610,7 +645,7 @@ export default {
             )
         },
 
-        scrollLoad: function() {
+        scrollLoad: function () {
             setTimeout(() => {
                 let maxLength = this.tableShowData.length
                 let temp = this.tableFilterData.slice(this.pointNum + 1, this.pointNum + this.basicCount)
@@ -625,14 +660,14 @@ export default {
             }, 1500)
         },
         /**根据学段、年级、班级搜索 */
-        filterData: function() {
+        filterData: function () {
             let data = this.students
 
             // 筛选没有关联班级的学生
             if (this.searchClassroom == 'noclass') {
                 if (this.searchClassroom) {
                     let id = this.searchClassroom
-                    data = data.filter(function(item) {
+                    data = data.filter(function (item) {
                         return item.classId == null
                     })
                 }
@@ -646,7 +681,7 @@ export default {
             // 帳號資訊搜尋
             if (this.searchText) {
                 let text = this.searchText
-                data = data.filter(function(item) {
+                data = data.filter(function (item) {
                     return item.name.indexOf(text) >= 0 || item.id.indexOf(text) >= 0
                 })
             }
@@ -654,23 +689,23 @@ export default {
             // 學制篩選
             if (this.searchPeriod) {
                 let id = this.searchPeriod
-                data = data.filter(function(item) {
-                return item.periodId == id
+                data = data.filter(function (item) {
+                    return item.periodId == id
                 })
             }
 
             // 年級篩選
             if (this.searchGrade) {
                 let id = this.searchGrade
-                data = data.filter(function(item) {
-                    return item.gradeId == id
+                data = data.filter(function (item) {
+                    return item.year == id
                 })
             }
 
             // 教室篩選
             if (this.searchClassroom) {
                 let id = this.searchClassroom
-                data = data.filter(function(item) {
+                data = data.filter(function (item) {
                     return item.classId == id
                 })
             }
@@ -684,6 +719,11 @@ export default {
         })
     },
     created() {
+        this.$store.dispatch('user/getSchoolProfile').then(
+            res => {
+                this.schoolBase = res.school_base
+            }
+        )
         this.initData()
         this.baseFindStudent()
     },
@@ -695,11 +735,11 @@ export default {
             students: 'schoolBaseInfo/getStudent', // 學生List
             aclassOneInfoNum: 'studentAclassOneAuth/getSchoolAclassOneInfoNum'
         }),
-        filterGrades: function() {
+        filterGrades: function () {
             var data = this.grades
             if (this.searchPeriod) {
                 let periodId = this.searchPeriod
-                data = data.filter(function(item) {
+                data = data.filter(function (item) {
                     return item.periodId == periodId
                 })
                 return data
@@ -707,11 +747,11 @@ export default {
                 return []
             }
         },
-        filterClasses: function() {
+        filterClasses: function () {
             var data = this.classes
             if (this.searchGrade) {
                 let gradeId = this.searchGrade
-                data = data.filter(function(item) {
+                data = data.filter(function (item) {
                     return item.gradeId == gradeId
                 })
                 return data
@@ -719,20 +759,49 @@ export default {
                 return []
             }
         },
-        getPeriodName: function() {
+        getPeriodName: function () {
             let str = ''
-            if(this.periods){
+            if (this.periods) {
                 let id = this.searchPeriod
                 let period = this.periods.filter((item) => {
                     return item.id == id
                 })
-                if(period[0]) str = period[0].name
+                if (period[0]) str = period[0].name
             }
             return str
+        },
+        years() {
+            if (this.schoolBase && this.schoolBase.period.length && this.searchPeriod) {
+                let pData = this.schoolBase.period.find(item => {
+                    return item.id == this.searchPeriod
+                })
+                if (pData) {
+                    let date = new Date()
+                    let year = date.getFullYear()
+                    let month = date.getMonth() + 1
+                    let start = pData.semesters.find(item => {
+                        return item.start == 1
+                    })
+                    // 根据入学月份确定当前年级和学级的关系
+                    if (start && month < start.month) {
+                        year--
+                    }
+                    let res = pData.grades.map(item => {
+                        return {
+                            label: `${item.name}(${year}级)`,
+                            value: year--
+                        }
+                    })
+                    return res
+                } else {
+                    return []
+                }
+            }
+            return []
         }
     },
     watch: {
-        selections: function(value) {
+        selections: function (value) {
             console.log(value)
         }
     },

+ 120 - 0
TEAMModelOS/ClientApp/src/view/task/index.less

@@ -0,0 +1,120 @@
+
+@main-bgColor: rgb(40,40,40); //主背景颜色
+@borderColor: #424242;
+@primary-textColor: #fff; //文本主颜色
+@second-textColor: #a5a5a5; //文本副级颜色
+@primary-fontSize: 14px;
+@second-fontSize: 16px;
+
+.task-container{
+    width: 100%;
+    height: 100%;
+    padding-left: 10px;
+    color: #a5a5a5;
+}
+.task-header{
+    width: 100%;
+    height: 45px;
+    line-height: 45px;
+    border-bottom: 1px solid @borderColor;
+    color: @second-textColor;
+}
+.task-content{
+    width: 100%;
+    height: ~"calc(100% - 45px)";
+}
+.ev-mark-info{
+    padding-left: 10px !important;
+}
+.task-bar-item {
+    margin-right: 10px;
+    display: inline-block;
+    cursor: pointer;
+    line-height: 38px;
+}
+.ev-item{
+    border-bottom: 1px solid @borderColor;
+    padding: 15px 10px 15px 0px;
+    cursor: pointer;
+    user-select: none;
+    .ev-name{
+        font-size: 16px;
+        color: white;
+    }
+}
+.mark-status-tag {
+    padding: 1px 2px;
+    border: 1px solid #1CC0F3;
+    margin-left: 2px;
+    border-radius: 2px;
+    font-size:12px;
+    color: #1cc0f3;
+    transform: scale(0.8);
+    display: inline-block;
+}
+.ev-info{
+    color: #a5a5a5;
+    margin-top: 5px;
+}
+.setting-block {
+    margin-top: 30px;
+}
+.setting-block:first-child {
+    margin-top: 20px;
+}
+.setting-block:first-child .setting-content {
+    // background: none;
+    padding: 25px 10px 25px 25px;
+}
+
+.setting-content {
+    background: #2b2a2f;
+    box-shadow: 1px 1px 13px #141414;
+    border: 1px solid rgba(98, 97, 101, 0.4);
+    padding: 15px 10px;
+    border-radius: 5px;
+    margin-right: 12px;
+    margin-top: 8px;
+    box-shadow: 0 26px 40px -24px rgb(30, 31, 33);
+}
+.count-content {
+    display: flex;
+}
+.count-wrap {
+    flex: 1;
+    text-align: center;
+    color: white;
+    width: 200px;
+    position: relative;
+    .count-icon {
+        color: #a5a5a5;
+    }
+    .count-num {
+        font-size: 40px;
+    }
+    .count-label {
+        color: #a5a5a5;
+    }
+}
+.count-wrap::after {
+    content: "";
+    width: 2px;
+    height: 30px;
+    background: #a5a5a5;
+    position: absolute;
+    right: 0px;
+    top: 50%;
+    margin-top: -15px;
+}
+.count-wrap:last-child::after {
+    display: none;
+}
+.to-mark-view{
+    cursor: pointer;
+    &:hover{
+        color: #2d8cf0;
+        .to-mark-view-text{
+            color: #2d8cf0;
+        }
+    }
+}

+ 153 - 0
TEAMModelOS/ClientApp/src/view/task/index.vue

@@ -0,0 +1,153 @@
+<template>
+    <!-- 未做多语言 -->
+    <div class="task-container">
+        <div class="task-header">
+            <span :class="curBarIndex == 0 ? 'task-bar-item line-bottom-active line-bottom':'task-bar-item line-bottom'" @click="selectBar(0)">
+                阅卷任务
+            </span>
+        </div>
+        <div class="task-content dark-iview-split">
+            <Split v-model="split1">
+                <vuescroll slot="left" class="ev-list">
+                    <div :class="['ev-item','block-bg',index == curEvIndex ? 'block-bg-active':'']" v-for="(item,index) in evList" :key="index" @click="selectEvaluation(index)">
+                        <p class="ev-name">
+                            <span>{{item.name}}</span>
+                            <span class="mark-status-tag">进行中</span>
+                        </p>
+                        <p class="ev-info">
+                            <Icon type="md-time" style="margin-right:5px;" size="16" />
+                            <span>{{$t('learnActivity.mgtScEv.endTime')}}{{dateFormat(item.endTime)}}</span>
+                        </p>
+                        <p class="ev-info">
+                            <Icon type="ios-cube" style="margin-right:5px;" size="14" />
+                            <span>{{$t('learnActivity.mgtScEv.evType')}}{{getTypeLabel(item.type)}}</span>
+                        </p>
+                    </div>
+                </vuescroll>
+                <vuescroll slot="right" class="ev-mark-info">
+                    <!-- 数据概览 -->
+                    <div class="setting-block">
+                        <p class="block-title">{{$t('learnActivity.mark.dataView')}}</p>
+                        <div class="setting-content count-content">
+                            <div class="count-wrap">
+                                <p class="count-num">12</p>
+                                <p class="count-label">
+                                    <Icon custom="iconfont icon-scanning" class="count-icon" size="16" />
+                                    总量
+                                </p>
+                            </div>
+                            <div class="count-wrap">
+                                <p class="count-num">1</p>
+                                <p class="count-label">
+                                    <Icon type="ios-star" class="count-icon" size="16" />
+                                    已阅
+                                </p>
+                            </div>
+                            <div class="count-wrap">
+                                <p class="count-num">2</p>
+                                <p class="count-label">
+                                    <Icon type="ios-star-outline" class="count-icon" size="16" />
+                                    未阅
+                                </p>
+                            </div>
+                            <div class="count-wrap to-mark-view" @click="toMarkView">
+                                <p class="count-num">
+                                    <Icon type="ios-arrow-forward" />
+                                    <Icon type="ios-arrow-forward" style="margin-left:-25px" />
+                                </p>
+                                <p class="count-label to-mark-view-text">
+                                    继续阅卷
+                                </p>
+                            </div>
+                        </div>
+                    </div>
+                    <!-- 数据对比 -->
+                    <div class="setting-block">
+                        <p class="block-title">数据对比</p>
+                        <div class="setting-content count-content">
+
+                        </div>
+                    </div>
+                </vuescroll>
+            </Split>
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {
+            split1: 0.2,
+            curBarIndex: 0,
+            evList: [],
+            curEvIndex: 0
+        }
+    },
+    methods: {
+        toMarkView() {
+            this.$router.push({
+                name: 'MarkView',
+                params: {
+                    type: 1,
+                    from: this.$route.name
+                }
+            })
+        },
+        /**获取type对应的label */
+        getTypeLabel(code) {
+            for (let item of this.$GLOBAL.EV_TYPE()) {
+                if (item.value == code) {
+                    return item.label
+                }
+            }
+        },
+        dateFormat(timestamp) {
+            var date = new Date(timestamp)
+            var Y = date.getFullYear() + '-'
+            var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'
+            var D = date.getDate() + ' '
+            return Y + M + D;
+        },
+        selectBar(index) {
+            this.curBarIndex = index
+        },
+        //查询阅卷任务列表 现在暂无相关API,暂时查询所有评测
+        findEvaluation() {
+            let requestData = {
+                code: this.$store.state.userInfo.schoolCode,
+                classIds: undefined
+            }
+            this.$api.learnActivity.FindExamInfo(requestData).then(
+                res => {
+                    if (!res.error) {
+                        res.examInfo = res.examInfo.sort((a, b) => {
+                            return a.createTime - b.createTime > 0 ? -1 : 1
+                        })
+                        this.evList = res.examInfo
+                        this.evList = res.examInfo
+                        this.selectEvaluation(0)
+                    } else {
+                        this.$Message.error('API ERROR!')
+                    }
+                }
+            )
+        },
+        selectEvaluation(index) {
+            this.curEvIndex = index
+            // if (this.evList[this.curEvaIndex] && this.evList[this.curEvaIndex].papers.length == 0) {
+            //     this.findExamPaper()
+            // } else {
+            //     this.examDetaiInfo = this.evaListShow[this.curEvaIndex]
+            // }
+        },
+    },
+    created() {
+        this.findEvaluation()
+    }
+}
+</script>
+<style scoped lang="less">
+@import "./index.less";
+</style>
+<style lang="less">
+</style>

+ 3 - 0
TEAMModelOS/Controllers/Client/HiTeachController.cs

@@ -86,9 +86,12 @@ namespace TEAMModelOS.Controllers.Client
                             if(statusNow == "join") //成為老師的才放入
                             {
                                 dynamic schoolExtobj = new ExpandoObject();
+                                var schoolJson = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync($"{obj.GetProperty("schoolId")}", new PartitionKey("Base"));
+                                var school = await JsonDocument.ParseAsync(schoolJson.ContentStream);
                                 schoolExtobj.schoolId = obj.GetProperty("schoolId");
                                 schoolExtobj.name = obj.GetProperty("name");
                                 schoolExtobj.status = obj.GetProperty("status");
+                                schoolExtobj.picture = school.RootElement.GetProperty("picture");
                                 schools.Add(schoolExtobj);
                             }
                         }

+ 1 - 1
TEAMModelOS/Controllers/Common/CommonController.cs

@@ -65,7 +65,7 @@ namespace TEAMModelOS.Controllers.Common
             }
             catch (Exception ex)
             {
-                await _dingDing.SendBotMsg($"OS,{_option.Location},common/finish\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
+                await _dingDing.SendBotMsg($"OS,{_option.Location},common/finish\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
                 return BadRequest();
             }
         }

+ 2 - 2
TEAMModelOS/Controllers/School/ClassRoomController.cs

@@ -23,12 +23,12 @@ namespace TEAMModelOS.Controllers
     //[Authorize(Roles = "IES5")]
     [Route("school/classroom")]
     [ApiController]
-    public class ClassroomController : ControllerBase
+    public class ClassController : ControllerBase
     {
         public readonly AzureCosmosFactory _azureCosmos;
         private readonly Option _option;
         private readonly DingDing _dingDing;
-        public ClassroomController(AzureCosmosFactory azureCosmos, DingDing dingDing,
+        public ClassController(AzureCosmosFactory azureCosmos, DingDing dingDing,
             IOptionsSnapshot<Option> option)
         {
             _azureCosmos = azureCosmos;

+ 168 - 0
TEAMModelOS/Controllers/School/RoomController.cs

@@ -0,0 +1,168 @@
+using Azure.Cosmos;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Models.Cosmos;
+
+namespace TEAMModelOS.Controllers
+{
+    [Route("school/room")]
+    [ApiController]
+    public class RoomController : ControllerBase
+    {
+        public readonly AzureCosmosFactory _azureCosmos;
+        private readonly Option _option;
+        private readonly DingDing _dingDing;
+        public RoomController(AzureCosmosFactory azureCosmos, DingDing dingDing,
+            IOptionsSnapshot<Option> option)
+        {
+            _azureCosmos = azureCosmos;
+            _dingDing = dingDing;
+            _option = option?.Value;
+        }
+        /// <summary>
+        /// {
+        ///     "id":"教室id,新增时为空","code":"学校编码hbcn","name":"教室名称","no":"编号","x":坐标x,"y":坐标y,
+        ///     "sn":"序列号","openType":"1  教室属性,普通 /专设的教室","style":"TBL IRS 类型区分","area":"教学区,第一教学楼...."
+        /// }
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        //[AuthToken(Roles = "Teacher")]
+        [HttpPost("upsert")]
+        public async ValueTask<IActionResult> Upsert(Room request) {
+
+            try
+            {
+                var client = _azureCosmos.GetCosmosClient();
+                request.pk = "Room";
+                request.code = request.pk + "-" + request.code;
+                request.ttl = -1;
+                if (string.IsNullOrEmpty(request.id))
+                {
+
+                    request.id = Guid.NewGuid().ToString();
+                    request = await client.GetContainer("TEAMModelOS", "School").CreateItemAsync(request, new PartitionKey($"{request.code}"));
+                }
+                else {
+                    var response = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(request.id, new PartitionKey($"{request.code}"));
+                    if (response.Status == 200)
+                    {
+                        using var json = await JsonDocument.ParseAsync(response.ContentStream);
+                        var info = json.ToObject<Room>();
+                        request = await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync(request, info.id, new PartitionKey($"{info.code}"));
+                    }
+                    else
+                    {
+                        request = await client.GetContainer("TEAMModelOS", "School").CreateItemAsync(request, new PartitionKey($"{request.code}"));
+                    }
+                }
+                return Ok(new { romm= request });
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},common/vote/save()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest();
+            }
+        }
+        /// <summary>
+        /// {"code":"hbcn学校编码"} 
+        /// </summary>
+        /// <param name="requert"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        //[AuthToken(Roles = "Teacher")]
+        [HttpPost("find")]
+        public async Task<IActionResult> Find(JsonElement request)
+        {
+            try
+            {
+                if (!request.TryGetProperty("code", out JsonElement code)) { return BadRequest(); }
+                var client = _azureCosmos.GetCosmosClient();
+                var item = client.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<Room>(queryText: $"select value(c) from c ",
+                requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Room-{code}") });
+                return Ok(new { rooms= item });
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},school/room/find()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest();
+            }
+        }
+        /// <summary>
+        /// {"id":"教室id","code":"hbcn学校编码"} 
+        /// </summary>
+        /// <param name="requert"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("find-id")]
+        public async Task<IActionResult> FindById(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();
+                Room room = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<Room>(id.GetString(), new PartitionKey($"Room-{code}"));
+                if (room != null)
+                {
+
+                    return Ok(new { room });
+                }
+                else
+                {
+                    return BadRequest("id,code不存在!");
+                }
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},school/room/find-id()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest();
+            }
+        }
+        /// <summary>
+        /// {"id":"教室id","code":"hbcn学校编码"} 
+        /// </summary>
+        /// <param name="requert"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("delete")]
+        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();
+                Room room = await client.GetContainer("TEAMModelOS", "School").DeleteItemAsync<Room>(id.GetString(), new PartitionKey($"Room-{code}"));
+                if (room != null)
+                {
+
+                    return Ok(new { room });
+                }
+                else
+                {
+                    return BadRequest("id,code不存在!");
+                }
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},school/room/find-id()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest();
+            }
+        }
+    }
+}

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

@@ -56,12 +56,12 @@ namespace TEAMModelOS.Controllers
         [ProducesDefaultResponseType]
         //[AuthToken(Roles = "admin")]
         [HttpPost("upsert")]
-        public async Task<IActionResult> Upsert(School requert)
+        public async Task<IActionResult> Upsert(TEAMModelOS.SDK.Models.School requert)
         {
             var (_, _, _, school) = HttpContext.GetAuthTokenInfo();
             try
             {
-                School schoolInfo = new School();
+                TEAMModelOS.SDK.Models.School schoolInfo = new TEAMModelOS.SDK.Models.School();
                 var client = _azureCosmos.GetCosmosClient();
                 var schoolContainer = client.GetContainer("TEAMModelOS", "School");
                 var response = await schoolContainer.ReadItemStreamAsync(requert.id, new PartitionKey($"Base"));
@@ -124,7 +124,7 @@ namespace TEAMModelOS.Controllers
         {
             if (!requert.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
             var client = _azureCosmos.GetCosmosClient();
-            List<School> schools = new List<School>();
+            List<TEAMModelOS.SDK.Models.School> schools = new List<TEAMModelOS.SDK.Models.School>();
             var query = $"select c.id,c.pk,c.code, c.name,c.region,c.province,c.city,c.timeZone,c.picture,c.size,c.period,c.campuses from c where c.id ='{school_code}'";
             await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
             {
@@ -134,7 +134,7 @@ namespace TEAMModelOS.Controllers
                 {
                     foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
                     {
-                        schools.Add(obj.ToObject<School>());
+                        schools.Add(obj.ToObject<TEAMModelOS.SDK.Models.School>());
                     }
                 }
             }

+ 110 - 1
TEAMModelOS/Controllers/Syllabus/VolumeController.cs

@@ -11,6 +11,8 @@ using System.Text.Json;
 using System.Threading.Tasks;
 using TEAMModelOS.Models;
 using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos.Common;
 
 namespace TEAMModelOS.Controllers
@@ -35,6 +37,114 @@ namespace TEAMModelOS.Controllers
             _option = option?.Value; ;
         }
 
+        /// <summary>
+        /// 删除册别
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        //[AuthToken(Roles = "Teacher")]
+        [HttpPost("delete")]
+        public async Task<IActionResult> Delete(JsonElement request)
+        {
+            try
+            {
+                if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
+                if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
+                if (!request.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
+                var client = _azureCosmos.GetCosmosClient();
+                if (scope.ToString().Equals("school"))
+                {
+                    var response = await client.GetContainer("TEAMModelOS", "School").DeleteItemStreamAsync(id.ToString(), new PartitionKey($"Volume-{code}"));
+                    return Ok(new { code = response.Status });
+                }
+                else
+                {
+                    var response = await client.GetContainer("TEAMModelOS", "Teacher").DeleteItemStreamAsync(id.ToString(), new PartitionKey($"Volume-{code}"));
+                    return Ok(new { code = response.Status });
+                }
+            }
+            catch (Exception e)
+            {
+                return BadRequest();
+            }
+        }
+
+        /// <summary>
+        /// 查找册别
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        //[AuthToken(Roles = "Teacher")]
+        [HttpPost("find")]
+
+        public async Task<IActionResult> Find(JsonElement request) {
+            List<Syllabus> syllabuses = new List<Syllabus>();
+            List<Volume> volumes = new List<Volume>();
+            request.TryGetProperty("periodId", out JsonElement periodCode);
+            request.TryGetProperty("subjectId", out JsonElement subjectCode);
+            request.TryGetProperty("status", out JsonElement status);
+            if (request.TryGetProperty("code", out JsonElement code))
+            {
+                request.TryGetProperty("type", out JsonElement type);
+                //私有课纲
+                if (type.GetInt32() == 1)
+                {
+                    await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Teacher").GetItemQueryStreamIterator(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Syllabus-{code}") }))
+                    {
+                        using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                        if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                        {
+                            foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                            {
+                                syllabuses.Add(obj.ToObject<Syllabus>());
+                            }
+                        }
+                    }
+                    await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Teacher").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.status = {status}", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Volume-{code}") }))
+                    {
+                        using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                        if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                        {
+                            foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                            {
+                                volumes.Add(obj.ToObject<Volume>());
+                            }
+                        }
+                    }
+                }
+                else {
+                    await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Syllabus-{code}") }))
+                    {
+                        using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                        if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                        {
+                            foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                            {
+                                syllabuses.Add(obj.ToObject<Syllabus>());
+                            }
+                        }
+                    }
+                    await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.status = {status} and c.periodId = '{periodCode}' and c.subjectId = '{subjectCode}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Volume-{code}") }))
+                    {
+                        using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                        if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                        {
+                            foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                            {
+                                volumes.Add(obj.ToObject<Volume>());
+                            }
+                        }
+                    }
+                }
+             }
+            else { return BadRequest(); };
+            return Ok(new { volumes });
+        }
+
+
+
         /// <summary>
         /// 新增册别
         /// </summary>
@@ -76,7 +186,6 @@ namespace TEAMModelOS.Controllers
                 catch (Exception  ex) {
                     return BadRequest(new { error = ResponseCode.FAILED });
                 }
-
             }
             //表示新增,则需要检查是否重复
             else {

+ 20 - 4
TEAMModelOS/Controllers/Teacher/InitController.cs

@@ -57,8 +57,8 @@ namespace TEAMModelOS.Controllers
                 var id = jwt.Payload.Sub;
                 jwt.Payload.TryGetValue("name", out object name);
                 jwt.Payload.TryGetValue("picture", out object picture);
-
-                object schools = null;
+               List<object> schools = new List<object>();
+               // object schools = null;
                 string defaultschool = null;
                 //TODO 取得Teacher 個人相關數據(課程清單、虛擬教室清單、歷史紀錄清單等),學校數據另外API處理,多校切換時不同
                 var client = _azureCosmos.GetCosmosClient();
@@ -67,10 +67,26 @@ namespace TEAMModelOS.Controllers
                 //老師個人資料(含初始化)
                 if (response.Status == 200)
                 {
-                    using var json = await JsonDocument.ParseAsync(response.ContentStream);
+                    var json = await JsonDocument.ParseAsync(response.ContentStream);
                     if (json.RootElement.TryGetProperty("schools", out JsonElement value))
                     {
-                        schools = value.ToObject<object>();
+
+                        foreach (var obj in value.EnumerateArray())
+                        {
+                            string statusNow = obj.GetProperty("status").ToString();
+                            if (statusNow == "join") //成為老師的才放入
+                            {
+                                dynamic schoolExtobj = new ExpandoObject();
+                                var schoolJson = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync($"{obj.GetProperty("schoolId")}", new PartitionKey("Base"));
+                                var school = await JsonDocument.ParseAsync(schoolJson.ContentStream);
+                                schoolExtobj.schoolId = obj.GetProperty("schoolId");
+                                schoolExtobj.name = obj.GetProperty("name");
+                                schoolExtobj.status = obj.GetProperty("status");
+                                schoolExtobj.picture = school.RootElement.GetProperty("picture");
+                                schools.Add(schoolExtobj);
+                            }
+                        }
+                        //schools = value.ToObject<object>();
                     }
                     //預設學校ID
                     if (json.RootElement.TryGetProperty("defaultSchool", out JsonElement valueD) && !string.IsNullOrEmpty(valueD.ToString()))