Browse Source

解決衝突

upon 1 year ago
parent
commit
f4111b6aa6
73 changed files with 6089 additions and 1023 deletions
  1. 18 13
      TEAMModelBI/ClientApp/src/view/areaServe/areamanage.vue
  2. 2 2
      TEAMModelBI/ClientApp/src/view/schoolServe/school.vue
  3. 72 33
      TEAMModelBI/ClientApp/src/view/userInquire/details.vue
  4. 2 2
      TEAMModelBI/ClientApp/src/view/userInquire/socrates.vue
  5. 7 0
      TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs
  6. 118 1
      TEAMModelOS.SDK/Context/Constant/ResponseCode.cs
  7. 118 0
      TEAMModelOS.SDK/Helper/Common/ReflectorExtensions/ObjectCopyConvert.cs
  8. 12 3
      TEAMModelOS.SDK/Models/Cosmos/Common/Activity.cs
  9. 40 0
      TEAMModelOS.SDK/Models/Cosmos/Common/IotTeachingData.cs
  10. 3 0
      TEAMModelOS.SDK/Models/Cosmos/Normal/TMDOrder.cs
  11. 5 0
      TEAMModelOS.SDK/Models/Cosmos/School/Elegant.cs
  12. 2 1
      TEAMModelOS.SDK/Models/Cosmos/Student/ArtAttachment.cs
  13. 26 2
      TEAMModelOS.SDK/Models/Service/BI/BIProdAnalysis.cs
  14. 6 2
      TEAMModelOS/ClientApp/public/lang/en-US.js
  15. 6 2
      TEAMModelOS/ClientApp/public/lang/zh-CN.js
  16. 6 2
      TEAMModelOS/ClientApp/public/lang/zh-TW.js
  17. 1 0
      TEAMModelOS/ClientApp/public/mw6hwxpgKz.txt
  18. 4 2
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseJudge.vue
  19. 3 1
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseMultiple.vue
  20. 3 2
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseSingle.vue
  21. 4 0
      TEAMModelOS/ClientApp/src/components/student-web/HomeView/HomeView.less
  22. 39 17
      TEAMModelOS/ClientApp/src/components/student-web/HomeView/HomeView.vue
  23. 3 3
      TEAMModelOS/ClientApp/src/router/routes.js
  24. 5 1
      TEAMModelOS/ClientApp/src/view/joinSchool/JoinSchool.vue
  25. 1 1
      TEAMModelOS/ClientApp/src/view/login/Index.vue
  26. 1 0
      TEAMModelOS/ClientApp/src/view/mycourse/MyCourse.less
  27. 8 2
      TEAMModelOS/ClientApp/src/view/mycourse/MyCourse.vue
  28. 5 0
      TEAMModelOS/ClientApp/src/view/mycourse/exam/Exam.less
  29. 24 2
      TEAMModelOS/ClientApp/src/view/mycourse/exam/Exam.vue
  30. 6 0
      TEAMModelOS/ClientApp/src/view/mycourse/record/Record.less
  31. 22 19
      TEAMModelOS/ClientApp/src/view/mycourse/record/Record.vue
  32. 4 4
      TEAMModelOS/ClientApp/src/view/mycourse/score/AddProject.vue
  33. 0 4
      TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBox.less
  34. 7 1
      TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBoxAddTable.vue
  35. 65 58
      TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBoxStudentScore.vue
  36. 86 70
      TEAMModelOS/ClientApp/src/view/mycourse/score/ScoreBody.vue
  37. 80 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/AddCard.vue
  38. 102 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/AddResources.vue
  39. 70 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/DialogBox.less
  40. 50 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/DialogBoxTemp.vue
  41. 63 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/ReleaseSyllabus.vue
  42. 319 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/A_Evaluate.vue
  43. 273 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/A_Homework.vue
  44. 356 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/A_Questionnaire.vue
  45. 312 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/A_Vote.vue
  46. 60 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/C_CloudContent.vue
  47. 78 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/C_LocalFile.vue
  48. 99 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/C_URL.vue
  49. 454 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/Resources.less
  50. 192 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/part/BaseQnForm.vue
  51. 52 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/SyllabusAdd.vue
  52. 103 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/SyllabusSorting.vue
  53. 90 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/SyncClass.vue
  54. 14 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusIndex.less
  55. 137 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusIndex.vue
  56. 90 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusMenu.less
  57. 203 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusMenu.vue
  58. 146 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusResource.less
  59. 258 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusResource.vue
  60. 39 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusSchedule.less
  61. 155 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusSchedule.vue
  62. 15 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/addSyllabus.less
  63. 100 0
      TEAMModelOS/ClientApp/src/view/mycourse/syllabus/addSyllabus.vue
  64. 178 529
      TEAMModelOS/ClientApp/src/view/signupActivity/createActivity.vue
  65. 306 143
      TEAMModelOS/ClientApp/src/view/signupActivity/infoActivity copy.vue
  66. 119 0
      TEAMModelOS/ClientApp/src/view/signupActivity/setActivity.vue
  67. 14 1
      TEAMModelOS/ClientApp/src/view/student-web/AppiView.less
  68. 4 14
      TEAMModelOS/Controllers/Both/CourseBaseController.cs
  69. 34 33
      TEAMModelOS/Controllers/Both/ScoreCalcController.cs
  70. 628 51
      TEAMModelOS/Controllers/Client/AClassONEController.cs
  71. 131 0
      TEAMModelOS/Controllers/Common/ActivityController.cs
  72. 30 2
      TEAMModelOS/Controllers/System/WeChatPayController.cs
  73. 1 0
      TEAMModelOS/Controllers/Teacher/InitController.cs

+ 18 - 13
TEAMModelBI/ClientApp/src/view/areaServe/areamanage.vue

@@ -866,24 +866,29 @@ export default {
     function updateShortcode(data,index){
     function updateShortcode(data,index){
       let shortCodes=data;let dataIndex=index
       let shortCodes=data;let dataIndex=index
       console.log(shortCodes.length,'长度')
       console.log(shortCodes.length,'长度')
-      if(shortCodes.length !==6 && shortCodes.length !==0){
-        ElMessage.error('简码需6位字母或数字,请重新填写')
-        optionData.value[dataIndex].shortCode=curTarget.value.text
-      }else if(shortCodes.length ===0){
-        let data={id:curTarget.value.id,name:curTarget.value.name,shortCode:shortCodes}
+      // if(shortCodes.length !==6 && shortCodes.length !==0){
+      //   ElMessage.error('简码需6位字母或数字,请重新填写')
+      //   optionData.value[dataIndex].shortCode=curTarget.value.text
+      // }else if(shortCodes.length ===0){
+      //   let data={id:curTarget.value.id,name:curTarget.value.name,shortCode:shortCodes}
+      //   proxy.$api.updateAreacode(data).then((res)=>{
+      //     console.log(res,'updateCode back')
+      //     res.state === 200 ? ElMessage.success('更新成功'):ElMessage.error('操作成功')
+      //   })
+      //   curTarget.value.index=-1
+      // }else{
+      //   let data={id:curTarget.value.id,name:curTarget.value.name,shortCode:shortCodes}
+      //   proxy.$api.updateAreacode(data).then((res)=>{
+      //     console.log(res,'updateCode back')
+      //     res.state === 200 ? ElMessage.success('更新成功'):ElMessage.error('操作成功')
+      //   })
+      //   curTarget.value.index=-1
+      // } let data={id:curTarget.value.id,name:curTarget.value.name,shortCode:shortCodes}
         proxy.$api.updateAreacode(data).then((res)=>{
         proxy.$api.updateAreacode(data).then((res)=>{
           console.log(res,'updateCode back')
           console.log(res,'updateCode back')
           res.state === 200 ? ElMessage.success('更新成功'):ElMessage.error('操作成功')
           res.state === 200 ? ElMessage.success('更新成功'):ElMessage.error('操作成功')
         })
         })
         curTarget.value.index=-1
         curTarget.value.index=-1
-      }else{
-        let data={id:curTarget.value.id,name:curTarget.value.name,shortCode:shortCodes}
-        proxy.$api.updateAreacode(data).then((res)=>{
-          console.log(res,'updateCode back')
-          res.state === 200 ? ElMessage.success('更新成功'):ElMessage.error('操作成功')
-        })
-        curTarget.value.index=-1
-      }
     }
     }
     //table按钮
     //table按钮
     async function operation (index, row, state) {
     async function operation (index, row, state) {

+ 2 - 2
TEAMModelBI/ClientApp/src/view/schoolServe/school.vue

@@ -1503,7 +1503,7 @@ export default {
         ElMessage.error('API异常,规模版本排序失败')
         ElMessage.error('API异常,规模版本排序失败')
       })
       })
     }
     }
-     // ※版本判定:1.學校管理(IPDYZYLC) + 學情分析(YMPCVCIM)=「標準版」 
+  // ※版本判定:1.學校管理(IPDYZYLC) + 學情分析(YMPCVCIM)=「標準版」 
     //           2.學校管理(IPDYZYLC) + 學情分析(YMPCVCIM) + 五育看板(YPXSJ6NJ) =「專業版」  
     //           2.學校管理(IPDYZYLC) + 學情分析(YMPCVCIM) + 五育看板(YPXSJ6NJ) =「專業版」  
     function versionsEstimate (val) {
     function versionsEstimate (val) {
       console.log(shouldFilter.value)
       console.log(shouldFilter.value)
@@ -1527,7 +1527,7 @@ export default {
        // 自訂版
        // 自訂版
        arrState.custom ? originalData.value.forEach((item) => { 
        arrState.custom ? originalData.value.forEach((item) => { 
         item.edition !== null && item.edition.scaleVersion !== null && item.edition.scaleVersion !== "" ? customArr.push(item) : '' }) : ''           
         item.edition !== null && item.edition.scaleVersion !== null && item.edition.scaleVersion !== "" ? customArr.push(item) : '' }) : ''           
-      
+
       let versionArr = [...marjorArr, ...standardArr, ...basicsArr, ...customArr]
       let versionArr = [...marjorArr, ...standardArr, ...basicsArr, ...customArr]
       console.log(versionArr, '合并结果')
       console.log(versionArr, '合并结果')
       tableData.value = versionArr
       tableData.value = versionArr

+ 72 - 33
TEAMModelBI/ClientApp/src/view/userInquire/details.vue

@@ -32,15 +32,10 @@
                             <p class="item-title">{{item.title}}</p>
                             <p class="item-title">{{item.title}}</p>
                             <div class="item-content" v-show="item.state">
                             <div class="item-content" v-show="item.state">
                                 <div class="content-left">
                                 <div class="content-left">
-                                    <p>{{item.subhead1}}</p>
-                                    <span>{{item.subhead1Value}}</span>
-                                </div>
-                                <div class="content-left">
-                                    <p>{{item.subhead2}}</p>
-                                    <span>{{item.subhead2Value}}</span>
+                                    <span>上次登陆时间:{{item.subhead2Value}}</span>
                                 </div>
                                 </div>
                             </div>
                             </div>
-                            <div class="notenabled-title" v-show="!item.state">未使用</div>
+                            <div class="notenabled-title" v-show="!item.state">近期未使用</div>
                         </div>
                         </div>
                     </div>
                     </div>
         </div>
         </div>
@@ -73,27 +68,34 @@
                     <div>空间与权益</div>
                     <div>空间与权益</div>
                     <div class="expire">到期日:XXXXX</div>
                     <div class="expire">到期日:XXXXX</div>
                 </div>
                 </div>
-                <el-divider />
-                <div class="size-label">
-                    <div class="size-item" v-for="item in gaugelabels" :key="item.id">
-                        <div class="size-value" :style="{'color':item.color}">{{item.value}}%</div>
-                        <div class="size-title">{{item.title}}</div>
+                <el-divider /> 
+                <div class="sizestate" v-if="sizeandequity ==='size'">
+                    <div class="size-label">
+                        <div class="size-item" v-for="item in gaugelabels" :key="item.id">
+                            <div class="size-value" :style="{'color':item.color}">{{item.value}}%</div>
+                            <div class="size-title">{{item.title}}</div>
+                        </div>
+                         </div>
+                        <el-divider />
+                        <div class="login-echart">
+                            <commonGaugeVue :gaugeData="gaugedata"></commonGaugeVue>
                     </div>
                     </div>
                 </div>
                 </div>
-                <el-divider />
-                <div class="login-echart">
-                    <commonGaugeVue :gaugeData="gaugedata"></commonGaugeVue>
-                </div>
-                <el-divider />
-                <div class="rightsbox">
-                    <p class="rightsbox-title">权益列表:</p>
-                    <div class="rightsbox-content">
-                        <div class="rightsbox-item" v-for="item in rightsdata" :key="item.key">
-                            <div class="rightsbox-item-name">{{item.name}}</div>
-                            <div class="rightsbox-item-time">到期日:{{item.time}}</div>
+                <div class="equitystate" v-else>
+                    <div class="rightsbox">
+                        <p class="rightsbox-title">权益列表:</p>
+                        <div class="rightsbox-content">
+                            <div class="rightsbox-item" v-for="item in rightsdata" :key="item.key">
+                                <div class="rightsbox-item-name">{{item.name}}</div>
+                                <div class="rightsbox-item-time">到期日:{{item.time}}</div>
+                            </div>
                         </div>
                         </div>
                     </div>
                     </div>
                 </div>
                 </div>
+                <div class="tab-state">
+                    <div :class="[sizeandequity ==='size' ? 'opts':'','tab-state-btn']" @click="sizeandequity='size'">我的空间</div>
+                    <div :class="[sizeandequity !=='size' ? 'opts':'','tab-state-btn']" @click="sizeandequity='equity'">我的权益</div>
+                </div>
             </div>
             </div>
             <div class="iesdiv">
             <div class="iesdiv">
                 <div  class="common-header-title">
                 <div  class="common-header-title">
@@ -148,6 +150,7 @@ let { proxy } = getCurrentInstance()
 let activeName = ref('basics')
 let activeName = ref('basics')
 let userdetailState=ref(false)
 let userdetailState=ref(false)
 let tabPosition = ref('left')
 let tabPosition = ref('left')
+let sizeandequity=ref('size')
 let usernames=ref('')
 let usernames=ref('')
 let userdata = ref([
 let userdata = ref([
     { id: 1, icon: '#icon-ic_idcard', value: '0', title: '',key:'integral',check:false ,hint:'用户ID'},
     { id: 1, icon: '#icon-ic_idcard', value: '0', title: '',key:'integral',check:false ,hint:'用户ID'},
@@ -158,10 +161,10 @@ let userdata = ref([
     { id: 6, icon: '#icon-shijian2', value: '2023-04-23', title: '', key: 'time', check: false ,hint:'上次登录时间' },
     { id: 6, icon: '#icon-shijian2', value: '2023-04-23', title: '', key: 'time', check: false ,hint:'上次登录时间' },
 ])
 ])
 let productdata = ref([
 let productdata = ref([
-    { id: 1, title: 'HiTeach', subhead1: '课堂总时长', subhead1Value: '13H', subhead2: '课堂数量', subhead2Value: 25,key:'HiTeach',state: false },
-    { id: 2, title: 'HiTA', subhead1: '使用时长', subhead1Value: '13H', subhead2: '协助课堂', subhead2Value: 199, key:'HiTA',state: false },
-    { id: 3, title: 'IES', subhead1: '使用资源课程', subhead1Value: '159', subhead2: '贡献资源数量', subhead2Value: 13, key:'IES', state: false },
-    { id: 4, title: '苏格拉底', subhead1: '上传影片', subhead1Value: '9', subhead2: '议课数量', subhead2Value: 15,key:'Socrates', state: false },
+    { id: 1, title: 'HiTeach', value:0,key:'HiTeach',state: false },
+    { id: 2, title: 'HiTA',value:0, key:'HiTA',state: false },
+    { id: 3, title: 'IES', value:0,key:'IES', state: false },
+    { id: 4, title: '苏格拉底', value:0,key:'Socrates', state: false },
 ])
 ])
 let tableData = ref([
 let tableData = ref([
     { time: '2023-07-05 15:33', ip: '222.209.14.199', location: '四川省成都市',platform:'HiTeach' },
     { time: '2023-07-05 15:33', ip: '222.209.14.199', location: '四川省成都市',platform:'HiTeach' },
@@ -443,11 +446,15 @@ function initdata() {
     userdata.value[4].value = 'XXXX'
     userdata.value[4].value = 'XXXX'
     userdata.value[5].value = 'XXXX-XX-XX'
     userdata.value[5].value = 'XXXX-XX-XX'
     //产品使用及安装情况
     //产品使用及安装情况
-    let {hiteach,hita,ies5,sokrates}=transmitData
-    transmitData.hasOwnProperty('hiteach') && Object.keys(hiteach).length !== 0 ? (productdata.value[0].state=true,productdata.value[0].subhead1Value=hiteach.subhead1Value,productdata.value[0].subhead2Value=hiteach.subhead2Value):productdata.value[0].state=false
-    transmitData.hasOwnProperty('hita') && Object.keys(hita).length !== 0 ? (productdata.value[1].state=true,productdata.value[1].subhead1Value=hita.subhead1Value,productdata.value[1].subhead2Value=hita.subhead2Value):productdata.value[1].state=false
-    transmitData.hasOwnProperty('ies5') && Object.keys(ies5).length !== 0 ? (productdata.value[2].state=true,productdata.value[2].subhead1Value='XXX',productdata.value[2].subhead2Value='XXX'):productdata.value[2].state=false
-    transmitData.hasOwnProperty('sokrates') && Object.keys(sokrates).length !== 0 ? (productdata.value[3].state=true,productdata.value[3].subhead1Value='XXX',productdata.value[3].subhead2Value='XXX'):productdata.value[3].state=false
+    let {login}=transmitData
+    if(login.length >0){
+       login.forEach(item => {
+         let typename=item.product
+         productdata.value.forEach(items=>{
+            typename === items.key ? items.value === 0 ? (items.value=item.time,items.state=true): item.time > items.value ? (items.value=item.time,items.state=true):'':''
+         })
+       })
+    }
     //空间与权益
     //空间与权益
     let {usedSize,teachSize,totalSize,surplusSize}=transmitData.ies5
     let {usedSize,teachSize,totalSize,surplusSize}=transmitData.ies5
     let usePercentum=parseInt(((Number(bytesToGB(usedSize))+Number(bytesToGB(teachSize)))/Number(bytesToGB(totalSize)))*100);let useGsize=proxy.$common.convertSize(usedSize)
     let usePercentum=parseInt(((Number(bytesToGB(usedSize))+Number(bytesToGB(teachSize)))/Number(bytesToGB(totalSize)))*100);let useGsize=proxy.$common.convertSize(usedSize)
@@ -569,7 +576,7 @@ onMounted(() => {
 .item-content{
 .item-content{
     width:100%;
     width:100%;
     display: flex;
     display: flex;
-    justify-content: space-between;
+    justify-content: center;
 }
 }
 .content-left,.content-right{
 .content-left,.content-right{
     margin-top:5px;
     margin-top:5px;
@@ -644,6 +651,38 @@ onMounted(() => {
     background-color: #fff;
     background-color: #fff;
     border-radius: 5px;
     border-radius: 5px;
     box-shadow: rgba(0, 0, 0, 0.3) 0px 3px 8px;
     box-shadow: rgba(0, 0, 0, 0.3) 0px 3px 8px;
+    position: relative;
+}
+.tab-state{
+    position:absolute;
+    width:18px;
+    right:-18px;
+    top:0px;
+    display: flex;
+    flex-wrap: wrap;
+}
+.tab-state-btn{
+    width:100%;
+    line-height: 14px;
+    font-size:14px;
+    padding: 2px;
+    border: 1px solid #ccc; /* 设置整个边框 */
+    border-left: none; /* 取消左边边框 */
+    border-radius: 0 5px 5px 0px;
+    color:#bbbecd;
+    cursor: pointer;
+    background-color: #c8c9cc;
+    color:#fff;
+    margin-top:1px;
+}
+.tab-state-btn:nth-child(2){
+    margin-top: 5px;
+}
+.opts{
+    background-color:#79bbff;
+    outline:none;
+    border-color:#79bbff;
+    color:#fff;
 }
 }
 .size-label{
 .size-label{
     width:100%;
     width:100%;

+ 2 - 2
TEAMModelBI/ClientApp/src/view/userInquire/socrates.vue

@@ -189,9 +189,9 @@ let auxiliary=ref([
  function initdatas(){
  function initdatas(){
     console.log(props,'苏格拉底')
     console.log(props,'苏格拉底')
     primary.value[0].value='XXX'
     primary.value[0].value='XXX'
-    primary.value[1].value=props.sokratesdatas.t_green
+    primary.value[1].value='XXX'
     primary.value[2].value='XXX'
     primary.value[2].value='XXX'
-    primary.value[3].value=props.sokratesdatas.t_data
+    primary.value[3].value='XXX'
 
 
     auxiliary.value[0].value='XXX'
     auxiliary.value[0].value='XXX'
     auxiliary.value[1].value='XXX'
     auxiliary.value[1].value='XXX'

+ 7 - 0
TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs

@@ -1542,6 +1542,10 @@ namespace TEAMModelOS.FunctionV4
                 errorItems.Add(item);
                 errorItems.Add(item);
             }
             }
             try {
             try {
+               /* bool isError =  examClassResults.SelectMany(c => c.status).ToList().Exists(z => z == 1);
+                if () { 
+                
+                }*/
                 if (errorItems.Count == 0)
                 if (errorItems.Count == 0)
                 {
                 {
                     // 新增逻辑 收集错题内容
                     // 新增逻辑 收集错题内容
@@ -1654,6 +1658,9 @@ namespace TEAMModelOS.FunctionV4
                             }
                             }
                             index_item++;
                             index_item++;
                         }
                         }
+                        if (index.Count == 0) {
+                            continue;
+                        }
                         //int[] item_index = ss[n];
                         //int[] item_index = ss[n];
                         foreach (var item in index)
                         foreach (var item in index)
                         {
                         {

+ 118 - 1
TEAMModelOS.SDK/Context/Constant/ResponseCode.cs

@@ -58,6 +58,123 @@ namespace TEAMModelOS
         /// 响应超时
         /// 响应超时
         /// </summary>
         /// </summary>
         public readonly static int TIMEOUT_ERROR = 503;
         public readonly static int TIMEOUT_ERROR = 503;
-        
+
+        #region 返回状态码
+        /// <summary>
+        /// 成功  200
+        /// </summary>
+        public readonly static int _200Ok = 200;
+
+        /// <summary>
+        /// 部分创建成功  201
+        /// </summary>
+        public readonly static int _201Created = 201;
+
+        /// <summary>
+        /// 已接受请求,处理未完成  202
+        /// </summary>
+        public readonly static int _202Accepted = 202;
+
+        /// <summary>
+        /// 非授权信息  203
+        /// </summary>
+        public readonly static int _203NonUnauthorizedInfo = 203;
+
+        /// <summary>
+        ///  服务器成功处理了请求,但没有返回任何内容。  204
+        /// </summary>
+        public readonly static int _204NoContent = 204;
+
+        /// <summary>
+        /// 参数错误  400
+        /// </summary>
+        public readonly static int _400ParamsError = 400;
+
+        /// <summary>
+        /// 未授权 请求要求身份验证  401
+        /// </summary>
+        public readonly static int _401Unauthorized = 401;
+
+        /// <summary>
+        /// 需要付费  402
+        /// </summary>
+        public readonly static int _402PaymentRequired = 402;
+
+        /// <summary>
+        /// 服务器拒绝/禁用  403
+        /// </summary>
+        public readonly static int _403Forbidden = 403;
+
+        /// <summary>
+        /// 密码错误
+        /// </summary>
+        public readonly static int _40301ForbiddenPwd = 40301;
+
+        /// <summary>
+        /// 未找到    404
+        /// </summary>
+        public readonly static int _404NotFound = 404;
+
+        /// <summary>
+        /// 方法不可用  405
+        /// </summary>
+        public readonly static int _405NotAllow = 405;
+
+        /// <summary>
+        /// 请求超时   408
+        /// </summary>
+        public readonly static int _408RespondTimeOut = 408;
+
+        /// <summary>
+        /// 已存在   409
+        /// </summary>
+        public readonly static int _409Conflict = 409;
+
+        /// <summary>
+        /// 过期    410
+        /// </summary>
+        public readonly static int _410Gone = 410;
+
+        /// <summary>
+        /// 异常 411
+        /// </summary>
+        public readonly static int _411Abnormal = 411;
+
+        /// <summary>
+        /// 不支持的媒体类型  415
+        /// </summary>
+        public readonly static int _415NoMediaType = 415;
+
+        /// <summary>
+        /// 创建失败
+        /// </summary>
+        public readonly static int _417CreateFailed = 417;
+
+        /// <summary>
+        /// 服务器错误  500
+        /// </summary>
+        public readonly static int _500Error = 500;
+
+        /// <summary>
+        /// 服务器拒绝
+        /// </summary>
+        public readonly static int _501Refuse = 501;
+
+        /// <summary>
+        /// 网关错误 502
+        /// </summary>
+        public readonly static int _502GatewayError = 502;
+
+        /// <summary>
+        /// 网关超时  504
+        /// </summary>
+        public readonly static int _504GatewayTimeOut = 504;
+
+        /// <summary>
+        /// 存储不足   507
+        /// </summary>
+        public readonly static int _507InsufficientStorage = 507;
+        #endregion
+
     }
     }
 }
 }

+ 118 - 0
TEAMModelOS.SDK/Helper/Common/ReflectorExtensions/ObjectCopyConvert.cs

@@ -0,0 +1,118 @@
+using HTEXLib.COMM.Helpers;
+using Microsoft.IdentityModel.Tokens;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.Extension;
+
+namespace SDK.Helpers
+{
+    public static class ObjectCopyConvert
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <typeparam name="ST"></typeparam>
+        /// <param name="json"></param>
+        /// <param name="target"></param>
+        /// <param name="filter">只修改部分指定的属性</param>
+        public static void CopyToSameProperty<ST>(this JsonElement json, ST target, List<string>? filter = null) {
+            ST? source = json.ToObject<ST>();
+            PropertyInfo[] sourceProperties = source!.GetType().GetProperties();
+            PropertyInfo[] targetProperties = target!.GetType().GetProperties();
+
+            foreach (PropertyInfo sourceProperty in sourceProperties)
+            {
+                //数据类型相同,属性名称相同,可能存在赋值关系。
+                PropertyInfo? targetProperty = targetProperties.FirstOrDefault(p => p.Name == sourceProperty.Name && p.PropertyType == sourceProperty.PropertyType);
+                var data_source = sourceProperty.GetValue(source);
+                if (targetProperty != null && sourceProperty.GetValue(source) != null)
+                {
+                    // JsonElement element_source = data_source!.ToJsonString().ToObject<JsonElement>();
+                    //var data_target = targetProperty.GetValue(target);
+                    //JsonElement element_target = data_target != null ? data_target.ToJsonString().ToObject<JsonElement>() : default;
+                    JsonElement temp = default;
+                    if (json.TryGetProperty(sourceProperty.Name, out temp)
+                        //驼峰命名,首字母小写
+                        || json.TryGetProperty($"{sourceProperty.Name.Substring(0, 1).ToLower()}{sourceProperty.Name.Substring(1)}", out temp))
+                    {
+                        if (filter.IsEmpty())
+                        {
+                            //只要传递了值才会运行此处
+                            targetProperty.SetValue(target, sourceProperty.GetValue(source));
+                        }
+                        else
+                        {
+                            if (filter!.Contains(targetProperty.Name))
+                            {
+                                targetProperty.SetValue(target, sourceProperty.GetValue(source));
+                            }
+                        }
+                    }
+                    else
+                    {
+                        // Console.WriteLine("默认值,如数字,bool类型下的默认值");
+                    }
+                    //var json=  sourceProperty.GetValue(source)!.ToJsonString().ToObject<JsonElement>();
+                    //判断数字类型,如果前后数字相同,则不赋值,防止出现0这种。
+                    //判断True ,如果相同,也不赋值,防止出现
+                }
+            }
+        }
+        /// <summary>
+        /// 复制类型
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <typeparam name="V"></typeparam>
+        /// <param name="json"></param>
+        /// <param name="target"></param>
+        /// <param name="filter"></param>
+        public static void CopyToSameProperty<S, T>(this JsonElement json, T target, List<string>? filter = null)
+        {
+            S? source=json.ToObject<S>();
+            PropertyInfo[] sourceProperties = source!.GetType().GetProperties();
+            PropertyInfo[] targetProperties = target!.GetType().GetProperties();
+
+            foreach (PropertyInfo sourceProperty in sourceProperties)
+            {
+                //数据类型相同,属性名称相同,可能存在赋值关系。
+                PropertyInfo? targetProperty = targetProperties.FirstOrDefault(p => p.Name == sourceProperty.Name  && p.PropertyType==sourceProperty.PropertyType );
+                var data_source = sourceProperty.GetValue(source);
+                if (targetProperty != null && sourceProperty.GetValue(source) != null)
+                {
+                    // JsonElement element_source = data_source!.ToJsonString().ToObject<JsonElement>();
+                    //var data_target = targetProperty.GetValue(target);
+                    //JsonElement element_target = data_target != null ? data_target.ToJsonString().ToObject<JsonElement>() : default;
+                    JsonElement temp = default;
+                    if (json.TryGetProperty(sourceProperty.Name, out temp)
+                        //驼峰命名,首字母小写
+                        || json.TryGetProperty($"{sourceProperty.Name.Substring(0, 1).ToLower()}{sourceProperty.Name.Substring(1)}", out temp))
+                    {
+                        if (filter.IsEmpty())
+                        {
+                            //只要传递了值才会运行此处
+                            targetProperty.SetValue(target, sourceProperty.GetValue(source));
+                        }
+                        else {
+                            if (filter!.Contains(targetProperty.Name))
+                            {
+                                targetProperty.SetValue(target, sourceProperty.GetValue(source));
+                            }
+                        }
+                    }
+                    else {
+                       // Console.WriteLine("默认值,如数字,bool类型下的默认值");
+                    }
+                    //var json=  sourceProperty.GetValue(source)!.ToJsonString().ToObject<JsonElement>();
+                    //判断数字类型,如果前后数字相同,则不赋值,防止出现0这种。
+                    //判断True ,如果相同,也不赋值,防止出现
+                   
+                }
+            }
+        }
+    }
+}

+ 12 - 3
TEAMModelOS.SDK/Models/Cosmos/Common/Activity.cs

@@ -2,10 +2,11 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations;
 using System.Linq;
 using System.Linq;
+using System.Net.Mail;
 using System.Text;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
-namespace TEAMModelOS.SDK.Models.Cosmos.Common
+namespace TEAMModelOS.SDK.Models
 {
 {
     public class Activity : CosmosEntity
     public class Activity : CosmosEntity
     {
     {
@@ -14,27 +15,32 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
         public Activity() {
         public Activity() {
             pk="Activity";
             pk="Activity";
         }
         }
+        [Required(ErrorMessage = "Required")]
         public string name { get; set; }
         public string name { get; set; }
+        [Required(ErrorMessage = "Required")]
         public string subject { get; set; }
         public string subject { get; set; }
         public string description { get; set; }
         public string description { get; set; }
         public string address { get; set; }
         public string address { get; set; }
         public long stime { get; set; }
         public long stime { get; set; }
         public long etime { get; set; }
         public long etime { get; set; }
         public string poster { get; set; }
         public string poster { get; set; }
-        public List<string> attachment { get; set; } = new List<string>();
+        public List<Attachment> attachment { get; set; } = new List<Attachment>();
         public List<string> zb { get; set; } = new List<string>();
         public List<string> zb { get; set; } = new List<string>();
         public List<string> cb { get; set; } = new List<string>();
         public List<string> cb { get; set; } = new List<string>();
         /// <summary>
         /// <summary>
         /// "hbcn/区级id,areaId",
         /// "hbcn/区级id,areaId",
         /// </summary>
         /// </summary>
+        [Required(ErrorMessage = "Required")]
         public string owner { get; set; }
         public string owner { get; set; }
         /// <summary>
         /// <summary>
         /// "public公开/area区级/school校级",
         /// "public公开/area区级/school校级",
         /// </summary>
         /// </summary>
+        [Required(ErrorMessage = "Required")]
         public string scope { get; set; }
         public string scope { get; set; }
         /// <summary>
         /// <summary>
         /// "enroll/报名制,invite/邀请制",
         /// "enroll/报名制,invite/邀请制",
         /// </summary>
         /// </summary>
+        [Required(ErrorMessage = "Required")]
         public string joinMode { get; set; }
         public string joinMode { get; set; }
         /// <summary>
         /// <summary>
         /// //区级活动时允许参与的学校,如果为空则全部学校
         /// //区级活动时允许参与的学校,如果为空则全部学校
@@ -60,7 +66,10 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
         /// 创建时间
         /// 创建时间
         /// </summary>
         /// </summary>
         public long createTime {  get; set; }
         public long createTime {  get; set; }
-
+        /// <summary>
+        /// 创建者
+        /// </summary>
+        public string creatorId { get; set; }
     }
     }
 
 
     /// <summary>
     /// <summary>

+ 40 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/IotTeachingData.cs

@@ -105,6 +105,38 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
         /// 是否送出小數據或SOK服務 0:false 1:true
         /// 是否送出小數據或SOK服務 0:false 1:true
         /// </summary>
         /// </summary>
         public string sendSok { get; set; }
         public string sendSok { get; set; }
+        /// <summary>
+        /// 學習型態-互評 0:false 1:true
+        /// </summary>
+        public string learnPeer { get; set; }
+        /// <summary>
+        /// 學習型態-協作 0:false 1:true
+        /// </summary>
+        public string learnCoop { get; set; }
+        /// <summary>
+        /// 課堂中有使用文字雲 0:false 1:true
+        /// </summary>
+        public string useWordCloud { get; set; }
+        /// <summary>
+        /// 課堂中有使用clouDAS 0:false 1:true
+        /// </summary>
+        public string useClouDAS { get; set; }
+        /// <summary>
+        /// 課堂中有使用GPT 0:false 1:true
+        /// </summary>
+        public string useGPT { get; set; }
+        /// <summary>
+        /// 課堂中有使用IES5測驗模式 0:false 1:true
+        /// </summary>
+        public string useIes5Test { get; set; }
+        /// <summary>
+        /// 課堂中有使用紙本測驗模式 0:false 1:true
+        /// </summary>
+        public string usePaperTest { get; set; }
+        /// <summary>
+        /// 課堂中有使用Excel測驗模式 0:false 1:true
+        /// </summary>
+        public string useExcelTest { get; set; }
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -148,5 +180,13 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
         public int item { get; set; } //題數
         public int item { get; set; } //題數
         public int interact { get; set; } //互動總次數
         public int interact { get; set; } //互動總次數
         public int sendSok { get; set; } //送出小數據或SOK服務
         public int sendSok { get; set; } //送出小數據或SOK服務
+        public int learnPeer { get; set; } //學習型態-互評
+        public int learnCoop { get; set; } //學習型態-協作
+        public int useWordCloud { get; set; } //課堂中有使用文字雲
+        public int useClouDAS { get; set; } //課堂中有使用clouDAS
+        public int useGPT { get; set; } //課堂中有使用GPT
+        public int useIes5Test { get; set; } //課堂中有使用IES5測驗模式
+        public int usePaperTest { get; set; } //課堂中有使用紙本測驗模式
+        public int useExcelTest { get; set; } //課堂中有使用Excel測驗模式
     }
     }
 }
 }

+ 3 - 0
TEAMModelOS.SDK/Models/Cosmos/Normal/TMDOrder.cs

@@ -23,6 +23,9 @@ namespace TEAMModelOS.SDK.Models
         public string buyer_email { get; set; }
         public string buyer_email { get; set; }
         public string return_url { get; set; }
         public string return_url { get; set; }
         public string notify_url { get; set; }
         public string notify_url { get; set; }
+        public string ip { get; set; }
+        public string region { get; set; }
+        public string school { get; set; }
         /// <summary>
         /// <summary>
         /// 微信支付二维码
         /// 微信支付二维码
         /// </summary>
         /// </summary>

+ 5 - 0
TEAMModelOS.SDK/Models/Cosmos/School/Elegant.cs

@@ -46,6 +46,11 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         /// </summary>
         public string type { get; set; }
         public string type { get; set; }
         public List<string> classes { get; set; } = new List<string>();
         public List<string> classes { get; set; } = new List<string>();
+        public string target { get; set; }
         public List<Attachment> attachments { get; set; } = new List<Attachment>();
         public List<Attachment> attachments { get; set; } = new List<Attachment>();
+        /// <summary>
+        /// 业务类型。elegant 德育, art 艺术
+        /// </summary>
+        public string bizCode { get; set; } = "elegant";
     }
     }
 }
 }

+ 2 - 1
TEAMModelOS.SDK/Models/Cosmos/Student/ArtAttachment.cs

@@ -50,7 +50,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Student
         public string des { get; set; }
         public string des { get; set; }
         //0 艺术作品 1 等级证书
         //0 艺术作品 1 等级证书
         public int artType { get; set; }
         public int artType { get; set; }
-        // 0 校级 1 区级 2 市级 3 省级 4 国家级
+        // 0 校级 1 区级 2 市级 3 省级 4 国家级 5艺术体验 6艺术特长、7艺术考级 8观看演出 9社会学习 10 乐器演奏 11观看展览 12个人演唱 13书画创作 14合唱表演 15 艺术评比...
         public int level { get; set; }
         public int level { get; set; }
         public long uploadTime { get; set; }
         public long uploadTime { get; set; }
         public long updateTime { get; set; }
         public long updateTime { get; set; }
@@ -58,6 +58,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Student
         /// 上传的文件
         /// 上传的文件
         /// </summary>
         /// </summary>
         public List<Attachment> files { get; set; }
         public List<Attachment> files { get; set; }
+        public string uploadName { get; set; }
 
 
     }
     }
 }
 }

File diff suppressed because it is too large
+ 26 - 2
TEAMModelOS.SDK/Models/Service/BI/BIProdAnalysis.cs


+ 6 - 2
TEAMModelOS/ClientApp/public/lang/en-US.js

@@ -1151,6 +1151,9 @@ const LANG_EN_US = {
         cusTab10: 'Create Announcement',
         cusTab10: 'Create Announcement',
         cusTab11: 'Create Survey',
         cusTab11: 'Create Survey',
         cusTab12: 'Create Poll',
         cusTab12: 'Create Poll',
+        cusTab13: 'Syllabus',
+        cusTab14: 'Sorting Syllabus',
+        cusTab15: 'Add New Syllabus',
         fullTips1: "School space is full, can't create school course assessment",
         fullTips1: "School space is full, can't create school course assessment",
         fullTips2: "Personal space is full, can't create personal course evaluation",
         fullTips2: "Personal space is full, can't create personal course evaluation",
         createPrivCus: 'Create Personal Course',
         createPrivCus: 'Create Personal Course',
@@ -7737,12 +7740,13 @@ const LANG_EN_US = {
         dataIsSave: 'Data has been saved',
         dataIsSave: 'Data has been saved',
         remind: 'Reminder',
         remind: 'Reminder',
         remindMessage1: 'There are unsaved settings, do you want to continue?',
         remindMessage1: 'There are unsaved settings, do you want to continue?',
-        remindMessage2: 'There are unsaved settings, do you want to continue?',
+        remindMessage2: 'There are unsaved settings, do you want to continue?',        
         deleteRemind1: 'Delete Item',
         deleteRemind1: 'Delete Item',
         remindMessage3: 'The data will not be retrieved after deletion. Do you want to delete it? ',
         remindMessage3: 'The data will not be retrieved after deletion. Do you want to delete it? ',
         deleteRemind2: 'Delete Activity Item',
         deleteRemind2: 'Delete Activity Item',
         remindMessage4: 'The activity item has been deleted',
         remindMessage4: 'The activity item has been deleted',
         remindMessage5: 'Score login completed',
         remindMessage5: 'Score login completed',
+        remindMessage6: 'There are unsaved settings, do you want to continue?',
         scoreCalc: ' Score Calculation',
         scoreCalc: ' Score Calculation',
         modifyContent: ' can be modified',
         modifyContent: ' can be modified',
         ask: 'Note',
         ask: 'Note',
@@ -7754,6 +7758,6 @@ const LANG_EN_US = {
         chooseAddWay:'Please choose how to add a score sheet',
         chooseAddWay:'Please choose how to add a score sheet',
         addNewTable:'Added "new" score sheet',
         addNewTable:'Added "new" score sheet',
         InheritTable:'Inherit the grade list',
         InheritTable:'Inherit the grade list',
-        addTableNotice:'Notice: The newly added score sheet results are based on the current system scores. The score sheet results are not linked to other functions',          
+        addTableNotice:'Note: The newly added score sheet will be based on the existing scores in the current system. That the newly created score sheet will not be affected or linked to other functions',          
     }
     }
 }
 }

+ 6 - 2
TEAMModelOS/ClientApp/public/lang/zh-CN.js

@@ -1151,6 +1151,9 @@ const LANG_ZH_CN = {
         cusTab10: '新建公告',
         cusTab10: '新建公告',
         cusTab11: '新建问卷',
         cusTab11: '新建问卷',
         cusTab12: '新建投票',
         cusTab12: '新建投票',
+        cusTab13: '课堂课纲',
+        cusTab14: '排序课纲',
+        cusTab15: '新增课纲',
         fullTips1: '学校空间已满,无法创建学校课程评测',
         fullTips1: '学校空间已满,无法创建学校课程评测',
         fullTips2: '个人空间已满,无法创建个人课程评测',
         fullTips2: '个人空间已满,无法创建个人课程评测',
         createPrivCus: '新建个人课程',
         createPrivCus: '新建个人课程',
@@ -7739,12 +7742,13 @@ const LANG_ZH_CN = {
         dataIsSave:'资料已储存',
         dataIsSave:'资料已储存',
         remind:'提醒',
         remind:'提醒',
         remindMessage1:'有未储存的设定,要继续切换活动项目吗? ',
         remindMessage1:'有未储存的设定,要继续切换活动项目吗? ',
-        remindMessage2:'有未储存的设定,要继续新增活动项目吗? ',
+        remindMessage2:'有未储存的设定,要继续新增活动项目吗? ',        
         deleteRemind1:'删除活动子项目',
         deleteRemind1:'删除活动子项目',
         remindMessage3:'活动子项目数据删除后将无法找回,确认删除当前活动子项目吗?',
         remindMessage3:'活动子项目数据删除后将无法找回,确认删除当前活动子项目吗?',
         deleteRemind2:'删除活动项目',
         deleteRemind2:'删除活动项目',
         remindMessage4:'活动项目已删除',
         remindMessage4:'活动项目已删除',
         remindMessage5:'分数登录完成',
         remindMessage5:'分数登录完成',
+        remindMessage6:'有未储存的设定,确定要继续吗? ',
         scoreCalc:'成绩计算',        
         scoreCalc:'成绩计算',        
         modifyContent:'可修改内容       ',
         modifyContent:'可修改内容       ',
         ask:'询问',
         ask:'询问',
@@ -7756,6 +7760,6 @@ const LANG_ZH_CN = {
         chooseAddWay:'请选择新增成绩表的方式',
         chooseAddWay:'请选择新增成绩表的方式',
         addNewTable:'新增"新"成绩表',
         addNewTable:'新增"新"成绩表',
         InheritTable:'沿用成绩表',
         InheritTable:'沿用成绩表',
-        addTableNotice:'注意:新增的成绩表成绩以当下系统有的成绩为准,成绩表成绩没有跟其他功能连动',          
+        addTableNotice:'注意:新增的成绩表将以当下系统中的现有成绩作为基础,新建的成绩表不会受到其他功能的影响或连动',          
     }
     }
 }
 }

+ 6 - 2
TEAMModelOS/ClientApp/public/lang/zh-TW.js

@@ -1151,6 +1151,9 @@ const LANG_ZH_TW = {
         cusTab10: '新建公告',
         cusTab10: '新建公告',
         cusTab11: '新建問卷',
         cusTab11: '新建問卷',
         cusTab12: '新建投票',
         cusTab12: '新建投票',
+        cusTab13: '課堂課綱',
+        cusTab14: '排序課綱',
+        cusTab15: '新增課綱',
         fullTips1: '學校空間已滿,無法創建學校課程評量',
         fullTips1: '學校空間已滿,無法創建學校課程評量',
         fullTips2: '個人空間已滿,無法創建個人課程評量',
         fullTips2: '個人空間已滿,無法創建個人課程評量',
         createPrivCus: '新建個人課程',
         createPrivCus: '新建個人課程',
@@ -7738,12 +7741,13 @@ const LANG_ZH_TW = {
         dataIsSave:'資料已儲存',
         dataIsSave:'資料已儲存',
         remind:'提醒',
         remind:'提醒',
         remindMessage1:'有未儲存的設定,要繼續切換活動項目嗎?',
         remindMessage1:'有未儲存的設定,要繼續切換活動項目嗎?',
-        remindMessage2:'有未儲存的設定,要繼續新增活動項目嗎?',
+        remindMessage2:'有未儲存的設定,要繼續新增活動項目嗎?',        
         deleteRemind1:'刪除活動子項目',
         deleteRemind1:'刪除活動子項目',
         remindMessage3:'活動子項目數據刪除後將無法找回,確認刪除當前活動子項目嗎?',
         remindMessage3:'活動子項目數據刪除後將無法找回,確認刪除當前活動子項目嗎?',
         deleteRemind2:'刪除活動項目',
         deleteRemind2:'刪除活動項目',
         remindMessage4:'活動項目已刪除',
         remindMessage4:'活動項目已刪除',
         remindMessage5:'分數登錄完成',
         remindMessage5:'分數登錄完成',
+        remindMessage6:'有未儲存的設定,確定要繼續嗎?',
         scoreCalc:'成績計算',        
         scoreCalc:'成績計算',        
         modifyContent:'可修改內容       ',
         modifyContent:'可修改內容       ',
         ask:'詢問',
         ask:'詢問',
@@ -7755,7 +7759,7 @@ const LANG_ZH_TW = {
         chooseAddWay:'請選擇新增成績表的方式',
         chooseAddWay:'請選擇新增成績表的方式',
         addNewTable:'新增"新"成績表',
         addNewTable:'新增"新"成績表',
         InheritTable:'沿用成績表',
         InheritTable:'沿用成績表',
-        addTableNotice:'注意:新增的成績表成績以當下系統有的成績為準,成績表成績沒有跟其他功能連動',
+        addTableNotice:'注意:新增的成績表將以當下系統中的現有成績作為基礎,新建的成績表不會受到其他功能的影響或連動',
     }
     }
 
 
 
 

+ 1 - 0
TEAMModelOS/ClientApp/public/mw6hwxpgKz.txt

@@ -0,0 +1 @@
+b695ac74b5189d16782294274ab65282

+ 4 - 2
TEAMModelOS/ClientApp/src/components/questionnaire/BaseJudge.vue

@@ -132,7 +132,7 @@
 					})
 					})
 					this.$nextTick(() => {
 					this.$nextTick(() => {
 						let editor = new E(that.$refs['singleOption' + newIndex][0])
 						let editor = new E(that.$refs['singleOption' + newIndex][0])
-						this.$editorTools.initSimpleEditor(editor)
+						this.$editorTools.initSimpleEditor(editor)						
 						editor.config.onchange = (html) => {
 						editor.config.onchange = (html) => {
 							let key = String.fromCharCode(64 + parseInt(newIndex + 1))
 							let key = String.fromCharCode(64 + parseInt(newIndex + 1))
 							let codeArr = this.optionsContent.map(item => item.code)
 							let codeArr = this.optionsContent.map(item => item.code)
@@ -241,7 +241,9 @@
 			this.$editorTools.initSimpleEditor(stemEditor)
 			this.$editorTools.initSimpleEditor(stemEditor)
 					stemEditor.create()
 					stemEditor.create()
 			this.stemEditor = stemEditor
 			this.stemEditor = stemEditor
-			this.initEditors()
+			if(!this.editInfo){
+				this.initEditors()
+			}			
 
 
 			if (this.editInfo && this.editInfo.question) {
 			if (this.editInfo && this.editInfo.question) {
 				console.log('进入判断题Mounted编辑')
 				console.log('进入判断题Mounted编辑')

+ 3 - 1
TEAMModelOS/ClientApp/src/components/questionnaire/BaseMultiple.vue

@@ -273,7 +273,9 @@
 			this.$editorTools.initSimpleEditor(stemEditor)
 			this.$editorTools.initSimpleEditor(stemEditor)
 					stemEditor.create()
 					stemEditor.create()
 			this.stemEditor = stemEditor
 			this.stemEditor = stemEditor
-			this.initEditors()
+			if(!this.editInfo){
+				this.initEditors()
+			}
 
 
 			if (this.editInfo && this.editInfo.question) {
 			if (this.editInfo && this.editInfo.question) {
 				console.log('进入多选题Mounted编辑')
 				console.log('进入多选题Mounted编辑')

+ 3 - 2
TEAMModelOS/ClientApp/src/components/questionnaire/BaseSingle.vue

@@ -239,8 +239,9 @@
 			this.$editorTools.initSimpleEditor(stemEditor)
 			this.$editorTools.initSimpleEditor(stemEditor)
 			stemEditor.create()
 			stemEditor.create()
 			this.stemEditor = stemEditor
 			this.stemEditor = stemEditor
-			this.initEditors()
-
+			if(!this.editInfo){
+				this.initEditors()
+			}
 			if (this.editInfo && this.editInfo.question) {
 			if (this.editInfo && this.editInfo.question) {
 				console.log('进入单选题Mounted编辑')
 				console.log('进入单选题Mounted编辑')
 				this.editSingleInfo = JSON.parse(JSON.stringify(this.editInfo)) 
 				this.editSingleInfo = JSON.parse(JSON.stringify(this.editInfo)) 

+ 4 - 0
TEAMModelOS/ClientApp/src/components/student-web/HomeView/HomeView.less

@@ -132,6 +132,10 @@
                 color: #03966a;
                 color: #03966a;
             }
             }
         }
         }
+
+        .course-box {
+            display: inline-block;
+        }
     }
     }
 
 
     .no-data {
     .no-data {

+ 39 - 17
TEAMModelOS/ClientApp/src/components/student-web/HomeView/HomeView.vue

@@ -2,26 +2,28 @@
     <div class="home-view">
     <div class="home-view">
         <Loading v-show="isLoading" bgColor="rgba(0, 0, 0, 0.3)"></Loading>
         <Loading v-show="isLoading" bgColor="rgba(0, 0, 0, 0.3)"></Loading>
         <div class="home-head home-card">
         <div class="home-head home-card">
-            <div class="home-title-name">
+            <div class="home-title-name title-one">
                 {{ $t("studentWeb.home.title.joinClass") }}
                 {{ $t("studentWeb.home.title.joinClass") }}
                 <Icon type="md-add-circle" color="#02B35A" size="17" :title="$t('studentWeb.home.joinClass')" @click="isScale ? false : addCourse = true" v-if="getAllCourse.length && !onlySystem" />
                 <Icon type="md-add-circle" color="#02B35A" size="17" :title="$t('studentWeb.home.joinClass')" @click="isScale ? false : addCourse = true" v-if="getAllCourse.length && !onlySystem" />
-                <div class="course-type" v-if="getAllCourse.length && $store.state.userInfo.scope === 'student'">
-                    <RadioGroup v-model="courseType" @on-change="searchCourse" size="small" type="button" button-style="solid">
-                        <Radio label="all">{{ $t('evaluation.filter.all') }}</Radio>
-                        <Radio label="school">{{ $t('answerSheet.dp.school') }}</Radio>
-                        <Radio label="private">{{ $t('cusMgt.private') }}</Radio>
-                    </RadioGroup>
-                    <!-- <Space direction="vertical" size="large">
-                        <Space> -->
-                            <Input v-model="searchText" :placeholder="$t('studentWeb.home.title.search')" size="small" style="width: 200px">
-                                <template #suffix>
-                                    <Icon type="ios-search" @click="searchCourse" />
-                                </template>
-                            </Input>
-                        <!-- </Space>
-                    </Space> -->
+                <div class="course-box">
+                    <div class="course-type" v-if="getAllCourse.length && $store.state.userInfo.scope === 'student'">
+                        <RadioGroup v-model="courseType" @on-change="searchCourse" size="small" type="button" button-style="solid">
+                            <Radio label="all">{{ $t('evaluation.filter.all') }}</Radio>
+                            <Radio label="school">{{ $t('answerSheet.dp.school') }}</Radio>
+                            <Radio label="private">{{ $t('cusMgt.private') }}</Radio>
+                        </RadioGroup>
+                        <!-- <Space direction="vertical" size="large">
+                            <Space> -->
+                                <Input v-model="searchText" :placeholder="$t('studentWeb.home.title.search')" size="small" style="width: 200px">
+                                    <template #suffix>
+                                        <Icon type="ios-search" @click="searchCourse" />
+                                    </template>
+                                </Input>
+                            <!-- </Space>
+                        </Space> -->
+                    </div>
+                    <Button style="margin-left: 10px;" size="small" type="success" ghost @click="getReview">{{ $t('studentWeb.home.applyList') }}</Button>
                 </div>
                 </div>
-                <Button style="margin-left: 10px;" size="small" type="success" ghost @click="getReview">{{ $t('studentWeb.home.applyList') }}</Button>
             </div>
             </div>
             <div class="home-join" v-if="allCourseShow.length">
             <div class="home-join" v-if="allCourseShow.length">
                 <vuescroll>
                 <vuescroll>
@@ -951,4 +953,24 @@ export default {
         }
         }
     }
     }
 }
 }
+
+@media screen and (max-width: 520px) {
+    .home-view{
+        .title-one {
+            height: 100px;
+        }
+        .course-box {
+            .course-type {
+                margin-left: 0;
+                .ivu-input-wrapper {
+                    margin: 5px 0;
+                }
+            }
+            .ivu-btn {
+                margin-left: 0 !important;
+            }
+        }
+    }
+}
+
 </style>
 </style>

+ 3 - 3
TEAMModelOS/ClientApp/src/router/routes.js

@@ -1497,9 +1497,9 @@ export const routes = [{
     {
     {
         path: 'activitySet',
         path: 'activitySet',
         name: 'activitySet',
         name: 'activitySet',
-        component: () => import('@/view/signupActivity/manageActivity.vue'),
+        component: () => import('@/view/signupActivity/setActivity.vue'),
         meta: {
         meta: {
-            activeName: 'activityManage',
+            activeName: 'activitySet',
         }
         }
     }
     }
     ]
     ]
@@ -1956,7 +1956,7 @@ export const routes = [{
         {
         {
             path: 'areaActivitySet',
             path: 'areaActivitySet',
             name: 'areaActivitySet',
             name: 'areaActivitySet',
-            component: () => import('@/view/signupActivity/manageActivity.vue'),
+            component: () => import('@/view/signupActivity/setActivity.vue'),
             meta: {
             meta: {
                 activeName: 'areaActivityManage',
                 activeName: 'areaActivityManage',
             }
             }

+ 5 - 1
TEAMModelOS/ClientApp/src/view/joinSchool/JoinSchool.vue

@@ -56,7 +56,11 @@ export default {
             this.isJoin = true
             this.isJoin = true
             this.$Message.success(this.$t('cusMgt.join.joinOk'))
             this.$Message.success(this.$t('cusMgt.join.joinOk'))
           } else {
           } else {
-            this.$Message.error(res.msg)
+            if(res.error === 3){
+              this.$Message.warning(this.$t('home.schoolSuccess'))
+            }else{
+              this.$Message.error(this.$t('cusMgt.join.joinErr'))
+            }
           }
           }
         },
         },
         err => {
         err => {

+ 1 - 1
TEAMModelOS/ClientApp/src/view/login/Index.vue

@@ -549,7 +549,7 @@ export default {
     }
     }
 
 
     //TEAMModelID 社群登入資訊
     //TEAMModelID 社群登入資訊
-    this.userOauth.code = this.$route.query.code
+    this.userOauth.code = this.$route.query.code || this.$route.query.ticket
     this.userOauth.state = this.$route.query.state
     this.userOauth.state = this.$route.query.state
 
 
     // 社群帳號登入
     // 社群帳號登入

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

@@ -150,6 +150,7 @@
     width: 100%;
     width: 100%;
     height: 45px;
     height: 45px;
     padding-left: 15px;
     padding-left: 15px;
+    padding-right: 150px;
     // background: #f9f9f9;
     // background: #f9f9f9;
     border-bottom: 1px solid #e2e2e2;
     border-bottom: 1px solid #e2e2e2;
 }
 }

+ 8 - 2
TEAMModelOS/ClientApp/src/view/mycourse/MyCourse.vue

@@ -113,6 +113,9 @@
 						<span @click="selectTab('score')" :class="tabName == 'score' ? 'course-classroom-label pane active':'course-classroom-label pane'">
 						<span @click="selectTab('score')" :class="tabName == 'score' ? 'course-classroom-label pane active':'course-classroom-label pane'">
 							{{$t('cusMgt.cusTab7')}}
 							{{$t('cusMgt.cusTab7')}}
 						</span>
 						</span>
+						<!-- <span @click="selectTab('classSyllabus')" :class="tabName == 'classSyllabus' ? 'course-classroom-label pane active':'course-classroom-label pane'">
+							{{$t('cusMgt.cusTab13')}}
+						</span> -->
 					</div>
 					</div>
 					<!-- 评测活动 -->
 					<!-- 评测活动 -->
 					<Exam v-if="tabName == 'exam'" v-model="fIds" :gradeParams="gradeParams" :students="students" :classInfo="teaClassList[curClassIndex]" :courseInfo="courseInfo" :teaClassList="teaClassList"> </Exam>
 					<Exam v-if="tabName == 'exam'" v-model="fIds" :gradeParams="gradeParams" :students="students" :classInfo="teaClassList[curClassIndex]" :courseInfo="courseInfo" :teaClassList="teaClassList"> </Exam>
@@ -124,6 +127,7 @@
 					<Notice v-else-if="tabName == 'notice'" :classInfo="teaClassList[curClassIndex]" :classList="teaClassList" :courseInfo="courseInfo"></Notice>
 					<Notice v-else-if="tabName == 'notice'" :classInfo="teaClassList[curClassIndex]" :classList="teaClassList" :courseInfo="courseInfo"></Notice>
 					<Discussion v-else-if="tabName == 'discussion'" :classInfo="teaClassList[curClassIndex]" :classList="teaClassList" :courseInfo="courseInfo"></Discussion>
 					<Discussion v-else-if="tabName == 'discussion'" :classInfo="teaClassList[curClassIndex]" :classList="teaClassList" :courseInfo="courseInfo"></Discussion>
 					<Score v-else-if="tabName == 'score'" :gradeParams="gradeParams" :grouplistId="teaClassList[curClassIndex]" :listType="listType"></Score>
 					<Score v-else-if="tabName == 'score'" :gradeParams="gradeParams" :grouplistId="teaClassList[curClassIndex]" :listType="listType"></Score>
+					<SyllabusIndex v-else-if="tabName == 'classSyllabus'" :gradeParams="gradeParams" :grouplistId="teaClassList[curClassIndex]" :listType="listType"></SyllabusIndex>
 				</div>
 				</div>
 			</Split>
 			</Split>
 		</div>
 		</div>
@@ -343,7 +347,8 @@
 	import Student from "./student/Student.vue";
 	import Student from "./student/Student.vue";
 	import Notice from "./notice/Notice.vue";
 	import Notice from "./notice/Notice.vue";
 	import Discussion from "./discussion/Discussion.vue";
 	import Discussion from "./discussion/Discussion.vue";
-	import Score from "./score/Score.vue"
+	import Score from "./score/Score.vue";
+	import SyllabusIndex from "./syllabus/SyllabusIndex.vue";
 	export default {
 	export default {
 		components: {
 		components: {
 			Exam,
 			Exam,
@@ -354,7 +359,8 @@
 			Student,
 			Student,
 			Notice,
 			Notice,
 			Discussion,
 			Discussion,
-			Score
+			Score,
+			SyllabusIndex
 		},
 		},
 		data() {
 		data() {
 			// 验证只能是字母和数字
 			// 验证只能是字母和数字

+ 5 - 0
TEAMModelOS/ClientApp/src/view/mycourse/exam/Exam.less

@@ -7,6 +7,11 @@
 @borderColor: var(--border-color);
 @borderColor: var(--border-color);
 @second-fontSize: 16px;
 @second-fontSize: 16px;
 
 
+.stu-action-wrap{
+    position: absolute;
+    right: 20px;
+    top: 7px;
+}
 .course-exam-container{
 .course-exam-container{
     width: 100%;
     width: 100%;
     height: ~"calc(100% - 46px)";
     height: ~"calc(100% - 46px)";

+ 24 - 2
TEAMModelOS/ClientApp/src/view/mycourse/exam/Exam.vue

@@ -1,6 +1,28 @@
 <template>
 <template>
     <div class="course-exam-container" id="course-exam-container">
     <div class="course-exam-container" id="course-exam-container">
-        <div class="exam-action-wrap">
+        <div class="stu-action-wrap common-save-btn">
+            <Dropdown style="margin-top:5px;margin-right:8px">
+                <a href="javascript:void(0)">
+                    {{$t('cusMgt.moreFn')}}
+                    <Icon type="ios-arrow-down"></Icon>
+                </a>
+                <DropdownMenu slot="list">
+                    <DropdownItem @click.native="isShowGrade = !isShowGrade">
+                        <span class="action-item" >
+                            <Icon :type="isShowGrade ? 'md-list' : 'md-grid'" />
+                            {{isShowGrade ? $t('cusMgt.cusTab6') : $t('cusMgt.cusTab7')}}
+                        </span>
+                    </DropdownItem>
+                    <DropdownItem @click.native="toCreate">
+                    <span class="action-item" >
+                        <Icon type="md-add" />
+                        {{$t('cusMgt.cusTab8')}}
+                    </span>
+                    </DropdownItem>
+                </DropdownMenu>
+            </Dropdown>
+        </div>
+        <!-- <div class="exam-action-wrap">
             <span class="action-item" @click="isShowGrade = !isShowGrade">
             <span class="action-item" @click="isShowGrade = !isShowGrade">
                 <Icon :type="isShowGrade ? 'md-list' : 'md-grid'" />
                 <Icon :type="isShowGrade ? 'md-list' : 'md-grid'" />
                 {{isShowGrade ? $t('cusMgt.cusTab6') : $t('cusMgt.cusTab7')}}
                 {{isShowGrade ? $t('cusMgt.cusTab6') : $t('cusMgt.cusTab7')}}
@@ -9,7 +31,7 @@
                 <Icon type="md-add" />
                 <Icon type="md-add" />
                 {{$t('cusMgt.cusTab8')}}
                 {{$t('cusMgt.cusTab8')}}
             </span>
             </span>
-        </div>
+        </div> -->
         <Loading v-show="isLoading"></Loading>
         <Loading v-show="isLoading"></Loading>
         <Grade v-show="isShowGrade" :paramsInfo="gradeParams" :student="students" class="exam-grade-view"></Grade>
         <Grade v-show="isShowGrade" :paramsInfo="gradeParams" :student="students" class="exam-grade-view"></Grade>
         <vuescroll>
         <vuescroll>

+ 6 - 0
TEAMModelOS/ClientApp/src/view/mycourse/record/Record.less

@@ -1,3 +1,9 @@
+
+.stu-action-wrap{
+    position: absolute;
+    right: 20px;
+    top: 7px;
+}
 .record-container{
 .record-container{
     width: 100%;
     width: 100%;
     height: ~"calc(100% - 50px)";
     height: ~"calc(100% - 50px)";

+ 22 - 19
TEAMModelOS/ClientApp/src/view/mycourse/record/Record.vue

@@ -14,7 +14,7 @@
         {{$t('cusMgt.autoShare')}}
         {{$t('cusMgt.autoShare')}}
       </span>
       </span>
       <i-switch :loading="sLoading" v-model="isAuto" size="small" @on-change="setAutoPublish" />
       <i-switch :loading="sLoading" v-model="isAuto" size="small" @on-change="setAutoPublish" />
-    </div>
+    </div> -->
     <vuescroll>
     <vuescroll>
       <Alert v-show="rcdParams.scope == 'private'" show-icon type="warning" closable>
       <Alert v-show="rcdParams.scope == 'private'" show-icon type="warning" closable>
         {{$t('cusMgt.recordTips')}}
         {{$t('cusMgt.recordTips')}}
@@ -25,12 +25,21 @@
           <p class="record-name" style="padding-left:10px">
           <p class="record-name" style="padding-left:10px">
             {{item.name}}
             {{item.name}}
             <span class="item-icon-wrap">
             <span class="item-icon-wrap">
-              <Icon type="md-create" class="common-item-icon ed-name" @click.stop="editRecordName(index)" :title="$t('cusMgt.edRdName')" />
-              <Icon type="md-trash" class="common-item-icon delete-item" @click.stop="delRecord(item)" :title="$t('cusMgt.delRcd')" />
-              <Icon v-show="item.isShare" type="ios-share-alt" :size="20" :class="['common-item-icon', 'share-student', 'share-active']" @click.stop="toggleShare(item)" :title="$t('cusMgt.unShare')" />
-              <Icon v-show="!item.isShare" type="ios-share-alt-outline" :size="20" :class="['common-item-icon','share-student',]" @click.stop="toggleShare(item)" :title="$t('cusMgt.shareToStu')" />
-              <Icon v-show="isFavorite(item.id)" type="md-heart" style="right:2px" :class="['common-item-icon', 'heart-active']" @click.stop="toggleFavorite(item)" :title="$t('cusMgt.unfvt')" />
-              <Icon v-show="!isFavorite(item.id)" type="md-heart-outline" style="right:2px" :class="['common-item-icon',]" @click.stop="toggleFavorite(item)" :title="$t('cusMgt.fvt')" />
+              <Icon type="md-create" class="common-item-icon ed-name" @click.stop="editRecordName(index)"
+                :title="$t('cusMgt.edRdName')" />
+              <Icon type="md-trash" class="common-item-icon delete-item" @click.stop="delRecord(item)"
+                :title="$t('cusMgt.delRcd')" />
+              <Icon v-show="item.isShare" type="ios-share-alt" :size="20"
+                :class="['common-item-icon', 'share-student', 'share-active']" @click.stop="toggleShare(item)"
+                :title="$t('cusMgt.unShare')" />
+              <Icon v-show="!item.isShare" type="ios-share-alt-outline" :size="20"
+                :class="['common-item-icon','share-student',]" @click.stop="toggleShare(item)"
+                :title="$t('cusMgt.shareToStu')" />
+              <Icon v-show="isFavorite(item.id)" type="md-heart" style="right:2px"
+                :class="['common-item-icon', 'heart-active']" @click.stop="toggleFavorite(item)"
+                :title="$t('cusMgt.unfvt')" />
+              <Icon v-show="!isFavorite(item.id)" type="md-heart-outline" style="right:2px"
+                :class="['common-item-icon',]" @click.stop="toggleFavorite(item)" :title="$t('cusMgt.fvt')" />
             </span>
             </span>
           </p>
           </p>
           <div style="padding-left:10px;margin-top:10px">
           <div style="padding-left:10px;margin-top:10px">
@@ -130,11 +139,14 @@
           </div>
           </div>
           <p style="margin:10px 0;color:red">* {{ $t('cusMgt.rcd.cover.tip') }}</p>
           <p style="margin:10px 0;color:red">* {{ $t('cusMgt.rcd.cover.tip') }}</p>
           <div v-show="previewCover">
           <div v-show="previewCover">
-            <p style="margin-bottom:10px">{{ $t('cusMgt.rcd.cover.preview') }} <span style="text-decoration:underline;color:gray;cursor: pointer;" @click="previewCover = ''">{{ $t('cusMgt.rcd.cover.undo') }}</span></p>
+            <p style="margin-bottom:10px">{{ $t('cusMgt.rcd.cover.preview') }} <span
+                style="text-decoration:underline;color:gray;cursor: pointer;"
+                @click="previewCover = ''">{{ $t('cusMgt.rcd.cover.undo') }}</span></p>
             <img :src="previewCover" alt="" style="width: 430px;height:242px">
             <img :src="previewCover" alt="" style="width: 430px;height:242px">
           </div>
           </div>
         </div>
         </div>
-        <Button :loading="btnLoading" @click="confirmEditRd" long type="primary" class="confirm-btn">{{ $t('syllabus.confirm') }}</Button>
+        <Button :loading="btnLoading" @click="confirmEditRd" long type="primary"
+          class="confirm-btn">{{ $t('syllabus.confirm') }}</Button>
       </div>
       </div>
     </Modal>
     </Modal>
   </div>
   </div>
@@ -367,7 +379,7 @@ export default {
       }
       }
       this.$api.courseMgmt.FavoriteUpsert(params).then(
       this.$api.courseMgmt.FavoriteUpsert(params).then(
         res => {
         res => {
-          if(res.status) {
+          if (res.status) {
             this.$Message.warning(this.$t('cusMgt.spaceFull'))
             this.$Message.warning(this.$t('cusMgt.spaceFull'))
           } else {
           } else {
             this.$Message.success(this.$t('cusMgt.fvtOk'))
             this.$Message.success(this.$t('cusMgt.fvtOk'))
@@ -540,19 +552,10 @@ export default {
                 promiseArr.push(new Promise(async (r, j) => {
                 promiseArr.push(new Promise(async (r, j) => {
                     let imageCover = ''
                     let imageCover = ''
                     try {
                     try {
-                      // 存在其他老师发布的课堂记录
-                      if(item.tmdid != this.$store.state.userInfo.TEAMModelId && this.rcdParams.scope != 'school') {
-                        let blobInfos = await this.$evTools.getBlobPrivateSasObj(item.tmdid)
-                        let url = `${blobInfos.url}/${blobInfos.name}/records/${item.id}/IES/TimeLine.json${blobInfos.sas}`
-                        let res = JSON.parse(await this.$tools.getFile(url))
-                        let pgids = res.PgIdList || []
-                        imageCover = `${blobInfos.url}/${blobInfos.name}/records/${item.id}/Memo/${pgids[0]}.jpg${blobInfos.sas}`
-                      } else {
                         let url = `${sasInfo.url}/${sasInfo.name}/records/${item.id}/IES/TimeLine.json${sasInfo.sas}`
                         let url = `${sasInfo.url}/${sasInfo.name}/records/${item.id}/IES/TimeLine.json${sasInfo.sas}`
                         let res = JSON.parse(await this.$tools.getFile(url))
                         let res = JSON.parse(await this.$tools.getFile(url))
                         let pgids = res.PgIdList || []
                         let pgids = res.PgIdList || []
                         imageCover = `${sasInfo.url}/${sasInfo.name}/records/${item.id}/Memo/${pgids[0]}.jpg${sasInfo.sas}`
                         imageCover = `${sasInfo.url}/${sasInfo.name}/records/${item.id}/Memo/${pgids[0]}.jpg${sasInfo.sas}`
-                      }
                     } catch (e) {
                     } catch (e) {
                     }
                     }
                     item.poster = imageCover
                     item.poster = imageCover

+ 4 - 4
TEAMModelOS/ClientApp/src/view/mycourse/score/AddProject.vue

@@ -247,9 +247,9 @@ export default {
     },
     },
     ProjectGoback(vule) {
     ProjectGoback(vule) {
       if (vule == "save") {
       if (vule == "save") {
-        if (this.totalNum > 100) {
-          this.$Message.warning(this.$t("scoreCalc.warringTotalRate"));
-        } else {
+        // if (this.totalNum > 100) {
+        //   this.$Message.warning(this.$t("scoreCalc.warringTotalRate"));
+        // } else {
           //#region 更新項目及子項目資料
           //#region 更新項目及子項目資料
           let items = [];
           let items = [];
           let sort = 1;
           let sort = 1;
@@ -289,7 +289,7 @@ export default {
           );
           );
           this.isSave = true;
           this.isSave = true;
           //#endregion
           //#endregion
-        }
+        // }
       } else if (vule == "back") {
       } else if (vule == "back") {
         //直接返回
         //直接返回
         this.$emit("tableInfo", this.tableInfo);
         this.$emit("tableInfo", this.tableInfo);

+ 0 - 4
TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBox.less

@@ -37,10 +37,6 @@
       margin: 1px 5px;
       margin: 1px 5px;
       border: 1px solid #dcdee2;
       border: 1px solid #dcdee2;
     }
     }
-    .txt-box {
-      text-align: left;
-      width: 400px;
-    }
     .txt-box2 {
     .txt-box2 {
       text-align: left;
       text-align: left;
       width: 350px;
       width: 350px;

+ 7 - 1
TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBoxAddTable.vue

@@ -15,7 +15,13 @@
           </RadioGroup>
           </RadioGroup>
           <div class="flex-item">
           <div class="flex-item">
             <Select v-model="chooseID" style="width:200px">
             <Select v-model="chooseID" style="width:200px">
-              <Option v-for="item in lists" :value="item.id" :key="item.id">{{ item.name+"_"+$jsFn.dateFormat(item.createTime) }}</Option>
+              <Option v-for="item in lists" :value="item.id" :key="item.id">
+                {{ item.name}} 
+                <span style="color:#808695;">
+                  <Icon type="md-time" style="margin:0px;" v-if="$jsFn.dateFormat(item.createTime) !== ''"/>
+                  {{$jsFn.dateFormat(item.createTime) }}
+                </span>                
+              </Option>
             </Select>
             </Select>
           </div>          
           </div>          
         </div>        
         </div>        

+ 65 - 58
TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBoxStudentScore.vue

@@ -12,8 +12,8 @@
           <div>
           <div>
             <DataTable :value="classData" showGridlines v-if="class_type == 'lessonrecord'" :scrollable="true"
             <DataTable :value="classData" showGridlines v-if="class_type == 'lessonrecord'" :scrollable="true"
               scrollHeight="400px" editMode="cell" class="editable-cells-table" responsiveLayout="scroll"
               scrollHeight="400px" editMode="cell" class="editable-cells-table" responsiveLayout="scroll"
-              style="min-height: 400px;" :sortField="sortField" :sortOrder="sortOrder" removableSort ref="myLessonTable">
-              <Column field="irs" :header="$t('scoreCalc.IRSnumber')" 
+              style="min-height: 400px;" :sortField="sortField" :sortOrder="sortOrder" removableSort @sort="userSort($event)">
+              <Column field="irs" :header="$t('scoreCalc.IRSnumber')" sortable
                 :styles="{ 'min-width': '80px', 'text-align': 'center', 'display': 'block' }"><!--sortable -->
                 :styles="{ 'min-width': '80px', 'text-align': 'center', 'display': 'block' }"><!--sortable -->
                 <template #body="rowData">
                 <template #body="rowData">
                   <div>
                   <div>
@@ -21,7 +21,7 @@
                   </div>
                   </div>
                 </template>
                 </template>
               </Column>
               </Column>
-              <Column field="name" :header="$t('scoreCalc.name')"
+              <Column field="name" :header="$t('scoreCalc.name')" sortable
                 :styles="{ 'min-width': '120px', 'text-align': 'center', 'display': 'block' }">
                 :styles="{ 'min-width': '120px', 'text-align': 'center', 'display': 'block' }">
                 <template #body="rowData">
                 <template #body="rowData">
                   <div>
                   <div>
@@ -29,7 +29,7 @@
                   </div>
                   </div>
                 </template>
                 </template>
               </Column>
               </Column>
-              <Column field="id" :header="$t('scoreCalc.id')"
+              <Column field="id" :header="$t('scoreCalc.id')" sortable
                 :styles="{ 'min-width': '120px', 'text-align': 'center', 'display': 'block' }">
                 :styles="{ 'min-width': '120px', 'text-align': 'center', 'display': 'block' }">
                 <template #body="rowData">
                 <template #body="rowData">
                   <div>
                   <div>
@@ -44,7 +44,7 @@
                   <div>
                   <div>
                     <!-- <input type="text" :value="attendShow(rowData.data[rowData.column.field],rowData)" @input="falseIsSave($event, rowData.index,'attend')"
                     <!-- <input type="text" :value="attendShow(rowData.data[rowData.column.field],rowData)" @input="falseIsSave($event, rowData.index,'attend')"
                       maxlength="1" class="column-input" style=" width:70px"/> -->
                       maxlength="1" class="column-input" style=" width:70px"/> -->
-                    <Select v-model="rowData.data.attendance" style="width:100px; color: #2d8cf0;"  @on-change="attSelectFun">
+                    <Select v-model="rowData.data.attendance" style="width:100px; color: #2d8cf0;"  @on-change="attSelectFun"  tabindex="-1">
                         <Option v-for="item in cityList" :value="item.value" :key="item.value" >{{ item.label }}</Option>
                         <Option v-for="item in cityList" :value="item.value" :key="item.value" >{{ item.label }}</Option>
                     </Select>
                     </Select>
                   </div>
                   </div>
@@ -56,7 +56,7 @@
                 <template #body="rowData">
                 <template #body="rowData">
                   <div>
                   <div>
                     <input type="text" v-model.number="rowData.data[rowData.column.field]" @input="falseIsSave($event, rowData.data.id,'score')"
                     <input type="text" v-model.number="rowData.data[rowData.column.field]" @input="falseIsSave($event, rowData.data.id,'score')"
-                      maxlength="3" class="column-input" />
+                      maxlength="3" class="column-input" @keydown.tab.stop/>
                   </div>
                   </div>
                 </template>
                 </template>
               </Column>
               </Column>
@@ -66,15 +66,15 @@
                 <template #body="rowData">
                 <template #body="rowData">
                   <div>
                   <div>
                     <input type="text" v-model.number="rowData.data[rowData.column.field]" @input="falseIsSave($event, rowData.data.id,'interact')"
                     <input type="text" v-model.number="rowData.data[rowData.column.field]" @input="falseIsSave($event, rowData.data.id,'interact')"
-                      maxlength="3" class="column-input" />
+                      maxlength="3" class="column-input"  @keydown.tab.stop/>
                   </div>
                   </div>
                 </template>
                 </template>
               </Column>
               </Column>
             </DataTable>
             </DataTable>
             <DataTable :value="classData" showGridlines v-if="class_type == 'activity'" :scrollable="true"
             <DataTable :value="classData" showGridlines v-if="class_type == 'activity'" :scrollable="true"
               scrollHeight="400px" editMode="cell" class="editable-cells-table" responsiveLayout="scroll"
               scrollHeight="400px" editMode="cell" class="editable-cells-table" responsiveLayout="scroll"
-              :sortField="sortField" :sortOrder="sortOrder" removableSort ref="myActivityTable" @sort="userSort($event)">
-              <Column field="irs" :header="$t('scoreCalc.IRSnumber')"  
+              :sortField="sortField" :sortOrder="sortOrder" removableSort @sort="userSort($event)">
+              <Column field="irs" :header="$t('scoreCalc.IRSnumber')"  sortable
                 :styles="{ 'min-width': '90px', 'text-align': 'center', 'display': 'block' }"><!--sortable-->
                 :styles="{ 'min-width': '90px', 'text-align': 'center', 'display': 'block' }"><!--sortable-->
                 <template #body="rowData">
                 <template #body="rowData">
                   <div>
                   <div>
@@ -82,7 +82,7 @@
                   </div>
                   </div>
                 </template>
                 </template>
               </Column>
               </Column>
-              <Column field="name" :header="$t('scoreCalc.name')" 
+              <Column field="name" :header="$t('scoreCalc.name')" sortable
                 :styles="{ 'min-width': '120px', 'text-align': 'center', 'display': 'block' }">
                 :styles="{ 'min-width': '120px', 'text-align': 'center', 'display': 'block' }">
                 <template #body="rowData">
                 <template #body="rowData">
                   <div style="text-align: center;">
                   <div style="text-align: center;">
@@ -90,7 +90,7 @@
                   </div>
                   </div>
                 </template>
                 </template>
               </Column>
               </Column>
-              <Column field="id" :header="$t('scoreCalc.id')" 
+              <Column field="id" :header="$t('scoreCalc.id')" sortable
                 :styles="{ 'min-width': '120px', 'text-align': 'center', 'display': 'block' }">
                 :styles="{ 'min-width': '120px', 'text-align': 'center', 'display': 'block' }">
                 <template #body="rowData">
                 <template #body="rowData">
                   <div>
                   <div>
@@ -102,14 +102,14 @@
                 :styles="{ 'min-width': '120px', 'color': 'rgb(45, 140, 240)', 'text-align': 'center', 'display': 'block' }"
                 :styles="{ 'min-width': '120px', 'color': 'rgb(45, 140, 240)', 'text-align': 'center', 'display': 'block' }"
                 :headerStyle="{ 'color': '#515a6e' }">
                 :headerStyle="{ 'color': '#515a6e' }">
                 <template #body="rowData">
                 <template #body="rowData">
-                  <div style="width: 100%">
+                  <div style="width: 100%" >
                     <!-- <input type="text" v-model.number="rowData.data[rowData.column.field]" @input="falseIsSave()"
                     <!-- <input type="text" v-model.number="rowData.data[rowData.column.field]" @input="falseIsSave()"
                       maxlength="3" class="column-input" v-show="isNotrated(rowData.data[rowData.column.field])" />
                       maxlength="3" class="column-input" v-show="isNotrated(rowData.data[rowData.column.field])" />
                       <input type="text" style="width: 50px;" value="未評分" @input="falseIsSave()"
                       <input type="text" style="width: 50px;" value="未評分" @input="falseIsSave()"
                       maxlength="6" class="column-input" v-show="!isNotrated(rowData.data[rowData.column.field])"/> -->
                       maxlength="6" class="column-input" v-show="!isNotrated(rowData.data[rowData.column.field])"/> -->
 
 
                     <input type="text" style="width: 50px;" :value="checkNotrated(rowData.data[rowData.column.field])" @input="falseIsSave($event, rowData.data.id,'score')"
                     <input type="text" style="width: 50px;" :value="checkNotrated(rowData.data[rowData.column.field])" @input="falseIsSave($event, rowData.data.id,'score')"
-                      maxlength="3" class="column-input" />
+                      maxlength="3" class="column-input" @keydown.tab.stop/>
                   </div>
                   </div>
                 </template>
                 </template>
               </Column>
               </Column>
@@ -124,7 +124,7 @@
           <div class="div-studentScore">
           <div class="div-studentScore">
             <textarea v-if="class_type == 'lessonrecord'" v-model="textareaValue_system" type="text" rows="4" cols="30"
             <textarea v-if="class_type == 'lessonrecord'" v-model="textareaValue_system" type="text" rows="4" cols="30"
               datatype="*" class="enter-box txt-box" :placeholder="custom_score_data" required
               datatype="*" class="enter-box txt-box" :placeholder="custom_score_data" required
-              @input="isTextareaInput = true, TextareaInput_system"></textarea>
+              @input="isTextareaInput = true, TextareaInput_system" @keydown.tab.prevent="insertTab"></textarea>
 
 
             <textarea v-if="class_type == 'activity'" v-model="textareaValue_system" type="text" rows="4" cols="30"
             <textarea v-if="class_type == 'activity'" v-model="textareaValue_system" type="text" rows="4" cols="30"
               datatype="*" class="enter-box txt-box" :placeholder="checkNotratedTextarea(custom_score_data2)" required
               datatype="*" class="enter-box txt-box" :placeholder="checkNotratedTextarea(custom_score_data2)" required
@@ -204,11 +204,15 @@ export default {
     TextareaInput_system() {
     TextareaInput_system() {
       this.isSave = false;
       this.isSave = false;
       if (this.isTextareaInput && this.textareaValue_system.trim() !== '') {
       if (this.isTextareaInput && this.textareaValue_system.trim() !== '') {
-        const data = this.textareaValue_system.split('\n').map((line) => line.split('\t'));
+        //const data = this.textareaValue_system.split('\n').map((line) => line.split('\t'));
+        const data = this.textareaValue_system.split('\n').map((line) => {
+          const values = line.split('\t');
+          // 使用 map 方法遍历每个值,如果为 undefined 或 null,则替换为 0
+          return values.map((value) => (value === undefined || value === null || value.trim() === '' ? '0' : value));
+        });
         const lastLine = data[data.length - 1];
         const lastLine = data[data.length - 1];
         const isLastLineEmpty = lastLine.length === 1 && lastLine[0].trim() === '';
         const isLastLineEmpty = lastLine.length === 1 && lastLine[0].trim() === '';
-
-        let classDataTemp =  this.sortTable();//回傳根據使用者排列而排列的array資料        
+        let classDataTemp =  this.sortTable();//回傳根據使用者排列而排列的array資料   
         for (let i = 0; i < data.length - 1; i++) { // 迭代到倒數第二行
         for (let i = 0; i < data.length - 1; i++) { // 迭代到倒數第二行
           if (classDataTemp[i]) {
           if (classDataTemp[i]) {
             const [attendance, score, interactiveScore] = data[i];
             const [attendance, score, interactiveScore] = data[i];
@@ -228,14 +232,14 @@ export default {
           let irsToMatch = this.classData[k].irs;
           let irsToMatch = this.classData[k].irs;
           const matchingItem = classDataTemp.find(item => item.irs === irsToMatch);
           const matchingItem = classDataTemp.find(item => item.irs === irsToMatch);
           if (matchingItem) {// 如果找到匹配,將 score 值給 classData 中對應屬性
           if (matchingItem) {// 如果找到匹配,將 score 值給 classData 中對應屬性
-          this.classData[k].attendance = matchingItem.attendance;
-              this.classData[k].score = matchingItem.score;
-              this.classData[k].interactiveScore = matchingItem.interactiveScore;
+            this.classData[k].attendance = matchingItem.attendance;
+            this.classData[k].score = matchingItem.score;
+            this.classData[k].interactiveScore = matchingItem.interactiveScore;
           }
           }
         }
         }
         this.isTextareaInput = false;
         this.isTextareaInput = false;
       }
       }
-    },    
+    }, 
     TextareaInput_custom() {
     TextareaInput_custom() {
       this.isSave = false;
       this.isSave = false;
       if (this.isTextareaInput && this.textareaValue_system.trim() !== '') {
       if (this.isTextareaInput && this.textareaValue_system.trim() !== '') {
@@ -277,52 +281,55 @@ export default {
   },
   },
   mounted() {    
   mounted() {    
   },
   },
-  methods: {          
+  methods: {    
+    insertTab(event) {// 捕獲 Tab 鍵事件並插入 \t 字符
+      if (event.key === "Tab") {
+        event.preventDefault(); // 阻止默認的 Tab 鍵行為
+        const textarea = event.target;
+        const start = textarea.selectionStart;
+        const end = textarea.selectionEnd;
+
+        // 在字串位置插入 \t
+        this.textareaValue_system =
+          this.textareaValue_system.substring(0, start) +
+          "\t" +
+          this.textareaValue_system.substring(end);
+
+        // 調整鼠標位置
+        textarea.selectionStart = textarea.selectionEnd = start + 1;
+      }
+    }, 
     userSort(event) {      
     userSort(event) {      
-      //嘗試去抓排序,但還不知道event哪個抓得到升冪降冪,以及sortField的值
       this.sortField = event.sortField;
       this.sortField = event.sortField;
       this.sortOrder = event.sortOrder;
       this.sortOrder = event.sortOrder;
-      console.log("this.sortField="+this.sortField);
-      console.log("this.sortOrder="+this.sortOrder);
-      console.log(`用户选择了按照列 ${event.sortField} 进行排序,方向是 ${event.sortOrder === 1 ? '升序' : '降序'}`);
+      // console.log("this.sortField="+this.sortField);
+      // console.log("this.sortOrder="+this.sortOrder);
+      // console.log(`用戶選擇了按照列 ${event.sortField} 進行排序,方向是 ${event.sortOrder === 1 ? '升序' : '降序'}`);      
       this.sortTable();//進行畫面渲染與排序。
       this.sortTable();//進行畫面渲染與排序。
     },
     },
-    sortTable(){//回傳根據使用者排列而排列的array資料
-      let classDataTemp =  [...this.classData];
-      //以下僅是根據sortField的值進行升冪排序,目前寫死sortField=irs
-      //因為尚找不到使用者根據什麼排序。
-      classDataTemp.sort((a, b) => {
-       return this.sortOrder === 1 ? a[this.sortField] - b[this.sortField] : b[this.sortField] - a[this.sortField];
+    sortTable(){//回傳根據使用者排列而排列的array資料      
+      this.classData.forEach(element => {//判別classData的attendance是否是undifind如果是就轉成0。
+        let value =  element.attendance;
+        if(value === undefined || value === null ) element.attendance = 0;
       });
       });
-      /*
-      if(this.sortOrder===1){//判斷升序
-        classDataTemp.sort((a, b) => {
-          if (typeof a[this.sortField] === 'number') {
-            // 如果字段是数字类型,按数字大小排序
-            console.log("typeof = number");
-            console.log("a[this.sortField] - b[this.sortField] ="+a[this.sortField] - b[this.sortField]);
-            return a[this.sortField] - b[this.sortField];
-          } else {
-            // 否则,按照字符串排序
-            console.log("typeof = else");
-            console.log("a[this.sortField].localeCompare(b[this.sortField]) ="+ a[this.sortField].localeCompare(b[this.sortField]));
-            return a[this.sortField].localeCompare(b[this.sortField]);
-          }
-        });
-      }else if(this.sortOrder===-1){//判斷降序
-        classDataTemp.sort((a, b) => {
-          if (typeof a[this.sortField] === 'string') {
-            return b[this.sortField].localeCompare(a[this.sortField]);
-          } else {
-            return b[this.sortField] - a[this.sortField];
-          }
-        });
-      }*/
-      classDataTemp.forEach(element => {
-        //console.log("id="+element.id+"/score="+element.score);
+      let classDataTemp =  [...this.classData];
+      classDataTemp.sort((a, b) => {                
+        if(this.sortOrder===null) return;//如果不排序則不繼續往下執行。        
+        // 检查是否是纯数字        
+        const isNumeric = /^\d+$/.test(a[this.sortField]) && /^\d+$/.test(b[this.sortField]);
+
+        if (isNumeric) {// 如果两个都是数字,按数字大小排序
+          return this.sortOrder === 1 ? a[this.sortField] - b[this.sortField] : b[this.sortField] - a[this.sortField];
+        } else {
+          return this.sortOrder === 1 ? a[this.sortField].localeCompare(b[this.sortField]) : b[this.sortField].localeCompare(a[this.sortField]);
+        }
       });
       });
+      
       this.custom_score_data = classDataTemp.map(item => `${item.attendance}\t${item.score}\t${item.interactiveScore}`).join('\n');
       this.custom_score_data = classDataTemp.map(item => `${item.attendance}\t${item.score}\t${item.interactiveScore}`).join('\n');
       this.custom_score_data2 = classDataTemp.map(item => `${item.score}`).join('\n');
       this.custom_score_data2 = classDataTemp.map(item => `${item.score}`).join('\n');
+      //不採用下面的,因為在使用者輸入雙位數時,因為及時連動,反而會出錯
+      // if(this.class_type==='lessonrecord') this.textareaValue_system = this.custom_score_data;
+      // else if(this.class_type==='activity') this.textareaValue_system = this.custom_score_data2;
       return  classDataTemp;
       return  classDataTemp;
     }, 
     }, 
     attSelectFun(){
     attSelectFun(){

+ 86 - 70
TEAMModelOS/ClientApp/src/view/mycourse/score/ScoreBody.vue

@@ -4,7 +4,8 @@
     <div class="body-content">      
     <div class="body-content">      
       <div class="foot">
       <div class="foot">
         <Button @click="delNewScoreFile">{{ $t('scoreCalc.delete') }}</Button>
         <Button @click="delNewScoreFile">{{ $t('scoreCalc.delete') }}</Button>
-        <div v-if="lists.length !== 0" class="creat-txt">{{ $t('scoreCalc.creatDate') }}:{{$jsFn.secondTimeFormat(this.tableInfo.creatTime)}}</div>
+        <div v-if="lists.length !== 0 && this.tableInfo.creatTime===0" class="creat-txt">{{ $t('scoreCalc.creatDate') }}:--</div>
+        <div v-if="lists.length !== 0 && this.tableInfo.creatTime!==0" class="creat-txt">{{ $t('scoreCalc.creatDate') }}:{{$jsFn.secondTimeFormat(this.tableInfo.creatTime)}}</div>
         <div class="button-group">
         <div class="button-group">
           <div v-if="isSave && lists.length !== 0" class="save-info-ok">
           <div v-if="isSave && lists.length !== 0" class="save-info-ok">
             <div>
             <div>
@@ -34,7 +35,10 @@
           v-bind:key="index">
           v-bind:key="index">
           <Card :class="['ivu-card', { active: list.click }]">
           <Card :class="['ivu-card', { active: list.click }]">
             <p><b>{{ list.name }}</b></p>
             <p><b>{{ list.name }}</b></p>
-            <p>{{$jsFn.dateFormat(list.createTime)}}</p>
+            <p style="color:#515a6e;">
+              <Icon type="md-time" style="margin:0px;" v-if="$jsFn.dateFormat(list.createTime) !== ''"/>
+              {{$jsFn.dateFormat(list.createTime)}}
+            </p>
           </Card>
           </Card>
         </div>
         </div>
       </div>      
       </div>      
@@ -99,19 +103,18 @@
                       </div>
                       </div>
                     </template>
                     </template>
                   </Column>
                   </Column>
-                  <Column field="homework" header="" :styles="{ ...commonStyle, width: '90px' }">
+                  <Column field="evaluate" header="" :styles="{ ...commonStyle, width: '90px' }">
                     <template #header>
                     <template #header>
                       <div class="div-center">
                       <div class="div-center">
                         <div>
                         <div>
-                          <div @click="changePageTo(Proportion.HomeWorkActRate.id)"
+                          <div @click="changePageTo(Proportion.ExamRate.id)"
                             style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                             style=" align-items: center; textDecoration: underline ; cursor: pointer;">
-                            {{ $t('scoreCalc.th_homework') }}
+                            {{ $t('scoreCalc.th_exam') }}
                           </div>
                           </div>
                           <div style="display: flex; align-items: center;">
                           <div style="display: flex; align-items: center;">
-                            ( <input type="text" v-model="Proportion.HomeWorkActRate.score"
-                              @input="onRateChange('homework')"
+                            ( <input type="text" v-model="Proportion.ExamRate.score" @input="onRateChange('evaluate')"
                               style="width: 20px; height: 20px; box-sizing: border-box;"
                               style="width: 20px; height: 20px; box-sizing: border-box;"
-                              :style="{ color: Proportion.HomeWorkActRate.color, margin: '0px 5px', border: 'none', background: 'none' }"
+                              :style="{ color: Proportion.ExamRate.color, margin: '0px 5px', border: 'none', background: 'none' }"
                               maxlength="2">
                               maxlength="2">
                             %)
                             %)
                           </div>
                           </div>
@@ -122,27 +125,28 @@
                       <div class="div-center" style="  flex-direction: column;">
                       <div class="div-center" style="  flex-direction: column;">
                         <div class="div-centerY">
                         <div class="div-centerY">
                           <div class="text-size20">
                           <div class="text-size20">
-                            {{ rowData.data.homework.score+rowData.data.homework.add }}
+                            {{ rowData.data.evaluate.score+rowData.data.evaluate.add }}
                           </div>
                           </div>
                         </div>
                         </div>
                         <div>
                         <div>
-                          ({{ calculateClassPercent(rowData.data, 'homework') }})
+                          ({{ calculateClassPercent(rowData.data, 'evaluate') }})
                         </div>
                         </div>
                       </div>
                       </div>
                     </template>
                     </template>
                   </Column>
                   </Column>
-                  <Column field="evaluate" header="" :styles="{ ...commonStyle, width: '90px' }">
+                  <Column field="homework" header="" :styles="{ ...commonStyle, width: '90px' }">
                     <template #header>
                     <template #header>
                       <div class="div-center">
                       <div class="div-center">
                         <div>
                         <div>
-                          <div @click="changePageTo(Proportion.ExamRate.id)"
+                          <div @click="changePageTo(Proportion.HomeWorkActRate.id)"
                             style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                             style=" align-items: center; textDecoration: underline ; cursor: pointer;">
-                            {{ $t('scoreCalc.th_exam') }}
+                            {{ $t('scoreCalc.th_homework') }}
                           </div>
                           </div>
                           <div style="display: flex; align-items: center;">
                           <div style="display: flex; align-items: center;">
-                            ( <input type="text" v-model="Proportion.ExamRate.score" @input="onRateChange('evaluate')"
+                            ( <input type="text" v-model="Proportion.HomeWorkActRate.score"
+                              @input="onRateChange('homework')"
                               style="width: 20px; height: 20px; box-sizing: border-box;"
                               style="width: 20px; height: 20px; box-sizing: border-box;"
-                              :style="{ color: Proportion.ExamRate.color, margin: '0px 5px', border: 'none', background: 'none' }"
+                              :style="{ color: Proportion.HomeWorkActRate.color, margin: '0px 5px', border: 'none', background: 'none' }"
                               maxlength="2">
                               maxlength="2">
                             %)
                             %)
                           </div>
                           </div>
@@ -153,15 +157,15 @@
                       <div class="div-center" style="  flex-direction: column;">
                       <div class="div-center" style="  flex-direction: column;">
                         <div class="div-centerY">
                         <div class="div-centerY">
                           <div class="text-size20">
                           <div class="text-size20">
-                            {{ rowData.data.evaluate.score+rowData.data.evaluate.add }}
+                            {{ rowData.data.homework.score+rowData.data.homework.add }}
                           </div>
                           </div>
                         </div>
                         </div>
                         <div>
                         <div>
-                          ({{ calculateClassPercent(rowData.data, 'evaluate') }})
+                          ({{ calculateClassPercent(rowData.data, 'homework') }})
                         </div>
                         </div>
                       </div>
                       </div>
                     </template>
                     </template>
-                  </Column>
+                  </Column>                  
                   <Column v-for="count in table_count" :key="count" field="custom" header=""
                   <Column v-for="count in table_count" :key="count" field="custom" header=""
                     :styles="{ ...commonStyle, width: '100px' }">
                     :styles="{ ...commonStyle, width: '100px' }">
                     <template #header>
                     <template #header>
@@ -277,7 +281,7 @@
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                                 {{ $t('scoreCalc.class') }}
                                 {{ $t('scoreCalc.class') }}
                               </div>
                               </div>
-                              <div style="display: flex; align-items: center;">
+                              <div>
                                 ( <input type="text" v-model="Proportion.ScoreCalcActRate.score"
                                 ( <input type="text" v-model="Proportion.ScoreCalcActRate.score"
                                   @input="onRateChange('class')"
                                   @input="onRateChange('class')"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
@@ -289,19 +293,19 @@
                           </div>
                           </div>
                         </template>
                         </template>
                       </Column>
                       </Column>
-                      <Column header="" :rowspan="2" :styles="{ ...sticky , ...tableBorder, top:'0px',}"><!--作業-->
+                      <Column header="" :rowspan="2" :styles="{ ...sticky , ...tableBorder, top:'0px',}"><!--評量-->
                         <template #header>
                         <template #header>
                           <div class="div-center" style="width: 80px;">
                           <div class="div-center" style="width: 80px;">
                             <div>
                             <div>
-                              <div @click="changePageTo(Proportion.HomeWorkActRate.id)"
+                              <div @click="changePageTo(Proportion.ExamRate.id)"
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
-                                {{ $t('scoreCalc.th_homework') }}
+                                {{ $t('scoreCalc.th_exam') }}
                               </div>
                               </div>
-                              <div style="display: flex; align-items: center;">
-                                ( <input type="text" v-model="Proportion.HomeWorkActRate.score"
-                                  @input="onRateChange('homework')"
+                              <div>
+                                ( <input type="text" v-model="Proportion.ExamRate.score"
+                                  @input="onRateChange('evaluate')"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
-                                  :style="{ color: Proportion.HomeWorkActRate.color, margin: '0px 5px', border: 'none', background: 'none' }"
+                                  :style="{ color: Proportion.ExamRate.color, margin: '0px 5px', border: 'none', background: 'none' }"
                                   maxlength="2">
                                   maxlength="2">
                                 %)
                                 %)
                               </div>
                               </div>
@@ -309,19 +313,19 @@
                           </div>
                           </div>
                         </template>
                         </template>
                       </Column>
                       </Column>
-                      <Column header="" :rowspan="2" :styles="{ ...sticky , ...tableBorder, top:'0px',}"><!--評量-->
+                      <Column header="" :rowspan="2" :styles="{ ...sticky , ...tableBorder, top:'0px',}"><!--作業-->
                         <template #header>
                         <template #header>
                           <div class="div-center" style="width: 80px;">
                           <div class="div-center" style="width: 80px;">
                             <div>
                             <div>
-                              <div @click="changePageTo(Proportion.ExamRate.id)"
+                              <div @click="changePageTo(Proportion.HomeWorkActRate.id)"
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
-                                {{ $t('scoreCalc.th_exam') }}
+                                {{ $t('scoreCalc.th_homework') }}
                               </div>
                               </div>
-                              <div style="display: flex; align-items: center;">
-                                ( <input type="text" v-model="Proportion.ExamRate.score"
-                                  @input="onRateChange('evaluate')"
+                              <div>
+                                ( <input type="text" v-model="Proportion.HomeWorkActRate.score"
+                                  @input="onRateChange('homework')"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
-                                  :style="{ color: Proportion.ExamRate.color, margin: '0px 5px', border: 'none', background: 'none' }"
+                                  :style="{ color: Proportion.HomeWorkActRate.color, margin: '0px 5px', border: 'none', background: 'none' }"
                                   maxlength="2">
                                   maxlength="2">
                                 %)
                                 %)
                               </div>
                               </div>
@@ -338,7 +342,7 @@
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                                 {{ Proportion['custom' + (count)].name }}
                                 {{ Proportion['custom' + (count)].name }}
                               </div>
                               </div>
-                              <div style="display: flex; align-items: center;">
+                              <div>
                                 ( <input type="text" v-model="Proportion['custom' + (count)].score"
                                 ( <input type="text" v-model="Proportion['custom' + (count)].score"
                                   @input="onRateChange('custom' + (count))"
                                   @input="onRateChange('custom' + (count))"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
@@ -360,8 +364,7 @@
                       </Column>
                       </Column>
                       <Column header="" :rowspan="2" :styles="tableNoneBackground" />
                       <Column header="" :rowspan="2" :styles="tableNoneBackground" />
                       <Column header="" :rowspan="2" field="total" sortable 
                       <Column header="" :rowspan="2" field="total" sortable 
-                      :styles="{ ...sticky , top:'0px',}"              
-                      ><!--總評分-->
+                        :styles="{ ...sticky , top:'0px',}"><!--總評分-->
                         <template #header>
                         <template #header>
                           <div class="div-center" style="width: 80px;">
                           <div class="div-center" style="width: 80px;">
                             {{ $t('scoreCalc.totalScore') }}
                             {{ $t('scoreCalc.totalScore') }}
@@ -386,7 +389,7 @@
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                                 {{ $t('scoreCalc.attend') }}
                                 {{ $t('scoreCalc.attend') }}
                               </div>
                               </div>
-                              <div style="display: flex; align-items: center;">
+                              <div>
                                 ( <input type="text" v-model="Proportion.ScoreCalcAct.attendRate.score"
                                 ( <input type="text" v-model="Proportion.ScoreCalcAct.attendRate.score"
                                   @input="onRateChange('attend')"
                                   @input="onRateChange('attend')"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
@@ -406,7 +409,7 @@
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                                 {{ $t('scoreCalc.point') }}
                                 {{ $t('scoreCalc.point') }}
                               </div>
                               </div>
-                              <div style="display: flex; align-items: center;">
+                              <div>
                                 ( <input type="text" v-model="Proportion.ScoreCalcAct.pointRate.score"
                                 ( <input type="text" v-model="Proportion.ScoreCalcAct.pointRate.score"
                                   @input="onRateChange('point')"
                                   @input="onRateChange('point')"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
@@ -427,7 +430,7 @@
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                                 style=" align-items: center; textDecoration: underline ; cursor: pointer;">
                                 {{ $t('scoreCalc.interactiveScore') }}
                                 {{ $t('scoreCalc.interactiveScore') }}
                               </div>
                               </div>
-                              <div style="display: flex; align-items: center;">
+                              <div>
                                 ( <input type="text" v-model="Proportion.ScoreCalcAct.interactRate.score"
                                 ( <input type="text" v-model="Proportion.ScoreCalcAct.interactRate.score"
                                   @input="onRateChange('interact')"
                                   @input="onRateChange('interact')"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
                                   style="width: 20px; height: 20px; box-sizing: border-box;"
@@ -535,36 +538,36 @@
                       </div>
                       </div>
                     </template>
                     </template>
                   </Column>
                   </Column>
-                  <Column field="homework" header="作業" :styles="{ ...tableBorder }">
+                  <Column field="evaluate" header="評量" :styles="{ ...tableBorder }">
                     <template #body="rowData">
                     <template #body="rowData">
                       <div class="div-center" style="  flex-direction: column;">
                       <div class="div-center" style="  flex-direction: column;">
-                        <div class="div-centerY" >
-                          <div  class="text-size20">
-                            {{ rowData.data.homework.score }}
+                        <div class="div-centerY">
+                          <div class="text-size20">
+                            {{ rowData.data.evaluate.score }}
                           </div>
                           </div>
-                          <input type="text" :value="inputNumShow(rowData.data.homework.add)"
-                            :style="inputColorShow(rowData.data.homework.add)" maxlength="2"
-                            @change="addOnChange($event, rowData.data.id, 'homework')" />                          
+                          <input type="text" :value="inputNumShow(rowData.data.evaluate.add)"
+                            :style="inputColorShow(rowData.data.evaluate.add)" maxlength="2"
+                            @change="addOnChange($event, rowData.data.id, 'evaluate')" />
                         </div>
                         </div>
                         <div>
                         <div>
-                          ({{ calculateClassPercent(rowData.data, 'homework') }})
+                          ({{ calculateClassPercent(rowData.data, 'evaluate') }})
                         </div>
                         </div>
                       </div>
                       </div>
                     </template>
                     </template>
                   </Column>
                   </Column>
-                  <Column field="evaluate" header="評量" :styles="{ ...tableBorder }">
+                  <Column field="homework" header="作業" :styles="{ ...tableBorder }">
                     <template #body="rowData">
                     <template #body="rowData">
                       <div class="div-center" style="  flex-direction: column;">
                       <div class="div-center" style="  flex-direction: column;">
-                        <div class="div-centerY">
-                          <div class="text-size20">
-                            {{ rowData.data.evaluate.score }}
+                        <div class="div-centerY" >
+                          <div  class="text-size20">
+                            {{ rowData.data.homework.score }}
                           </div>
                           </div>
-                          <input type="text" :value="inputNumShow(rowData.data.evaluate.add)"
-                            :style="inputColorShow(rowData.data.evaluate.add)" maxlength="2"
-                            @change="addOnChange($event, rowData.data.id, 'evaluate')" />
+                          <input type="text" :value="inputNumShow(rowData.data.homework.add)"
+                            :style="inputColorShow(rowData.data.homework.add)" maxlength="2"
+                            @change="addOnChange($event, rowData.data.id, 'homework')" />                          
                         </div>
                         </div>
                         <div>
                         <div>
-                          ({{ calculateClassPercent(rowData.data, 'evaluate') }})
+                          ({{ calculateClassPercent(rowData.data, 'homework') }})
                         </div>
                         </div>
                       </div>
                       </div>
                     </template>
                     </template>
@@ -612,7 +615,8 @@
                       <div class="div-center" style="  flex-direction: column;">
                       <div class="div-center" style="  flex-direction: column;">
                         <div class="div-centerY">
                         <div class="div-centerY">
                           <div class="text-size20">
                           <div class="text-size20">
-                            {{ calculatePR(rowData.index,rowData.data) }}
+                            {{ calculatePR(rowData.data) }}
+                            <!-- {{ Number(rowData.data.PR) }} -->
                           </div>
                           </div>
                         </div>
                         </div>
                       </div>
                       </div>
@@ -809,12 +813,12 @@ export default {
         //缺席absent 病假SL 事假PL 公假OL
         //缺席absent 病假SL 事假PL 公假OL
         { title: this.$t('scoreCalc.absence2'), key: 'absent' }, { title: this.$t('scoreCalc.sickLeave2'), key: 'SL' }, { title: this.$t('scoreCalc.personalLeave2'), key: 'PL' }, { title: this.$t('scoreCalc.publicLeave2'), key: 'OL' },
         { title: this.$t('scoreCalc.absence2'), key: 'absent' }, { title: this.$t('scoreCalc.sickLeave2'), key: 'SL' }, { title: this.$t('scoreCalc.personalLeave2'), key: 'PL' }, { title: this.$t('scoreCalc.publicLeave2'), key: 'OL' },
         { title: this.$t('scoreCalc.attend'), key: 'attend' }, { title: this.$t('scoreCalc.point'), key: 'point' }, { title: this.$t('scoreCalc.interactiveScore'), key: 'interact' },
         { title: this.$t('scoreCalc.attend'), key: 'attend' }, { title: this.$t('scoreCalc.point'), key: 'point' }, { title: this.$t('scoreCalc.interactiveScore'), key: 'interact' },
-        { title: this.$t('scoreCalc.class'), key: 'class' }, { title: this.$t('scoreCalc.th_homework'), key: 'homework' }, { title: this.$t('scoreCalc.th_exam'), key: 'evaluate' },
+        { title: this.$t('scoreCalc.class'), key: 'class' },  { title: this.$t('scoreCalc.th_exam'), key: 'evaluate' }, { title: this.$t('scoreCalc.th_homework'), key: 'homework' },
         { title: this.$t('scoreCalc.totalScore'), key: 'total' }, { title: this.$t('scoreCalc.PRScore'), key: 'PR' }
         { title: this.$t('scoreCalc.totalScore'), key: 'total' }, { title: this.$t('scoreCalc.PRScore'), key: 'PR' }
       ],
       ],
       table_columns_Simple_print: [//打算輸出的表單格式(簡單)
       table_columns_Simple_print: [//打算輸出的表單格式(簡單)
         { title: this.$t('scoreCalc.IRSnumber'), key: 'irs' },{ title: this.$t('scoreCalc.name'), key: 'name' }, { title: this.$t('scoreCalc.id'), key: 'id' },
         { title: this.$t('scoreCalc.IRSnumber'), key: 'irs' },{ title: this.$t('scoreCalc.name'), key: 'name' }, { title: this.$t('scoreCalc.id'), key: 'id' },
-        { title: this.$t('scoreCalc.class'), key: 'class' }, { title: this.$t('scoreCalc.th_homework'), key: 'homework' }, { title: this.$t('scoreCalc.th_exam'), key: 'evaluate' },
+        { title: this.$t('scoreCalc.class'), key: 'class' },  { title: this.$t('scoreCalc.th_exam'), key: 'evaluate' }, { title: this.$t('scoreCalc.th_homework'), key: 'homework' },
         { title: this.$t('scoreCalc.totalScore'), key: 'total' }
         { title: this.$t('scoreCalc.totalScore'), key: 'total' }
       ],
       ],
     };
     };
@@ -890,9 +894,10 @@ export default {
         lazyLoading.value = false;
         lazyLoading.value = false;
       }, Math.random() * 1000 + 250);
       }, Math.random() * 1000 + 250);
     },
     },
-    calculatePR(index,rowData) {//PR值計算
+    calculatePR(rowData) {//PR值計算
+      //console.log("calculatePR in/rowData.total="+rowData.total);
       const N = this.table_class_Data_print.length; // 團體總人數
       const N = this.table_class_Data_print.length; // 團體總人數
-      const studentScore = rowData.total; // 學生的總分      
+      const studentScore = this.table_class_Data_print.find(item => item.id === rowData.id).total; // 學生的總分      
       const sortedScores = this.table_class_Data_print.map(item => item.total).sort((a, b) => b - a);
       const sortedScores = this.table_class_Data_print.map(item => item.total).sort((a, b) => b - a);
       const studentRank = sortedScores.indexOf(studentScore) + 1;// 學生的排名
       const studentRank = sortedScores.indexOf(studentScore) + 1;// 學生的排名
       // 使用公式計算 PR 值,PR=[(N-R)/N]×100,其中N代表團體總人數,R是某個人的分數在團體中的排名。      
       // 使用公式計算 PR 值,PR=[(N-R)/N]×100,其中N代表團體總人數,R是某個人的分數在團體中的排名。      
@@ -1011,7 +1016,7 @@ export default {
       }
       }
       //PR動一個會所有人成績都有變動,因此要全部變更。 
       //PR動一個會所有人成績都有變動,因此要全部變更。 
       for(let j = 0;j< this.table_class_Data.length ; j++){        
       for(let j = 0;j< this.table_class_Data.length ; j++){        
-        this.table_class_Data[j].PR = this.calculatePR(j,this.table_class_Data[j]);
+        this.table_class_Data[j].PR = this.calculatePR(this.table_class_Data[j]);
         // console.log("this.table_class_Data[j].total="+this.table_class_Data[j].total);
         // console.log("this.table_class_Data[j].total="+this.table_class_Data[j].total);
         // console.log("calculatePR()="+this.calculatePR(j,this.table_class_Data[j]));
         // console.log("calculatePR()="+this.calculatePR(j,this.table_class_Data[j]));
         // console.log("this.table_class_Data[j].PR="+this.table_class_Data[j].PR);
         // console.log("this.table_class_Data[j].PR="+this.table_class_Data[j].PR);
@@ -1234,13 +1239,7 @@ export default {
     getAPI_ScoreCalc_all(score_id) {//讀取成績API表單all成績資料
     getAPI_ScoreCalc_all(score_id) {//讀取成績API表單all成績資料
       this.isLoading = true;
       this.isLoading = true;
       if (score_id) this.scoreCalcId = score_id;
       if (score_id) this.scoreCalcId = score_id;
-      console.log("score_id=" + score_id);//重要的console,成績表的ID
-      console.log({ 
-        "id": score_id,
-        "grouplistId": this.classInfo.grouplistId,
-        "classId": this.classInfo.classId,
-        "scope": this.listType,
-        });
+      console.log("score_id=" + score_id);//重要的console,成績表的ID      
       console.log("-------------------");
       console.log("-------------------");
       this.$api.learnActivity.getScoreCalcAll({ 
       this.$api.learnActivity.getScoreCalcAll({ 
         "id": score_id,
         "id": score_id,
@@ -1430,7 +1429,7 @@ export default {
             }
             }
             //需要等total算完才能繼續算pr,否則會有錯誤
             //需要等total算完才能繼續算pr,否則會有錯誤
             for(let i =0 ; i<this.table_class_Data.length ; i++){
             for(let i =0 ; i<this.table_class_Data.length ; i++){
-              this.table_class_Data[i].PR = this.calculatePR(i,this.table_class_Data[i]);
+              this.table_class_Data[i].PR = this.calculatePR(this.table_class_Data[i]);
               // console.log("i="+i);
               // console.log("i="+i);
               // console.log("this.table_class_Data[i].total="+this.table_class_Data[i].total);
               // console.log("this.table_class_Data[i].total="+this.table_class_Data[i].total);
               // console.log("this.table_class_Data[i].PR="+this.table_class_Data[i].PR);
               // console.log("this.table_class_Data[i].PR="+this.table_class_Data[i].PR);
@@ -2091,6 +2090,22 @@ export default {
       }, 1000);
       }, 1000);
     },
     },
     menuClcik(index) {
     menuClcik(index) {
+      if(!this.isSave){
+        this.$Modal.confirm({
+          title: this.$t("scoreCalc.remind"),
+          content: '<p>' + this.$t("scoreCalc.remindMessage6") + '</p>',
+          onOk: async () => {
+            this.menuChangeTable(index);
+          },
+            onCancel: () => {
+              //this.$Message.info('Clicked cancel');
+            }
+          });
+      }else{
+        this.menuChangeTable(index);
+      }
+    },
+    menuChangeTable(index){
       if(index===-1){
       if(index===-1){
         this.tableClear();//清空表單資料
         this.tableClear();//清空表單資料
         this.tableReLoad_fun();//重新加載表單
         this.tableReLoad_fun();//重新加載表單
@@ -2105,7 +2120,8 @@ export default {
             this.tableReLoad_fun();//重新加載表單
             this.tableReLoad_fun();//重新加載表單
           }
           }
         }
         }
-      }      
+      } 
+      this.isSave = true;
     },
     },
     //拖曳相關--str---↓↓--
     //拖曳相關--str---↓↓--
     allowDrop(e) {//取消默認行為
     allowDrop(e) {//取消默認行為

+ 80 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/AddCard.vue

@@ -0,0 +1,80 @@
+<template>
+  <div class="AddCard-container">
+    <Modal v-model="DialogBoxBtn" title="新增節點" @on-ok="ok" @on-cancel="cancel">
+      <div>
+        名稱:
+        <Input v-model="nameValue" placeholder="Enter something..." style="width: 400px" />
+      </div>
+      <div class="AddCard-choose">
+        <div class="div-centerY">
+          <RadioButton v-model="RadioChoose" inputId="ingredient1" value="Chapter" />
+          <span class="AddSpen">章節</span>
+        </div>
+        <div class="div-centerY">
+          <RadioButton v-model="RadioChoose" inputId="ingredient2" value="Section" />
+          <span class="AddSpen">項目
+            <Select v-model="selectOne" style="width:200px" placeholder="課綱">
+              <Option v-for="item in syllabusList" :value="item.id" :key="item.id">{{ item.name }}</Option>
+            </Select>
+          </span>
+        </div>
+      </div>
+    </Modal>
+  </div>
+</template>
+<script>
+import RadioButton from 'primevue/radiobutton';
+import 'primevue/resources/themes/saga-blue/theme.css'; // 根據你喜好的主題選擇
+import 'primevue/resources/primevue.min.css';
+//import AddSyllabus from "./addSyllabus.vue"
+
+export default {
+  components: {
+    RadioButton,
+  },
+  props: {
+    DialogBoxCtl: Boolean,
+    chooseOne:Object,
+    cardData:Array,
+  },
+  data() {
+    return {
+      DialogBoxBtn: false,
+      RadioChoose: '',//Chapter章節 / Section資源卡片
+      selectOne:'',//多選,選擇的內容
+      nameValue:'',//輸入的內容
+      syllabusList: [],//放入下拉選單的選項
+    }
+  },
+  computed: {
+  },
+  created() {
+    this.syllabusList.push({id:this.chooseOne.id,name:this.chooseOne.name});
+    if(this.cardData){
+      for(let i = 0;i<this.cardData.length;i++){
+        this.syllabusList.push({id:this.cardData[i].id,name:this.cardData[i].name});
+      }
+    }
+  },
+  methods: {
+    ok() {
+      // this.$Message.info('Clicked ok');
+      this.$emit('DialogBoxClose', false);
+    },
+    cancel() {
+      this.$emit('DialogBoxClose', false);
+    },
+  },
+  watch: {
+    DialogBoxCtl(newVal) {
+      this.DialogBoxBtn = newVal;
+    },    
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./DialogBox.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 102 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/AddResources.vue

@@ -0,0 +1,102 @@
+<template>
+  <div class="AddResources-container">
+    <Modal v-model="DialogBoxBtn" title="新增資源" @on-ok="ok" @on-cancel="cancel" :width="TabsClick.width" class="AddResources-Modal">
+      <Tabs type="card" :animated="false" @on-click="TabsClickFun">
+        <TabPane label="內容資源" name="content">
+          <Button class="attend-button" :type="C_buttonType[0].btn ? 'primary':'default'" @click="changePage('content',0)">雲端內容</Button>
+          <Button class="attend-button" :type="C_buttonType[1].btn ? 'primary':'default'" @click="changePage('content',1)">本機檔案</Button>          
+          <Button class="attend-button" :type="C_buttonType[2].btn ? 'primary':'default'" @click="changePage('content',2)">超連結</Button>  
+          <div v-if="TabsClick.tab==='content'" class="content-div">
+            <CloudContent v-if="C_buttonType[0].btn"></CloudContent>
+            <LocalFile v-else-if="C_buttonType[1].btn"></LocalFile>            
+            <URL v-else-if="C_buttonType[2].btn"></URL>
+          </div>          
+        </TabPane>
+        <TabPane label="活動資源" name="activity">
+          <Button class="attend-button" :type="A_buttonType[0].btn ? 'primary':'default'" @click="changePage('activity',0)">個人評量</Button>
+          <Button class="attend-button" :type="A_buttonType[1].btn ? 'primary':'default'" @click="changePage('activity',1)">作業活動</Button>
+          <Button class="attend-button" :type="A_buttonType[2].btn ? 'primary':'default'" @click="changePage('activity',2)">個人投票</Button>
+          <Button class="attend-button" :type="A_buttonType[3].btn ? 'primary':'default'" @click="changePage('activity',3)">個人問卷</Button>
+          <div v-if="TabsClick.tab==='activity'" class="content-div">
+            <Evaluate v-if="A_buttonType[0].btn"></Evaluate>
+            <Homework v-else-if="A_buttonType[1].btn"></Homework>
+            <Vote v-else-if="A_buttonType[2].btn"></Vote>
+            <Questionnaire v-else-if="A_buttonType[3].btn"></Questionnaire>
+          </div>          
+        </TabPane>
+      </Tabs>
+    </Modal>
+  </div>
+</template>
+<script>
+import CloudContent from "./Resources/C_CloudContent.vue"//雲端內容
+import LocalFile from "./Resources/C_LocalFile.vue"//本機檔案
+import URL from "./Resources/C_URL.vue"//超連結
+import Evaluate from "./Resources/A_Evaluate.vue"//個人評量
+import Homework from "./Resources/A_Homework.vue"//作業活動
+import Vote from "./Resources/A_Vote.vue"//個人投票
+import Questionnaire from "./Resources/A_Questionnaire.vue"//個人問卷
+
+export default {
+  components: {
+    CloudContent,LocalFile,URL,Evaluate,Homework,Vote,Questionnaire
+  },
+  props: {
+    DialogBoxCtl: Boolean,    
+  },
+  data() {
+    return {
+      DialogBoxBtn:false,
+      TabsClick:{tab:'',width:800},//{<Tab>類型/按鈕類型/寬度}
+      //雲端內容/本機檔案/超連結↓
+      C_buttonType: [{btn:true,width:800},{btn:false,width:800},{btn:false,width:800}],
+      //個人評量/作業活動/個人投票/個人問卷↓
+      A_buttonType: [{btn:true,width:1000},{btn:false,width:800},{btn:false,width:800},{btn:false,width:800}],
+    }
+  },
+  computed: {
+  },
+  created() {
+    
+  },
+  mounted(){
+    this.TabsClick.tab = 'content';//必須在產生後才給值,否則tabs會互相干擾
+  },
+  methods: {  
+    TabsClickFun(name){//確認目前點到哪個標籤。此判斷是為了防止Tabs內外互相干擾
+      this.TabsClick.tab = name;
+      if(name==='content') this.TabsClick.width = this.C_buttonType.find(item => item.btn === true).width;
+      else if(name==='activity') this.TabsClick.width = this.A_buttonType.find(item => item.btn === true).width;      
+    },  
+    changePage(type,index){
+      let widthNum = type === 'content' ? this.C_buttonType[index].width : this.A_buttonType[index].width;
+      this.TabsClick = { tab: type, button: index, width: widthNum };
+      if(type==='content'){
+        for(let i =0;i<this.C_buttonType.length;i++)this.$set(this.C_buttonType[i], 'btn' , false);
+        this.$set(this.C_buttonType[index], 'btn' , true);
+      }else if(type==='activity'){
+        for(let i =0;i<this.A_buttonType.length;i++)this.$set(this.A_buttonType[i], 'btn', false);
+        this.$set(this.A_buttonType[index], 'btn', true);
+      }
+    },
+    ok() {
+      // this.$Message.info('Clicked ok');
+      this.$emit('DialogBoxClose',false);
+    },
+    cancel() {
+      this.$emit('DialogBoxClose',false);
+    },
+  },
+  watch: {
+    DialogBoxCtl(newVal) {
+      this.DialogBoxBtn= newVal;
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./DialogBox.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 70 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/DialogBox.less

@@ -0,0 +1,70 @@
+/deep/ .ivu-modal-header-inner{
+    font-weight: bold !important;
+}
+.div-center{//水平置中
+    display: flex; 
+    justify-content: center; 
+    text-align:center;
+    width:100%;
+}
+.div-centerY{//垂直置中
+    display: flex; 
+    align-items: center;  
+}
+.between{//分兩邊
+    display: flex;
+    justify-content: space-between;
+}
+.gray-font{
+    font-size: 10px;
+    color: #808695;
+}
+.showClass-div
+    {
+        margin-bottom: 10px;
+
+        .showClass
+        {
+            color: #2d8cf0;
+            padding: 5px;
+            border: 1px solid #2d8cf0;
+            border-radius: 5px;
+            margin: 5px;
+        }
+    }
+.SortingDiv{
+    border: 1px solid #c5c8ce;
+    overflow: auto;
+    max-height: 300px;
+    .itemCard{
+        margin: 10px 5px;
+    }
+}
+.mleft20{
+    margin-left: 20px;
+}
+
+.AddCard-choose{
+    display: flex;
+    margin: 5px;
+    margin-top: 10px;
+    .AddSpen{
+        margin-left: 5px;
+        margin-right: 30px;
+    }
+}
+
+
+
+.AddResources-Modal{
+    .attend-button{
+        white-space:normal ;
+        height: auto;
+        margin-right:15px;
+        padding: 2px 15px;
+    }
+    .content-div{
+        margin-top: 20px;
+    }
+    
+}

+ 50 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/DialogBoxTemp.vue

@@ -0,0 +1,50 @@
+<template>
+  <div class="AddCard-container">
+    <Modal v-model="DialogBoxBtn" title="新增節點" @on-ok="ok" @on-cancel="cancel">
+      123
+    </Modal>
+  </div>
+</template>
+<script>
+//import AddSyllabus from "./addSyllabus.vue"
+
+export default {
+  components: {
+
+  },
+  props: {
+    DialogBoxCtl: Boolean,    
+  },
+  data() {
+    return {
+      DialogBoxBtn:false,
+      
+    }
+  },
+  computed: {
+  },
+  created() {
+    
+  },
+  methods: {
+    ok() {
+      // this.$Message.info('Clicked ok');
+      this.$emit('DialogBoxClose',false);
+    },
+    cancel() {
+      this.$emit('DialogBoxClose',false);
+    },
+  },
+  watch: {
+    DialogBoxCtl(newVal) {
+      this.DialogBoxBtn= newVal;
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./DialogBox.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 63 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/ReleaseSyllabus.vue

@@ -0,0 +1,63 @@
+<template>
+  <div class="ReleaseSyllabus-container">
+    <Modal v-model="ReleaseBtn" title="上架設定" @on-ok="ok" @on-cancel="cancel">
+      <div class="mleft20">
+        <RadioGroup v-model="addData.chooseWay" vertical>
+          <Radio label="Empty">
+            <span>立即上架</span>
+          </Radio>        
+          <Radio label="Choose" :tabindex="0">
+            <span>預約上架:</span>          
+          </Radio>
+          <DatePicker type="daterange" placement="bottom-end" placeholder="Select date" style="width: 230px; margin-left:20px" />             
+        </RadioGroup>
+      </div>      
+    </Modal>
+  </div>
+</template>
+<script>
+//import AddSyllabus from "./addSyllabus.vue"
+
+export default {
+  components: {
+
+  },
+  props: {
+    ReleaseCtl: Boolean,    
+  },
+  data() {
+    return {
+      ReleaseBtn:false,
+      addData: {//新增課綱的相關內容
+        chooseWay: 'Empty',
+        codeData: '',
+      },
+    }
+  },
+  computed: {
+  },
+  created() {
+    
+  },
+  methods: {
+    ok() {
+      // this.$Message.info('Clicked ok');
+      this.$emit('ReleaseOpenFun',true);
+    },
+    cancel() {
+      this.$emit('ReleaseFun',false);
+    },
+  },
+  watch: {
+    ReleaseCtl(newVal) {
+      this.ReleaseBtn= newVal;
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./DialogBox.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 319 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/A_Evaluate.vue

@@ -0,0 +1,319 @@
+<template>
+  <div class="Evaluate-container">
+    <div class="between">
+      <div class="evaluation-attr-wrap">
+      <p class="wrap-label">{{$t('learnActivity.createEv.baseInfo')}}</p>
+      <div style=" padding-top:15px;"
+        class="ivu-select-nochoose light-el-input">
+          <Form ref="evaForm" :model="evaluationInfo" label-position="top" class="evaluation-attr-form " label-colon
+            :rules="ruleValidate">
+            <FormItem :label="$t('learnActivity.createEv.evName')" prop="name">
+              <Input v-special-char v-model="evaluationInfo.name"
+                :placeholder="$t('learnActivity.createEv.evName')"></Input>
+            </FormItem>
+            <FormItem prop="source">
+              <label slot="label" style="width:200px">
+                <span>{{$t('learnActivity.createEv.evMode')}}</span>
+                <Tooltip :content="$t('tip.examMode')" transfer theme="light" max-width="300">
+                  <Icon type="ios-information-circle-outline" color="#1cc0f3" style="margin-left:5px" />
+                </Tooltip>
+              </label>
+              <Select v-model="evaluationInfo.source" @on-change="checkItemSort">
+                <!-- 暂时取消创建课中评量 --> <!-- 20230105課中評測放回 -->
+                <Option v-for="(item,index) in $GLOBAL.EV_MODE()" v-show="true" :label="item.label" :value="item.value"
+                  :key="index"
+                  :disabled="index > 1 && (!$store.state.userInfo.hasSchool || !$store.state.user.schoolProfile.svcStatus.VABAJ6NV)">
+                  <div>
+                    <span>
+                      {{ item.label }}
+                    </span>
+                    <span @click.stop="toProduct" v-show="index > 1 && scaleStatusText()" class="no-auth-tag">
+                      {{ scaleStatusText() }}
+                    </span>
+                  </div>
+                </Option>
+              </Select>
+            </FormItem>
+            <FormItem>
+              <Checkbox v-model="evaluationInfo.isCompletion">{{ $t('learnActivity.createEv.completeScore') }}
+              </Checkbox>
+            </FormItem>
+          </Form>
+      </div>
+      </div>
+      <div class="evaluation-question-wrap">
+        <div class="evaluation-question-main">
+          <Tabs v-model="activeTab" type="card" class="question-main-tabs" name="createTest">
+            <TabPane :label="$t('learnActivity.createEv.papersLabel')" name="manualPaper"
+              v-if="createType == 'manualPaper'" :index="1" tab="createTest">
+              <ManualPaper @selectPaper="selectPaper"
+                :selectedId="evaluationInfo.paperInfo[0] ? evaluationInfo.paperInfo[0].id : ''"></ManualPaper>
+            </TabPane>
+            <TabPane :label="$t('learnActivity.createEv.perviewLabel')" name="preview" :index="2" tab="createTest">
+              <div class="teacher-preview-container">
+                <!--返回顶部-->
+                <!-- <div class="back-to-top" :title="$t('learnActivity.mgtScEv.returnTop')" v-show="showBack" @click="handleBackToTop">
+                                      <Icon type="ios-arrow-up" />
+                                  </div> -->
+                <BackToTop @on-to-top="handleBackToTop"></BackToTop>
+                <vuescroll ref="paper-preview" @handle-scroll="checkBackTop">
+                  <TestPaper v-if="activeTab == 'preview'"
+                    :paper="evaluationInfo.paperInfo.length ? evaluationInfo.paperInfo[0] : {item:[]}" isExamPaper
+                    hideSheet></TestPaper>
+                </vuescroll>
+              </div>
+            </TabPane>
+          </Tabs>
+        </div>
+      </div>
+    </div>    
+  </div>
+</template>
+<script>
+//參考於CreatePrivEva.vue
+import BlobTool from '@/utils/blobTool.js'
+import TestPaper from '@/view/evaluation/index/TestPaper.vue'
+import ManualPaper from '../../../../learnactivity/ManualPaper.vue'
+export default {
+  components: {
+    TestPaper,
+    ManualPaper,
+  },
+  props: {
+  },
+  data() {
+    return {
+      activeTab: 'manualPaper',
+      createType: 'manualPaper',
+      evaluationInfo: {
+        name: '',
+        targets: [],
+        classes: [],
+        scope: '',
+        type: '',  //测试类别
+        source: '',
+        publish: '0',
+        examType: null, //测试类型
+        paperInfo: [],
+        papers: [],
+        isCompletion: 0
+      },
+      ruleValidate: {
+        name: [
+          { required: true, message: this.$t('learnActivity.createEv.errTips1'), trigger: 'change' }
+        ],
+        'type.id': [
+          { required: true, message: this.$t('learnActivity.createEv.errTips2'), trigger: 'change' }
+        ],
+        source: [
+          { required: true, message: this.$t('learnActivity.createEv.errTips3'), trigger: 'change' }
+        ],
+        'type': [
+          { required: true, message: this.$t('learnActivity.createEv.errTips4'), trigger: 'change' }
+        ],
+        'examType.id': [
+          { required: true, message: this.$t('learnActivity.createEv.errTips5'), trigger: 'change' }
+        ],
+        targets: [
+          { required: true, message: this.$t('learnActivity.createEv.errTips6'), type: 'array', trigger: 'change' }
+        ],
+        classes: [
+          { required: true, message: this.$t('learnActivity.createEv.errTips6'), type: 'array', trigger: 'change' }
+        ],
+        publish: [
+          { required: true, message: this.$t('learnActivity.createEv.errTips7'), trigger: 'change' }
+        ],
+      },
+    }
+  },
+  computed: {
+  },
+  created() {
+    //编辑评测逻辑
+    let routerData = this.$route.params.evaluationInfo
+    if (routerData) {
+      // console.log(JSON.stringify(routerData))
+      console.log(routerData.subjects)
+      this.initData(routerData)
+    }
+  },
+  methods: {
+    scaleStatusText() {
+      if (!this.$store.state.userInfo.hasSchool) {
+        return this.$t('learnActivity.createEv.noSchool')
+      }
+      if (this.$store.state.user.schoolProfile.svcStatus.VABAJ6NV) {
+        return ''
+      } else {
+        return this.$t('learnActivity.createEv.noAuth')
+      }
+    },
+    toProduct() {
+      if (this.$store.state.userInfo.hasSchool) {
+        this.$router.push({
+          name: 'product'
+        })
+      }
+    },
+    //设置评测模式后检查试卷itemSort
+    checkItemSort() {
+      if (this.evaluationInfo.source == '2') {
+        let p = this.evaluationInfo.paperInfo.find(paper => paper.itemSort == 1)
+        if (p) {
+          this.$Modal.confirm({
+            title: this.$t('learnActivity.createEv.sort1'),
+            content: this.$t('learnActivity.createEv.sort2'),
+            onOk: () => {
+              for (let i = 0; i < this.evaluationInfo.paperInfo.length; i++) {
+                if (this.evaluationInfo.paperInfo[i].itemSort == 1) {
+                  let defaultPaper = {
+                    periodName: this.evaluationInfo.name,
+                    periodId: this.evaluationInfo.id,
+                    subjectName: this.evaluationInfo.paperInfo[i].subjectName,
+                    subjectId: this.evaluationInfo.paperInfo[i].subjectId,
+                    createType: 'manualPaper',
+                    score: 100,
+                    item: [],
+                    filter: {},
+                    name: this.$t('learnActivity.createEv.defaultPaper'),
+                    time: 0 //作答时间
+                  }
+                  this.evaluationInfo.paperInfo.splice(i, 1, this._.cloneDeep(defaultPaper))
+                }
+              }
+            },
+            onCancel: () => {
+              this.evaluationInfo.source = '0'
+            }
+          })
+        }
+      }
+    },
+    //复制或编辑评测初始化数据
+    async initData(data) {
+      let subjects = this._.cloneDeep(data.subjects)
+      data.id = ''
+      data.name = `${data.name}(${this.$t('learnActivity.mgtScEv.copy')})`
+      // this.endTime = new Date(data.endTime)
+      let pp = {
+        "@DESC": "createTime",
+        code: data.papers[0].code?.replace('Paper-', ''),
+        scope: data.papers[0].scope,
+        id: data.papers.map(item => item.id)
+      }
+      data.paperInfo = []
+      data.papers = []
+      data.publish = '0'
+      this.evaluationInfo = data
+      console.log(JSON.stringify(this.evaluationInfo))
+      try {
+        let paperInfo = await this.$api.learnActivity.FindExamPaper(pp)
+        if (!paperInfo.length) {
+          // pp.sc
+          paperInfo = await this.$api.learnActivity.FindExamPaper(pp)
+        }
+        for (let i = 0; i < paperInfo.papers.length; i++) {
+          let fullPaper = await this.$evTools.getFullPaper(paperInfo.papers[i])
+          this.comfirmSelectPaper(paperInfo.papers[i], fullPaper)
+        }
+        this.evaluationInfo.subjects = subjects
+      } catch (e) {
+
+      }
+      this.activeTab = 'preview'
+      // this.endTime = new Date(new Date(new Date().toLocaleDateString()).getTime() + 2 * 24 * 60 * 60 * 1000 - 1)
+      // this.evaluationInfo.endTime = new Date(new Date().toLocaleDateString()).getTime() + 2 * 24 * 60 * 60 * 1000 - 1
+      // data.id = ''
+      // data.name = `${data.name}(${this.$t('learnActivity.mgtScEv.copy')})`
+      // this.startTime = new Date(data.startTime)
+      // this.endTime = new Date(data.endTime)
+      // data.paperInfo = []
+      // this.defTargets = data.targets
+      // for (let i = 0; i < data.papers.length; i++) {
+      //     let paper = this._.cloneDeep(data.papers[i])
+      //     data.paperInfo.push(paper)
+      //     data.paperInfo[i].subjectId = data.subjects[i].id
+      //     data.paperInfo[i].subjectName = data.subjects[i].name
+      // }
+      // data.publish = '0'
+      // this.evaluationInfo = data
+      // this.activeTab = 'preview'
+    },
+
+    comfirmSelectPaper(simplePaper, fullPaper) {
+      if (!this.evaluationInfo.name) {
+        this.evaluationInfo.name = simplePaper.name
+      }
+      fullPaper.examId = ''
+      fullPaper.examScope = this.mode
+      fullPaper.examCode = this.$store.state.userInfo.schoolCode
+      this.evaluationInfo.paperInfo[0] = fullPaper
+      this.evaluationInfo.papers[0] = simplePaper
+      this.goToPreview()
+    },
+    goToPreview() {
+      this.activeTab = 'preview'
+    },
+    /**
+     * 处理挑选试卷事件
+     * @param data
+     */
+    selectPaper(data) {
+      if (this.evaluationInfo.source == '2' && data.itemSort == 1) {
+        return this.$Message.warning(this.$t('learnActivity.createEv.sort3'))
+      }
+      let simplePaper = data
+      this.$Modal.confirm({
+        title: this.$t('learnActivity.createEv.stPaperTitle'),
+        content: `${this.$t('learnActivity.createEv.stPaperContent')}${data.name}?`,
+        onOk: async () => {
+          let fullPaper = await this.$evTools.getFullPaper(simplePaper)
+          this.comfirmSelectPaper(simplePaper, fullPaper)
+        }
+      })
+    },
+    /**vuescroll回到顶部 */
+    handleBackToTop() {
+      this.$refs['paper-preview'].scrollTo(
+        {
+          y: '0'
+        },
+        300
+      )
+    },
+    /**
+     * 判断是否显示回到顶部按钮
+     * @param vertical
+     * @param horizontal
+     * @param nativeEvent
+     */
+    checkBackTop(vertical, horizontal, nativeEvent) {
+      if (vertical.scrollTop > 100) {
+        this.showBack = true
+      } else {
+        this.showBack = false
+      }
+    },
+  },
+  watch: {
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./Resources.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+
+.evaluation-question-main .ivu-tabs-tab-active {
+  font-weight: 600;
+}
+
+.evaluation-question-main .ivu-tabs-bar {
+  border-color: #404040;
+  margin-bottom: 0px;
+  border-bottom: none;
+}
+
+
+</style>

+ 273 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/A_Homework.vue

@@ -0,0 +1,273 @@
+<template>
+  <div class="Homework-container">
+    <Form ref="voteForm" :model="voteForm" label-position="top" :rules="ruleValidate" :disabled="!voteFormEdit" hide-required-mark>
+      <div style="display: flex;">
+        <div style="width: 48%;">
+          <FormItem :label="$t('homework.form.name')" prop="name">
+            <Input :class="!voteFormEdit ? 'vote-form-disabled':''" v-model="voteForm.name" 
+              :placeholder="$t('homework.form.namePlace')"></Input>
+          </FormItem>
+          <!-- 作业描述 -->
+          <FormItem :label="$t('homework.form.description')" prop="description">
+            <div ref="descriptionEditor" style="text-align:left" v-show="voteFormEdit"></div>
+            <div v-html="voteForm.description" v-show="!voteFormEdit" style="margin:10px;font-size:16px;font-weight:bold;word-break: break-all;"></div>
+          </FormItem>      
+        </div>
+        <div style="width: 48%;padding-left: 2%;margin-left:2%;border-left: 1px dashed #D2D2D2;">
+          <!-- 作业附件 -->
+          <FormItem :label="$t('homework.form.attachments')">            
+            <p style="text-align: right;font-size: 12px;color:#1ba6dd;text-decoration: underline;cursor: pointer;" @click="openChooseContent">{{ $t('homework.chooseContent') }}</p>
+            <BaseUpload simpleUpload v-show="voteFormEdit" @uploadFinish="uploadFinish"></BaseUpload>
+            <div v-if="attachmentsArr.length" class="attachments-list">
+              <div class="attachments-item" v-for="(item,index) in attachmentsArr" :key="index">
+                <span class="name">
+                  <span style="margin-right: 10px;">{{ getSizeByBytes(item.size) }}</span>
+                  <Icon type="md-close" color="#adadad" @click="removeAttachment(index)" v-if="voteFormEdit" />                  
+                </span>
+              </div>
+            </div>
+          </FormItem>
+          <!-- 作业其他选项 -->
+          <FormItem :label="$t('homework.form.other')" style="margin-bottom: 0px;">
+            <CheckboxGroup v-model="voteForm.allowSupply">
+              <Checkbox label="allow">{{ $t('homework.form.allowFix') }}</Checkbox>
+            </CheckboxGroup>
+            <CheckboxGroup v-model="voteForm.allowComment">
+              <Checkbox label="allow">{{ $t('homework.form.allowComment') }}</Checkbox>
+            </CheckboxGroup>
+            <CheckboxGroup v-model="voteForm.mustSubmit">
+              <Checkbox label="mustSubmit">{{ $t('homework.form.mustSubmit') }}</Checkbox>
+            </CheckboxGroup>
+            <CheckboxGroup v-model="voteForm.extLimit" v-if="voteForm.mustSubmit.length">
+              <Checkbox label="extLimit">{{ $t('homework.form.allowFileType') }}</Checkbox>
+            </CheckboxGroup>
+            <Select v-model="chooseExtends" filterable multiple allow-create @on-create="handleCreate" v-if="voteForm.extLimit.length && voteForm.mustSubmit.length && voteFormEdit" :placeholder="$t('homework.extLimitPlace')">
+              <Option v-for="item in extendArr" :value="item" :key="item">.{{ item  }}</Option>
+            </Select>
+            <div v-if="chooseExtends.length && !voteFormEdit">
+              <span>{{ $t('homework.limitType') }}:</span>
+              <span v-for="(item,index) in chooseExtends" :key="index"
+                style="background-color: #5da9ff;margin-right: 10px;color: #fff;padding: 2px 10px;border-radius: 4px;">.{{ item }}</span>
+            </div>
+          </FormItem>
+        </div>
+      </div>
+    </Form>
+
+    <!-- 关联内容弹窗 -->
+    <Modal v-model="contentModal" width="880" footer-hide class="related-modal base-repair-modal">
+      <div class="modal-header" slot="header">{{$t('evaluation.newExercise.contentRelate')}}</div>
+      <NewChooseContent :showSyllabus="false" :showOther="false" :showQuestion="false" :showPaper="false" ref="chooseContentRef" @on-file-change="onSelectFile" v-if="contentModal"></NewChooseContent>
+
+      <Button class="modal-btn" @click="onConfirmRelate">{{$t('evaluation.confirm')}}</Button>
+    </Modal>
+
+  </div>
+</template>
+<script>
+//程式碼參考BaseHwForm.vue
+import E from 'wangeditor'
+
+export default {
+  components: {
+
+  },
+  props: { 
+    editItem: {
+      type: Object,
+      default: null
+    },
+  },
+  data(vm) {
+    return {
+      maxAttachmentCount: 5,
+      maxFileSize: 1024 * 1024 * 50,
+      contentModal: false,
+      extendArr: ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'rar', 'mp3', 'mp4', 'txt', 'jpg', 'jpeg',
+        'png'
+      ],
+      chooseExtends: [],
+      attachmentsArr: [],
+      classNameArr: [],
+      isEdit: false,
+      editInfo: null,
+      voteFormEdit: true,
+      descriptionEditor: null,
+      voteForm: {
+        name: '',
+        classes: [],
+        startTime: '',
+        endTime: '',
+        description: '',
+        allowSupply: [],
+        allowComment: [],
+        extLimit: [],
+        mustSubmit: []
+      },
+      ruleValidate: {
+        name: [{
+          required: true,
+          message: vm.$t('homework.form.ruleName'),
+          trigger: 'blur'
+        }],
+        // description: [{
+        // 	// required: true,
+        // 	message: vm.$t('homework.form.ruleDescription'),
+        // 	trigger: 'blur'
+        // }],
+        // startTime: [{
+        // 	type: 'date',
+        // 	message: this.$t('learnActivity.createEv.errTips8'),
+        // 	trigger: 'change'
+        // }],
+        endTime: [{
+          required: true,
+          type: 'date',
+          message: this.$t('learnActivity.createEv.errTips9'),
+          trigger: 'change'
+        }]
+      },
+      selectFiles: [],
+    }
+  },
+  
+  created() {
+    
+  },
+  methods: {
+    openChooseContent() {
+      this.contentModal = true
+      this.$nextTick(() => {
+        if (this.$refs.chooseContentRef) {
+          this.$refs.chooseContentRef.clickTab('content')
+        }
+      })
+    },
+    /* 内容挑选变化 */
+    onSelectFile(val) {
+      this.selectFiles = val.files
+    },
+    /* 确认添加站内资源 */
+    onConfirmRelate() {
+      for (let i = 0; i < this.selectFiles.length; i++) {
+        let file = this.selectFiles[i]
+        if (this.attachmentsArr.length >= this.maxAttachmentCount) {
+          this.$Message.warning(this.$t('homework.countTip'))
+          return
+        } else {
+          this.attachmentsArr.push(file)
+        }
+      }
+      this.contentModal = false
+    },
+    /* 自定义添加文件后缀 */
+    handleCreate(val) {
+      this.extendArr.push(val);
+    },
+    /* 添加附件 */
+    uploadFinish(file) {
+      if (this.attachmentsArr.length >= this.maxAttachmentCount) {
+        this.$Message.warning(this.$t('homework.countTip'))
+      } else if (file.size > this.maxFileSize) {
+        this.$Message.warning(this.$t('homework.sizeTip'))
+      } else {
+        this.attachmentsArr.push(file)
+      }
+    },
+     /* 移除附件 */
+    removeAttachment(index) {
+      this.attachmentsArr.splice(index, 1)
+    },
+    /* 根据字节数转换为大小 */
+    getSizeByBytes(bytes) {
+      return bytes / 1024 < 1024 ? (bytes / 1024).toFixed(1) + 'KB' : bytes / 1024 / 1024 < 1024 ? (bytes /
+        1024 / 1024).toFixed(1) + 'M' : (bytes / 1024 / 1024 / 1024).toFixed(1) + 'G'
+    },
+    /* 渲染作业活动 */
+    async doRender(item) {
+      console.log('需要渲染的投票对象', item)
+      if (item.targetType === 'research') {
+        console.log(this.groupList);
+        let groupNameArr = []
+        item.tchLists.forEach(i => {
+          let findObj = this.groupList.find(j => j.id === i)
+          if (findObj) {
+            groupNameArr.push(findObj)
+          }
+        })
+        this.classNameArr = groupNameArr
+      } else {
+        this.classNameArr = item.classes.length ? await this.getClassNameByIds(item.classes) : item
+          .stuLists.length ? await this.getClassNameByIds(item.stuLists) : []
+      }
+      this.voteForm = null
+      this.chooseExtends = item.extLimit
+      this.attachmentsArr = item.attachments
+      this.voteForm = {
+        name: item.name,
+        code: item.code,
+        targets: item.targets,
+        classes: item.classes.length ? item.classes : item.stuLists,
+        startTime: item.startTime ? new Date(item.startTime) : '',
+        endTime: item.endTime ? new Date(item.endTime) : '',
+        description: item.description,
+        allowSupply: item.allowSupply ? ['allow'] : [],
+        allowComment: item.allowComment ? ['allow'] : [],
+        mustSubmit: item.mustSubmit ? ['mustSubmit'] : [],
+        extLimit: item.extLimit.length ? ['extLimit'] : [],
+      }
+      this.descriptionEditor.txt.html(item.description)
+
+      this.$nextTick(() => {
+        this.$refs.voteForm.validateField('name')
+        this.$refs.voteForm.validateField('classes')
+        this.$refs.voteForm.validateField('description')
+      })
+    },
+  },
+  watch: {
+    editItem: {
+      handler(newValue) {
+        /** 编辑回显 */
+        if (newValue) {
+          console.log(newValue)
+          this.doRender(JSON.parse(JSON.stringify(newValue)))
+          this.isEdit = Boolean(newValue.id)
+          this.editInfo = JSON.parse(JSON.stringify(newValue))
+        }
+      },
+    }
+  },
+  mounted() {
+    let descriptionEditor = new E(this.$refs.descriptionEditor)
+    descriptionEditor.config.onchange = (html) => {
+      this.voteForm.description = html
+    }
+    descriptionEditor.config.height = 200
+    this.$editorTools.initSimpleEditor(descriptionEditor, this)
+    descriptionEditor.create()
+    this.descriptionEditor = descriptionEditor
+
+    if (this.editItem && this.editItem.name) {
+      console.log(this.editItem)
+      this.editInfo = JSON.parse(JSON.stringify(this.editItem))
+      this.doRender(this.editInfo)
+    }
+  },
+  computed: {
+    isDraft() {
+      return this.editInfo.progress === 'draft'
+    }
+  },
+}
+</script>
+<style lang="less" scoped>
+@import "./Resources.less";
+
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+
+
+
+</style>

+ 356 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/A_Questionnaire.vue

@@ -0,0 +1,356 @@
+<template>
+  <div class="Questionnaire-container">
+    <Loading :top="200" bgColor="rgba(103, 103, 103, 0.27)" type="1" v-show="isLoading"></Loading>
+    <div class="body">
+      <div class="left">
+        <BaseQnForm :editItem="currentQn" @onAddSuccess="onAddSuccess" @onAddFail="isBtnLoading = false" ref="qnForm">
+        </BaseQnForm>
+      </div>
+      <div class="right">
+        <!-- 问卷提交数据 -->
+        <div class="qn-col qn-data-box">
+          <div class="qn-box-header">
+            <div class="qn-box-header-tools">
+              <div class="qn-box-header-tools-tool" style="margin-right: 10px">
+                <Dropdown @on-click="onAddItem">
+                  <Button icon="md-list-box">
+                    {{ $t('survey.addItem') }}
+                    <Icon type="ios-arrow-down"></Icon>
+                  </Button>
+                  <DropdownMenu slot="list">
+                    <DropdownItem name="single">{{ $t('survey.single') }}</DropdownItem>
+                    <DropdownItem name="multiple">{{ $t('survey.multiple') }}
+                    </DropdownItem>
+                    <DropdownItem name="judge">{{ $t('survey.judge') }}</DropdownItem>
+                    <DropdownItem name="subjective">{{ $t('survey.subjective') }}
+                    </DropdownItem>
+                  </DropdownMenu>
+                </Dropdown>
+              </div>
+              <div class="qn-box-header-tools-tool" style="margin-right: 10px">
+                <Button class="btn-save" icon="md-folder" :loading="isBtnLoading"
+                  @click="onSaveQn">{{ $t('survey.save') }}</Button>
+              </div>
+            </div>            
+          </div>
+          <div class="contect">
+            <BaseQuestionnaire :currentQn="currentQn" :students="allSsList" :isEdit="editable" ref="qnPaper" v-if="isEmptyData">
+            </BaseQuestionnaire>
+          </div>          
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import BaseQnForm from './part/BaseQnForm.vue';
+import BaseQuestionnaire from "@/components/questionnaire/BaseQuestionnaire.vue";
+export default {
+  components: {
+    BaseQnForm,BaseQuestionnaire,
+  },
+  props: {
+  },
+  data() {
+    return {
+      isEmptyData: true,
+      isLoading: false,
+      isBtnLoading: false,
+      editable: true,
+      qnList: [],
+      currentQn: {
+        progress: "pending",
+      },
+      noFinishStudents: [],
+      allSsList: [],
+      areaRecord: [],
+    }
+  },
+  mounted() {
+
+  },
+  computed: {
+    isAreaSurvey() {
+      return this.$route.name === 'manageAreaQuestionnaire'
+    },
+    getCurScope() {
+      return this.$route.name === "personalSurvey" ? "private" : "school";
+    },
+    isPrivate() {
+      return this.$route.name === 'personalSurvey'
+    },
+  },
+  created() {
+  },
+  methods: {
+    onAddItem(name) {
+      this.$refs.qnPaper.onMenuClick(name);
+    },
+    
+
+    /* 获取区级活动的作答数据 */
+    async getAreaRecord(schoolIndex) {
+      let curSchoolInfo = this.areaRecord[schoolIndex]
+      let schoolSas = await this.$evTools.getBlobSchoolSas(curSchoolInfo.code)
+      let fullPath = this.$evTools.getBlobHost() + '/' + curSchoolInfo.code + curSchoolInfo.url + schoolSas
+      let recordJson = JSON.parse(await this.$tools.getFile(fullPath))
+      console.log(curSchoolInfo)
+      console.log(recordJson)
+      this.allSsList = new Array(curSchoolInfo.count).fill('0')
+      this.noFinishStudents = new Array(curSchoolInfo.count - recordJson.userids.length).fill('0')
+    },
+
+    /* 保存问卷操作,由外層的確定觸發 */
+    async onSaveQn() {
+      try {
+        let qnBaseInfo = this.handleSubmit("qnForm");
+        let qnItems = this.$refs.qnPaper.items || [];
+
+        if (!qnItems.length) {
+          this.$Message.warning(this.$t('survey.noItemTip'))
+          return
+        }
+        this.isBtnLoading = true;
+        if (this.isAreaSurvey) {
+          qnBaseInfo.survey.scope = 'school'
+          qnBaseInfo.survey.id = this.$tools.guid()
+          // 将问卷试题内容保存到blob 用blobUrl来替换quesitons字段
+          qnBaseInfo.survey.answers = this.getSurveyAns(qnItems)
+          qnBaseInfo.survey.recordUrl = ""
+          qnBaseInfo.survey.blob = await this.doUploadAreaBlob(qnBaseInfo.survey, qnItems);
+          qnBaseInfo.survey.status = 1
+          console.log(qnBaseInfo)
+        } else {
+          // 将问卷试题内容保存到blob 用blobUrl来替换quesitons字段
+          qnBaseInfo.answers = this.getSurveyAns(qnItems)
+          qnBaseInfo.blob = await this.doUploadBlob(qnBaseInfo, qnItems);
+        }
+
+        // 开始保存问卷
+        this.saveorUpdataQn(qnBaseInfo)
+          .then((res) => {
+            this.$Message.success(this.$t('survey.doSuc'));
+            this.hasModify = true
+            this.onAddSuccess();
+          })
+          .catch((error) => {
+            this.$Message.error(`${error}`);
+          }).finally(data => {
+            this.isLoading = false;
+            this.isBtnLoading = false;
+          });
+      } catch (e) {
+        console.log(e)
+        this.isLoading = false;
+        this.isBtnLoading = false;
+      }
+
+    },
+    /* 保存问卷题目到Blob */
+    doUploadAreaBlob(qnBaseInfo, items) {
+      return new Promise(async (resolve, reject) => {
+        try {
+          let s = this.$store.state.user.userProfile.osblob_uri
+          // 获取初始化Blob需要的数据
+          let sasData = {
+            sas: '?' + this.$store.state.user.userProfile.osblob_sas,
+            name: 'teammodelos',
+            // url: s.split(s.substring(s.lastIndexOf('/')))[0]
+            url: this.$evTools.getBlobHost(s)
+          }
+          //初始化Blob
+          let containerClient = new blobTool(
+            sasData.url,
+            sasData.name,
+            sasData.sas,
+            qnBaseInfo.scope
+          );
+          let areaId = sessionStorage.getItem('areaId')
+          let itemUrls = await this.doUploadAreaItems(qnBaseInfo, items, containerClient)
+          qnBaseInfo.slides = itemUrls
+          let file = new File([JSON.stringify(qnBaseInfo)], "index.json");
+          // 等待上传blob的返回结果
+          let blobFile = await containerClient.upload(file, {
+            path: `${areaId}/survey/${qnBaseInfo.id}`,
+            checkSize: false,
+            root: `${areaId}/`
+          })
+
+          if (blobFile.blob) {
+            delete qnBaseInfo.slides
+            resolve(blobFile.blob)
+          } else {
+            this.$Message.error(this.$t('evaluation.newExercise.uploadErrorTip'));
+          }
+        } catch (e) {
+          this.isLoading = false;
+          this.isBtnLoading = false;
+          reject(e);
+        }
+      })
+    },
+    async doUploadAreaItems(qnBaseInfo, items, containerClient) {
+      return new Promise(async (resolve, reject) => {
+        let promiseArr = []
+        let areaId = sessionStorage.getItem('areaId')
+        for (let item of items) {
+          let curId = item.id || this.$tools.guid()
+          promiseArr.push(new Promise(async (r, j) => {
+            // let itemJsonFile = await this.$evTools.createBlobItem(exerciseItem);
+            let file = new File([JSON.stringify(item)], curId + ".json");
+            try {
+              // 等待上传blob的返回结果
+              // let blobFile = await containerClient.upload(file, `${areaId}/survey/${qnBaseInfo.id}`,{} , false,`${areaId}/`);
+              let blobFile = await containerClient.upload(file, {
+                path: `${areaId}/survey/${qnBaseInfo.id}`,
+                checkSize: false,
+                root: `${areaId}/`
+              })
+              if (blobFile.blob) {
+                console.log('上传Blob成功', blobFile)
+                r(blobFile.blob)
+              } else {
+                this.$Message.error(this.$t('evaluation.newExercise.uploadErrorTip'));
+              }
+            } catch (e) {
+              j(e)
+              this.isLoading = false;
+              this.isBtnLoading = false;
+              this.$Message.error(e.spaceError);
+            }
+          }))
+        }
+        Promise.all(promiseArr).then(result => {
+          resolve(result)
+        })
+      })
+    },
+
+    /* 上传index.json */
+    async doUploadItems(qnBaseInfo, items) {
+      return new Promise(async (resolve, reject) => {
+        let promiseArr = []
+        // 获取初始化Blob需要的数据
+        let sasData = qnBaseInfo.scope === 'private' ? await this.$tools.getPrivateSas() :
+          await this.$tools.getSchoolSas();
+        //初始化Blob
+        let containerClient = new blobTool(
+          sasData.url,
+          sasData.name,
+          sasData.sas,
+          qnBaseInfo.scope
+        );
+
+        for (let item of items) {
+          let curId = item.id || this.$tools.guid()
+          promiseArr.push(new Promise(async (r, j) => {
+            // let itemJsonFile = await this.$evTools.createBlobItem(exerciseItem);
+            let file = new File([JSON.stringify(item)], curId + ".json");
+            try {
+              // 等待上传blob的返回结果
+              let blobFile = await containerClient.upload(file, { path: 'survey/' + qnBaseInfo.id });
+              if (blobFile.blob) {
+                console.log('上传Blob成功', blobFile)
+                r(blobFile.blob)
+              } else {
+                this.$Message.error(this.$t(
+                  'evaluation.newExercise.uploadErrorTip'));
+              }
+            } catch (e) {
+              j(e)
+              this.isLoading = false;
+              this.isBtnLoading = false;
+              this.$Message.error(e.spaceError);
+            }
+          }))
+        }
+        Promise.all(promiseArr).then(result => {
+          resolve(result)
+        })
+      })
+    },
+    /* 保存问卷题目到Blob */
+    doUploadBlob(qnBaseInfo, items) {
+      return new Promise(async (resolve, reject) => {
+        try {
+          let itemUrls = await this.doUploadItems(qnBaseInfo, items)
+          qnBaseInfo.slides = itemUrls
+          // 获取初始化Blob需要的数据
+          let sasData = qnBaseInfo.scope === 'private' ? await this.$tools.getPrivateSas() :
+            await this.$tools.getSchoolSas();
+          //初始化Blob
+          let containerClient = new blobTool(
+            sasData.url,
+            sasData.name,
+            sasData.sas,
+            qnBaseInfo.scope
+          );
+          let file = new File([JSON.stringify(qnBaseInfo)], "index.json");
+          // 等待上传blob的返回结果
+          let blobFile = await containerClient.upload(file, { path: 'survey/' + qnBaseInfo.id });
+          if (blobFile.blob) {
+            delete qnBaseInfo.slides
+            resolve(blobFile.blob)
+          } else {
+            this.$Message.error(this.$t('evaluation.newExercise.uploadErrorTip'));
+          }
+        } catch (e) {
+          this.isLoading = false;
+          this.isBtnLoading = false;
+          reject(e);
+        }
+      })
+    },
+    /**
+     * 新增问卷或者编辑问卷
+     * @param data
+     */
+    saveorUpdataQn(data) {
+      return new Promise((r, j) => {
+        if (this.isAreaSurvey) {
+          this.$api.ability.saveAreaSurveys(data).then((res) => {
+            if (!res.error) {
+              r(res);
+            } else {
+              j(res.error);
+            }
+          });
+        } else {
+          this.$api.questionnaire.UpsertSurvey(data).then((res) => {
+            if (!res.error) {
+              r(res);
+            } else {
+              j(res.error);
+            }
+          });
+        }
+
+      });
+    },
+
+    /** 新增问卷成功回调 */
+    onAddSuccess() {
+      this.continueToken = null
+      this.handleTabClick(this.$route.name === "manageQuestionnaire" ? 0 : 1);
+    },
+
+    /* 获取问卷所有试题的选项内容 */
+    getSurveyAns(items) {
+      let result = []
+      items.forEach(item => {
+        result.push(item.option.map(i => i.code))
+      })
+      return result
+    },
+
+  },
+  watch: {
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./Resources.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 312 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/A_Vote.vue

@@ -0,0 +1,312 @@
+<template>
+  <div class="Vote-container">
+    <Form ref="voteForm" :model="voteForm" label-position="top" :rules="ruleValidate" hide-required-mark>
+      <div style="display: flex;">
+        <div style="width: 48%;">
+          <FormItem :label="$t('vote.form.name')" prop="name">
+            <Input v-special-char  v-model="voteForm.name" :placeholder="$t('vote.form.namePlace')"></Input>
+          </FormItem>          
+          <FormItem :label="$t('vote.form.description')" prop="description">
+            <div ref="descriptionEditor" style="text-align:left;"></div>
+            <!-- <div v-html="voteForm.description" style="margin:10px;font-size:16px;font-weight:bold;word-break: break-all;"></div> -->
+          </FormItem>
+        </div>
+        <div style="width: 48%;padding-left: 2%;margin-left:2%;border-left: 1px dashed #D2D2D2;">
+          <FormItem :label="$t('vote.form.optionSetting')" prop="attachment" ref="optionsBox">
+            <div v-if="voteOptions.length">
+              <div v-for="(item,index) in voteOptions" :key="index" class="option-editor-wrap">
+                <div style="display: flex;">
+                  <span class="option-order">{{ index + 1 }}
+                    <Icon type="md-trash" @click="deleteOption(index)" />
+                  </span>
+                  <div :ref="'voteOption'+index" style="text-align:left" class="option-editor" @click="optionClick(index)"></div>
+                </div>                
+              </div>
+            </div>
+            <p style="float:right;color:#757575;cursor:pointer" @click="onAddOption" >
+              <Icon type="md-add" />{{ $t('vote.form.addOption') }}
+            </p>
+          </FormItem>
+          <FormItem :label="$t('vote.form.times')">
+            <Select v-model="voteForm.times" >
+              <Option value="once">{{ $t('vote.form.once') }}</Option>
+              <Option value="day">{{ $t('vote.form.day') }}</Option>
+              <Option value="week">{{ $t('vote.form.week') }}</Option>
+              <Option value="month">{{ $t('vote.form.month') }}</Option>
+              <Option value="year">{{ $t('vote.form.year') }}</Option>
+            </Select>
+          </FormItem>
+          <FormItem :label="$t('vote.form.selectNum')" prop="selectMax">
+            <!--<Input :class="!voteFormEdit ? 'vote-form-disabled':''" v-model="voteForm.count" placeholder="请输入投票名称"></Input>-->
+            <InputNumber :min="1" v-model="voteForm.selectMax"></InputNumber>
+          </FormItem>
+          <FormItem :label="$t('vote.form.other')" prop="secret">
+            <CheckboxGroup v-model="voteForm.secret">
+              <Checkbox label="secret">{{ $t('vote.form.openSecret') }}</Checkbox>
+            </CheckboxGroup>
+            <CheckboxGroup v-model="voteForm.repeat" v-if="voteForm.selectMax > 1">
+              <Checkbox label="repeat">{{ $t('vote.form.openRepeat') }}</Checkbox>
+            </CheckboxGroup>
+          </FormItem>
+        </div>
+      </div>
+    </Form>
+  </div>
+</template>
+<script>
+//import AddSyllabus from "./addSyllabus.vue"
+import E from 'wangeditor'
+export default {
+  components: {
+
+  },
+  props: { 
+  },
+  data(vm) {
+    return {
+      classNameArr: [],
+      descriptionEditor: null,
+      voteOptions: [...new Array(2).keys()], // 默认四个选项,
+      voteOptionsContent: [],
+      voteForm: {
+        name: '',
+        classes: [],
+        endTime: '',
+        publishModel: '0',
+        startTime: '',
+        rangeTime: null,
+        description: '',
+        isReset: [],
+        selectMax: 1,
+        secret: [],
+        repeat: [],
+        times: 'once',
+        voteNum: '1'
+      },
+      ruleValidate: {
+        name: [{
+          required: true,
+          message: vm.$t('vote.form.ruleName'),
+          trigger: 'blur'
+        }],
+        endTime: [{
+          required: true,
+          type: 'date',
+          message: this.$t('learnActivity.createEv.errTips9'),
+          trigger: 'change'
+        }]
+      },
+    }
+  },
+  created() {
+    
+  },
+  methods: {   
+    /* 渲染投票对象表单 */
+    async doRender(item) {
+      console.log('需要渲染的投票对象', item)
+      // await this.findResearchList()
+      // 如果是区级投票
+      if (this.isAreaVote) {
+        this.classNameArr = item.targets.map(i => {
+          return {
+            name: i
+          }
+        })
+      } else {
+        if (item.targetType === 'research') {
+          if (item.tchLists.includes('TeacherAll')) {
+            this.classNameArr = [{
+              name: this.$t('vote.allTeacher')
+            }]
+          } else {
+            let groupNameArr = []
+            item.tchLists.forEach(i => {
+              let findObj = this.groupList.find(j => j.id === i)
+              if (findObj) {
+                groupNameArr.push(findObj)
+              }
+            })
+            this.classNameArr = groupNameArr
+          }
+        } else {
+          this.classNameArr = item.classes.length ? await this.getClassNameByIds(item.classes) : item
+            .stuLists.length ? await this.getClassNameByIds(item.stuLists) : []
+        }
+      }
+
+      console.log(this.classNameArr);
+      this.voteForm = null
+      this.voteOptionsContent = []
+      this.voteOptions = []
+      this.initEditors()
+      this.voteForm = {
+        name: item.name,
+        code: item.code,
+        targets: item.targets,
+        classes: item.targetType === 'research' ? item.tchLists : item.classes.length ? item.classes : item.stuLists,
+        startTime: item.startTime ? new Date(item.startTime) : '',
+        endTime: item.endTime ? new Date(item.endTime) : '',
+        description: item.description,
+        secret: item.secret ? ['secret'] : [],
+        repeat: item.repeat ? ['repeat'] : [],
+        selectMax: item.voteNum || 1,
+        times: item.times || 'once',
+        voteNum: item.voteNum || 1,
+        isReset: []
+      }
+      console.error('render', this.voteForm)
+      this.isImmediate = item.isImmediate || false
+      this.descriptionEditor.txt.html(item.description)
+      this.voteOptionsContent = item.options
+      this.voteOptions = item.options.map((item, index) => index)
+
+      this.$nextTick(() => {
+        this.initEditors()
+        this.$refs.voteForm.validateField('name')
+        this.$refs.voteForm.validateField('classes')
+        this.$refs.voteForm.validateField('description')
+      })
+    },
+    /* 初始化编辑器 */
+    initEditors() {
+      console.log('进入编辑起初始化')
+      console.log(this.voteOptions)
+      console.log(this.voteOptionsContent)
+      this.$nextTick(() => {
+        // Editor默认配置
+        if (this.voteOptions.length > 0) {
+          this.voteOptions.forEach((item, i) => {
+            let that = this
+            let editor = new E(that.$refs['voteOption' + i][0])
+            this.$editorTools.initSimpleEditor(editor)
+            // 选项编辑器失焦隐藏工具栏
+            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.config.onchange = (html) => {
+              let key = String.fromCharCode(64 + parseInt(i + 1))
+              let codeArr = this.voteOptionsContent.map(item => item.code)
+              // 如果已经编辑过则 修改选项内容
+              if (codeArr.indexOf(key) !== -1) {
+                this.voteOptionsContent[codeArr.indexOf(key)].value = html
+              } else { // 否则创建新选项
+                let option = {
+                  code: key,
+                  value: html
+                }
+                this.voteOptionsContent.push(option)
+              }
+            }
+            editor.create()
+
+            // 如果是编辑状态 则将选项内容回显
+            if (this.editInfo) {
+              editor.txt.html(this.voteOptionsContent[i].value)
+            }
+          })
+        }
+      })
+    },
+    /* 模拟选项聚焦事件 */
+    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'
+      }
+      setTimeout(function () {
+        let currentToolBar = that.$refs['voteOption' + index][0].children[0]
+        if (currentToolBar.clientHeight > 50) {
+          currentToolBar.style.top = '-90px'
+        }
+        currentToolBar.style.visibility = 'visible'
+      }, 100)
+    },
+    /* 删除选项 */
+    deleteOption(index) {
+      this.voteOptions.splice(index, 1)
+      this.voteOptionsContent.splice(index, 1)
+      console.log(this.voteOptions)
+      console.log(this.voteOptionsContent)
+      this.$nextTick(() => {
+        this.initEditors()
+      })
+    },
+    /* 添加选项 */
+    onAddOption() {
+      let that = this
+      let newIndex = this.voteOptions.length
+      let optionsLength = this.voteOptions.length
+      console.log(this.voteOptionsContent)
+      if (optionsLength < 10) {
+        this.voteOptions.push(newIndex)
+        this.$nextTick(() => {
+          let editor = new E(that.$refs['voteOption' + newIndex][0])
+          this.$editorTools.initSimpleEditor(editor)
+          editor.config.onchange = (html) => {
+            let key = String.fromCharCode(64 + parseInt(newIndex + 1))
+            let codeArr = this.voteOptionsContent.map(item => item.code)
+            // 如果已经编辑过则 修改选项内容
+            if (codeArr.indexOf(key) !== -1) {
+              this.voteOptionsContent[codeArr.indexOf(key)].value = html
+            } else { // 否则创建新选项
+              let option = {
+                code: key,
+                value: html
+              }
+              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 {
+        this.$Message.warning(this.$t('vote.form.optionNumsTip'))
+      }
+    },
+  },
+  watch: {
+  },
+  mounted() {
+    let descriptionEditor = new E(this.$refs.descriptionEditor)
+    descriptionEditor.config.onchange = (html) => {
+      this.voteForm.description = html
+    }
+    descriptionEditor.config.height = 200//重要
+    this.$editorTools.initSimpleEditor(descriptionEditor, this)
+    descriptionEditor.create()
+    this.descriptionEditor = descriptionEditor
+    
+    this.voteOptions = [...new Array(2).keys()]
+    this.initEditors()
+  },
+  computed: {
+    isAreaVote() {
+      return this.$route.name === 'manageAreaVote'
+    },
+  },
+}
+</script>
+<style lang="less" scoped>
+@import "./Resources.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 60 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/C_CloudContent.vue

@@ -0,0 +1,60 @@
+<template>
+  <div class="CloudContent-container">
+    <div style="overflow:hidden;">
+      <NewChooseContent :showSyllabus="false" ref="chooseContentRef"
+        :showContent="true" :showQuestion="false" 
+        :showPaper="false" :showOther="false"
+        :singleChoose="false" style="position: relative; top:-40px;"
+        @on-select-question="getSelectedQuestion" @on-cancel-question="cancelQuestion" 
+        @on-file-change="getSelectFile"></NewChooseContent>      
+    </div>    
+  </div>
+</template>
+<script>
+//import AddSyllabus from "./addSyllabus.vue"
+import NewChooseContent from '@/components/selflearn/NewChooseContent.vue'
+export default {
+  components: {
+    NewChooseContent,
+  },
+  props: { 
+  },
+  data() {
+    return {      
+      learnUnit: {//放資源
+        name: '',
+        resource: [],
+        item: []
+      },
+    }
+  },
+  computed: {
+  },
+  created() {    
+  },
+  methods: {
+    cancelQuestion(data) {
+      console.log("cancelQuestion");
+      this.learnUnit.item = data.questions 
+    },
+    getSelectedQuestion(data) {
+      console.log("getSelectedQuestion");
+      this.learnUnit.item = data
+    },
+    getSelectFile(data) {
+      console.log("getSelectFile");
+      console.log("data.files="+data.files);
+      this.learnUnit.resource = data.files
+    },
+  },
+  watch: {
+    
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./Resources.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 78 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/C_LocalFile.vue

@@ -0,0 +1,78 @@
+<template>
+  <div class="LocalFile-container">
+    <BaseUpload simpleUpload @uploadFinish="uploadFinish"></BaseUpload>
+    <div v-if="!attachmentsArr.length "
+      style="margin:-20px 10px 10px 10px;font-size:14px;font-weight:bold;">{{ $t('homework.noAttachments') }}</div>
+    <div v-if="attachmentsArr.length" class="attachments-list" style="margin:-20px 10px 10px 10px;">
+      <div class="attachments-item" v-for="(item,index) in attachmentsArr" :key="index">
+        <span class="name" >{{ item.name }}</span>
+        <span class="name">
+          <span style="margin-right: 10px;">{{ getSizeByBytes(item.size) }}</span>
+          <Icon type="md-close" color="#adadad" @click="removeAttachment(index)" />
+        </span>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+//程式碼參考:BaseHwForm.vue 如何存檔以及存到資料庫還尚未研究
+//import AddSyllabus from "./addSyllabus.vue"
+
+export default {
+  components: {
+
+  },
+  props: {
+  },
+  data() {
+    return {
+      attachmentsArr: [],
+      maxFileSize: 1024 * 1024 * 50,
+      previewFile: null,
+      previewStatus: false,
+    }
+  },
+  computed: {
+
+  },
+  created() {
+    
+  },
+  methods: {    
+    /* 上传本地文件成功回调 */
+    uploadFinish(file) {
+      console.log('file.name='+file.name);
+      console.log('file.type='+file.type);
+      console.log('file.size ='+file.size);
+      console.log('file.hash='+file.hash);
+      /*
+      if (this.attachmentsArr.length >= this.maxAttachmentCount) {
+        this.$Message.warning(this.$t('homework.countTip'))
+      } else*/
+      if (file.size > this.maxFileSize) {
+        this.$Message.warning(this.$t('homework.sizeTip'))
+      } else {
+        //file.name,file.type,file.hash
+        this.attachmentsArr.push(file)
+      }
+    },
+    /* 移除附件 */
+    removeAttachment(index) {
+      this.attachmentsArr.splice(index, 1)
+    },  
+    /* 根据字节数转换为大小 */
+    getSizeByBytes(bytes) {
+      return bytes / 1024 < 1024 ? (bytes / 1024).toFixed(1) + 'KB' : bytes / 1024 / 1024 < 1024 ? (bytes /
+        1024 / 1024).toFixed(1) + 'M' : (bytes / 1024 / 1024 / 1024).toFixed(1) + 'G'
+    },
+  },
+  watch: {
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./Resources.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 99 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/C_URL.vue

@@ -0,0 +1,99 @@
+<template>
+  <div class="URL-container">
+    <div style="margin:20px 10px 10px 10px;">{{ $t('syllabus.linkName') }}</div>
+    <Input v-special-char v-model="curLink.name" style="width:calc(100% - 20px); margin:0px 20px 0px 10px;"/>
+    <div style="margin:10px;">{{ $t('syllabus.linkUrl') }}</div>
+    <Input v-model="curLink.url" placeholder="" style="width:calc(100% - 20px); margin:0px 20px 10px 10px;"/>
+  </div>
+</template>
+<script>
+//參考Syllabus.vue 新增超链接资源弹窗
+//import AddSyllabus from "./addSyllabus.vue"
+
+export default {
+  components: {
+
+  },
+  props: {
+  },
+  data() {
+    return {
+      curLink: {
+        name: '',
+        link: ''
+      },
+    }
+  },
+  computed: {
+  },
+  created() {
+
+  },
+  methods: {
+    /* 添加超链接 */
+    onAddLink() {//按下確定按鈕後執行的程式 
+      console.log(this.$refs.treeRef.curData)
+      let curLink = this.curLink.url
+      if (!/^(http:|https:)/i.test(curLink)) {
+        curLink = "http://" + curLink;
+      }
+      if (!this.isURL(curLink)) {
+        this.$Message.warning(this.$t('evaluation.repairResourse.formatErrorTip'))
+        return
+      }
+      this.$refs.treeRef.curData.rnodes.push({
+        code: this.curCode,
+        scope: this.curScope,
+        id: this.$tools.guid(),
+        link: curLink,
+        title: this.curLink.name,
+        type: 'link',
+        ctnr: '',
+        hash: this.$tools.getStringMd5(curLink)
+      })
+      this.$refs.treeRef.curData.creatorId = this.curTeammodelId
+      this.$refs.treeRef.curData.creatorName = this.curName
+      this.modifyIdArr.push(this.curChapter.data.id)
+      //   this.hasModify = true
+      this.isShowLinkModal = false
+    },
+    /* 判断是否为正确的链接地址 */
+    isURL(url) {
+      const strRegex = '^((https|http|ftp)://)?' //(https或http或ftp):// 可有可无
+        +
+        '(([\\w_!~*\'()\\.&=+$%-]+: )?[\\w_!~*\'()\\.&=+$%-]+@)?' //ftp的user@ 可有可无
+        +
+        '(([0-9]{1,3}\\.){3}[0-9]{1,3}' // IP形式的URL- 3位数字.3位数字.3位数字.3位数字
+        +
+        '|' // 允许IP和DOMAIN(域名)
+        +
+        '(localhost)|' //匹配localhost
+        +
+        '([\\w_!~*\'()-]+\\.)*' // 域名- 至少一个[英文或数字_!~*\'()-]加上.
+        +
+        '\\w+\\.' // 一级域名 -英文或数字 加上.
+        +
+        '[a-zA-Z]{1,6})' // 顶级域名- 1-6位英文
+        +
+        '(:[0-9]{1,5})?' // 端口- :80 ,1-5位数字
+        +
+        '((/?)|' // url无参数结尾 - 斜杆或这没有
+        +
+        '(/[\\w_!~*\'()\\.;?:@&=+$,%#-]+)+/?)$'; //请求参数结尾- 英文或数字和[]内的各种字符
+      const re = new RegExp(strRegex, 'i'); // 大小写不敏感
+      if (re.test(encodeURI(url))) {
+        return true;
+      }
+      return false;
+    },
+  },
+  watch: {
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./Resources.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 454 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/Resources.less

@@ -0,0 +1,454 @@
+.div-center{//水平置中
+    display: flex; 
+    justify-content: center; 
+    text-align:center;
+    width:100%;
+}
+.div-centerY{//垂直置中
+    display: flex; 
+    align-items: center;  
+}
+.between{//分兩邊
+    display: flex;
+    justify-content: space-between;
+}
+.textBox{//對話框
+    width: 100%;
+    // color: #2d8cf0;
+    padding-left: 5px;
+    border: 1px solid #e8eaec;
+    border-radius: 5px;
+}
+.Evaluate-container{    
+    .evaluation-attr-wrap{
+        width: 40%;
+        margin-right: 10px;
+    }
+    .evaluation-question-wrap{
+        width: 60%;
+    }
+}
+.Homework-container{
+    .base-upload-container {
+        padding-bottom: 0px;
+    }
+}
+
+
+
+
+@main-bgColor: rgb(40, 40, 40);
+@borderColor: #424242;
+@primary-color: #70B1E7;
+@primary-textColor: #393939; //�ı�����ɫ
+@second-textColor: #636363; //�ı�������ɫ
+@primary-fontSize: 14px;
+@second-fontSize: 16px;
+
+/deep/ .ivu-tag {
+    border: none;
+    background: @primary-color;
+    height: 28px;
+    line-height: 28px;
+
+    i {
+        top: 8px;
+        color: #fff;
+    }
+
+    .ivu-tag-text {
+        color: #fff;
+    }
+}
+
+.Vote-container {
+    // padding: 0px 20px 0px 15px;
+    background-color: #fff;
+    
+    .image-viewer {
+        background-color: rgba(0, 0, 0, 0.8);
+        z-index: 9999;
+        width: 100%;
+        height: 100%;
+        position: fixed;
+        top: 0;
+        left: 0;
+        overflow-y: scroll;
+        overflow-x: hidden;
+        text-align: center;
+        /*display: flex;
+	    justify-content: center;
+	    align-items: center;*/
+        padding: 50px;
+        padding-top: 8%;
+
+        .close-icon {
+            position: absolute;
+            right: -16px;
+            top: -16px;
+            font-size: 24px;
+            color: black;
+            cursor: pointer;
+            border-radius: 50px;
+            background: white;
+            padding: 2px;
+        }
+    }
+    .ivu-form-item:not(:first-child) {
+        margin-top: 30px;
+    }
+
+    .ivu-form .btn-save {
+        width: 100%;
+        background: @primary-color;
+        border: none;
+        height: 38px;
+    }
+
+    .ivu-form .btn-reset {
+        width: 48%;
+        border: none;
+        height: 38px;
+        background-color: rgb(236, 236, 236);
+    }
+
+    .ivu-input::-webkit-input-placeholder {
+        color: #939393;
+    }
+
+    .ivu-input,
+    .ivu-select-single .ivu-select-selection,
+    .ivu-select-multiple .ivu-select-selection {
+        // border: 1px solid #c1c1c1;
+        margin-top: 10px;
+        height: 40px;
+        line-height: 40px;
+        padding-left: 8px;
+        /* color: @primary-textColor;
+		background-color: transparent; */
+    }
+
+    .ivu-input-number-input,
+    .ivu-input-number {
+        width: 100%;
+        padding-left: 10px;
+        height: 40px;
+        line-height: 40px;
+        color: @primary-textColor;
+
+        .ivu-input-number-handler-wrap {
+            background: none;
+            border: none;
+
+            .ivu-input-number-handler-down {
+                border-top: 1px solid #6f6f6f;
+            }
+
+            .ivu-input-number-handler {
+                height: 20px;
+
+                span {
+                    height: 20px;
+                    line-height: 20px;
+                }
+            }
+        }
+    }
+
+    .ivu-select-multiple .ivu-select-selection {
+        height: auto;
+    }
+
+    .ivu-tag {
+        border: none;
+        background: @primary-color;
+        height: 28px;
+        line-height: 28px;
+
+        i {
+            top: 8px;
+            color: #fff;
+        }
+
+        .ivu-tag-text {
+            color: #fff;
+        }
+    }
+
+    .ivu-select {
+        color: @second-textColor;
+    }
+
+    .ivu-input-prefix i,
+    .ivu-input-suffix i {
+        line-height: 60px;
+    }
+
+    .ivu-select-single .ivu-select-selection .ivu-select-placeholder,
+    .ivu-select-multiple .ivu-select-selection .ivu-select-placeholder,
+    .ivu-select-single .ivu-select-selection .ivu-select-selected-value {
+        height: 40px;
+        line-height: 40px;
+    }
+
+    .ivu-date-picker {
+        width: 100%;
+        margin-top: -20px;
+    }
+
+    .ivu-radio-wrapper,
+    .ivu-checkbox-wrapper {
+        color: @second-textColor;
+    }
+
+    .ivu-radio-wrapper:not(:first-child),
+    .ivu-checkbox-wrapper:not(:first-child) {
+        margin-left: 15px;
+    }
+
+    .ivu-radio-inner:after {
+        background: @primary-color;
+    }
+
+    .ivu-upload-drag {
+        margin-top: 10px;
+        border: 1px dashed #6c6e71;
+        color: @second-textColor;
+
+        .ivu-icon {
+            color: @primary-color;
+            font-weight: bold;
+        }
+    }
+
+    .ivu-checkbox-checked .ivu-checkbox-inner {
+        border-color: @primary-color;
+        background: @primary-color;
+    }
+
+    .ivu-upload-list-file,
+    .ivu-upload-list-file>span i {
+        color: @second-textColor;
+        margin-right: 5px;
+    }
+
+    .ivu-upload-list-file:hover {
+        span {
+            color: @second-textColor;
+        }
+    }
+
+    .ivu-upload-list-remove {
+        margin-top: 5px;
+        font-size: 22px;
+    }
+
+    .ivu-select-single .ivu-select-selection .ivu-select-placeholder {
+        color: #939393;
+    }
+
+    .w-e-toolbar {
+        margin-top: 10px;
+        z-index: 1 !important;
+    }
+
+    .w-e-text-container {
+        z-index: 0 !important;
+    }
+
+    .option-editor-wrap {
+        position: relative;
+        margin-top: 10px;
+
+        .option-order {
+            position: relative;
+            display: inline-flex;
+            justify-content: center;
+            align-items: center;
+            min-height: 42px;
+            width: 10%;
+            float: left;
+            // color: #a0a0a0;
+            background: var(--input-bg-color);
+
+            &:hover {
+                .ivu-icon {
+                    display: unset;
+                }
+            }
+
+            .ivu-icon {
+                position: absolute;
+                top: 50%;
+                left: 50%;
+                transform: translate(-50%, -50%);
+                font-size: 20px;
+                display: none;
+                cursor: pointer;
+            }
+        }
+
+        .option-editor {
+            position: relative;
+            display: inline-block;
+            // height: 42px;
+            // border: none;
+            width: 90%;
+            border:1px solid rgba(204, 204, 204, 0.49);
+        }
+
+        .w-e-text-container {
+            height: auto !important;
+            z-index: 0 !important;
+        }
+
+        .w-e-toolbar {
+            position: absolute;
+            top: -50px;
+            left: 0px;
+            visibility: hidden;
+            font-size: 12px;
+            width: 100%;
+        }
+    }
+
+    .vote-form-disabled {
+
+        .ivu-input,
+        .ivu-select-single .ivu-select-selection,
+        .ivu-select-selection,
+        .ivu-date-picker-focused input {
+            background: transparent;
+            border: none;
+            font-size: @second-fontSize;
+            font-weight: bold;
+            box-shadow: none;
+        }
+
+        .ivu-icon {
+            display: none !important;
+        }
+
+        .ivu-select-multiple .ivu-tag span:not(.ivu-select-max-tag) {
+            margin-right: 10px;
+        }
+
+
+    }
+
+    .ivu-input-number-disabled {
+        background-color: transparent !important;
+        border: none !important;
+
+        .ivu-input-number-input {
+            background-color: transparent !important;
+        }
+    }
+}
+
+.Questionnaire-container{
+    .body{
+        width:100%;
+        .left{
+            float:left;
+            width: 50%;
+            padding: 10px;
+        }
+        .right{
+            float:right;
+            width: 50%;
+            overflow-y: auto;
+            
+            .contect{
+                float: unset;
+                height: 470px;
+                padding-top: 10px;
+                overflow-y: auto;
+                .component-questionnaire{
+                    min-height: 30vh;
+                    padding-bottom:0px;
+                    height:unset;
+                }
+            }
+            
+        }
+    }
+    .qn-col {
+		height: 100%;
+		overflow: hidden;
+
+		.qn-box-header {
+			height: 45px;
+			line-height: 45px;
+			padding: 0 15px;
+			// font-weight: bold;
+			// border-bottom: 1px solid @borderColor;
+			display: flex;
+			justify-content: space-between;
+
+			&-tab {
+				margin-right: 25px;
+				cursor: pointer;
+				color: #909090;
+			}
+
+			&-tab-active {
+				border-bottom: 2px solid var(--tabs-bottom-color);
+				padding-bottom: 5px;
+				color: var(--tabs-text-color);
+				font-weight: bold;
+			}
+
+			.qn-box-header-tools {
+				display: flex;
+
+				&-tool {
+					cursor: pointer;
+					font-weight: 500;
+					color: #40A8F0;
+
+					.ivu-btn:before {
+						background-color: none;
+					}
+				}
+
+				.ivu-icon {
+					font-size: 16px;
+					margin-right: 5px;
+					vertical-align: sub;
+				}
+
+				.ivu-dropdown-rel {
+					display: flex;
+					align-items: center;
+
+					.ivu-btn {
+						padding: 0;
+					}
+				}
+
+				.ivu-btn {
+					background: transparent;
+					border: none;
+					padding: 0 10px;
+					color: #40A8F0;
+
+					&::before {
+						background-color: none;
+					}
+
+					&:focus {
+						border: none;
+					}
+
+					.ivu-icon {
+						font-size: 16px;
+					}
+				}
+
+			}
+		}
+	}
+    
+
+}

+ 192 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/Resources/part/BaseQnForm.vue

@@ -0,0 +1,192 @@
+<template>
+  <div class="Questionnaire-container">
+    <Loading :top="200" bgColor="rgba(103, 103, 103, 0.27)" type="1" v-show="isLoading"></Loading>
+    <div class="">
+      <Form ref="qnForm" :model="qnForm" label-position="top" :rules="ruleValidate">
+        <FormItem :label="$t('survey.form.name')" prop="name">
+          <Input v-special-char class="qn-form-disabled" v-model="qnForm.name"
+            :placeholder="$t('survey.form.namePlace')"></Input>
+        </FormItem>
+        <FormItem :label="$t('vote.form.other')" prop="publishModel">
+          <Checkbox v-model="allowModify" style="margin:0 5px"> {{ $t('survey.questionaire.allowModify') }}</Checkbox>
+        </FormItem>
+        <FormItem :label="$t('survey.form.description')" prop="description">
+          <div ref="descriptionEditor" style="text-align:left"></div>
+        </FormItem>
+      </Form>
+    </div>
+  </div>
+</template>
+<script>
+import E from 'wangeditor'
+export default {
+  components: {
+  },
+  props: {
+  },
+  data(vm) {
+    return {
+      allowModify: false,
+      descriptionEditor: null,
+      qnForm: {
+        name: '',
+        classes: [],
+        publishModel: 0,
+        rangeTime: [],
+        description: '',
+        isReset: [],
+        other: []
+      },
+      ruleValidate: {
+        name: [{
+          required: true,
+          message: vm.$t('survey.form.ruleName'),
+          trigger: 'blur'
+        }],
+      },
+      isLoading: false,
+      isBtnLoading: false,
+    }
+  },
+  mounted() {
+    /** 初始化问卷详情的富文本编辑器 */
+    let descriptionEditor = new E(this.$refs.descriptionEditor)
+    descriptionEditor.config.onchange = (html) => {
+      this.qnForm.description = html
+    }
+    descriptionEditor.config.height = 200//重要
+    this.$editorTools.initSimpleEditor(descriptionEditor, this)
+    descriptionEditor.create()
+    this.descriptionEditor = descriptionEditor
+  },
+  computed: {
+    isAreaSurvey() {
+      return this.$route.name === 'manageAreaQuestionnaire'
+    },
+  },
+  created() {
+
+  },
+  methods: {
+    
+    /**
+     * 提交新增问卷表单
+     * @param name FormName
+     */
+    handleSubmit(name) {
+      return new Promise((resolve, reject) => {
+        this.$refs[name].validate((valid) => {
+          // let hasTargets = (!this.isAreaSurvey && this.qnForm.classes.length) || (this.isAreaSurvey && this.schoolTarget.length)
+          let hasTargets = this.$refs.classSelectRef.targetType === 'research' ? this.$refs.classSelectRef.groupArr.length : this.$refs.classSelectRef.defaultArr.length
+          if (valid && this.getSimpleText(this.qnForm.description) && hasTargets) {
+            let params = JSON.parse(JSON.stringify(this.defaultParams))
+            let areaParams = null
+            let target = []
+            let classSelectScope = this.isAreaSurvey ? 'school' : this.$refs.classSelectRef.evaluationInfo.scope
+            let isSchoolClass = this.isAreaSurvey ? false : this.$refs.classSelectRef.evaluationInfo.scope ===
+              'school' && this.$refs.classSelectRef.privateClassType === 'school'
+            let isPersonal = this.$route.name === 'personalSurvey' && classSelectScope ===
+              'private'
+            let isSchool = this.$route.name === 'manageQuestionnaire'
+            params.code = this.getCurCode
+            // 如果个人问卷的班级是校本班级 那么也要把scope置为school
+            params.scope = isPersonal ? 'private' : 'school'
+            params.name = this.qnForm.name
+            params.description = this.qnForm.description
+            params.targets = this.qnForm.targets
+            params.isSub = this.allowModify ? 1 : 0
+            // 新增参数
+            params.owner = this.$route.name === 'personalSurvey' ? 'teacher' : 'school'
+            params.creatorId = this.$store.state.userInfo.TEAMModelId
+            params.school = params.scope === 'school' ? this.$store.state.userInfo
+              .schoolCode : null
+
+            params.tchLists = []
+            params.classes = []
+            params.stuLists = []
+            // 如果是编辑状态 则直接复制ID 如果是新增 则直接赋值新ID
+            if (this.isEdit && this.editInfo.id && this.editInfo.code) {
+              params.id = this.editInfo.id
+              params.createTime = this.editInfo.createTime
+            } else {
+              params.id = this.$tools.guid()
+            }
+
+            // 如果是发布的区级投票 则需要修改保存参数
+            if (this.isAreaSurvey) {
+              let schArr = [...new Set(this.schoolTarget.map(i => i[0]))]
+              let para = []
+              schArr.forEach((i, index) => {
+                para.push({
+                  sId: i,
+                  sName: this.schList.find(j => j.id === i).sname,
+                  gName: [],
+                  gId: []
+                })
+                // 如果是区级活动 需要拼接学校加教研组信息
+                this.schoolTarget.forEach(j => {
+                  if (j[0] === i) {
+                    let groupName = j[1].split('-')[1]
+                    if (groupName === '所有老师(未分组)') {
+                      para[index].gName = []
+                      para[index].gId = ['default']
+                    } else {
+                      let curSch = this.schList.find(sch => sch.id === i)
+                      let groupId = curSch.gId[curSch.name.indexOf(groupName)]
+                      para[index].gName.push(groupName)
+                      para[index].gId.push(groupId)
+                    }
+                  }
+                })
+              })
+              delete this.qnForm.classes
+              delete this.qnForm.targets
+              delete this.qnForm.teachers
+              delete this.qnForm.stuLists
+              areaParams = {
+                "id": this.areaId,
+                "para": para,
+                "survey": params
+              }
+            } else {
+              // 如果是校本投票 则需要进一步确定发布对象是教研组还是学生名单
+              if (isSchool && this.$refs.classSelectRef.targetType === 'research') {
+                params.tchLists = this.qnForm.classes
+                params.targetType = 'research'
+              } else if (isSchoolClass) {
+                params.classes = this.qnForm.classes
+                params.targetType = 'student'
+              } else {
+                params.stuLists = this.qnForm.classes
+                params.targetType = 'student'
+              }
+            }
+            let finalParams = this.isAreaSurvey ? areaParams : params
+            console.log(finalParams)
+            resolve(finalParams)
+          } else {
+            this.$emit('onAddFail')
+            if (!hasTargets) {
+              this.$Message.error(this.$t('survey.form.ruleClasses'))
+            } else if (!this.getSimpleText(this.qnForm.description)) {
+              this.$Message.error(this.$t('survey.form.ruleDescription'))
+            } else {
+              this.$Message.error(this.$t('survey.form.noCompleteTip'))
+            }
+            reject(500)
+          }
+        })
+      })
+    },
+    
+  },
+  watch: {
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "../Resources.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 52 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/SyllabusAdd.vue

@@ -0,0 +1,52 @@
+<template>
+  <div class="SyllabusAdd-container">
+    <Modal v-model="DialogBoxAddBtn" title="新增課綱" @on-ok="ok" @on-cancel="cancel"
+      :width="750">
+      <AddSyllabus ref="addSyllabus" class="RadioGroup" :addBtnCtl="false"></AddSyllabus>
+      <span class="gray-font mleft20">※貼代碼與選擇課綱所新增的課綱『不同步』於來源課綱,若要同步,請在『來源課綱』設定同步對象!</span>
+    </Modal>    
+  </div>
+</template>
+<script>
+//import AddSyllabus from "./addSyllabus.vue"
+import AddSyllabus from "../addSyllabus.vue"
+export default {
+  components: {
+    AddSyllabus,
+  },
+  props: {
+    AddCtl: Boolean,    
+  },
+  data() {
+    return {
+      DialogBoxAddBtn:false,
+    }
+  },
+  computed: {
+  },
+  created() {
+    
+  },
+  methods: {
+    ok() {
+      // this.$Message.info('Clicked ok');
+      this.$refs.addSyllabus.addSyllabusFun();
+      this.$emit('AddClose',false);
+    },
+    cancel() {
+      this.$emit('AddClose',false);
+    },
+  },
+  watch: {
+    AddCtl(newVal) {
+      this.DialogBoxAddBtn= newVal;
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./DialogBox.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 103 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/SyllabusSorting.vue

@@ -0,0 +1,103 @@
+<template>
+  <div class="SyllabusSorting-container">
+    <Modal v-model="SortingBtn" title="課綱排序" @on-ok="ok" @on-cancel="cancel"
+      class="SyllabusSorting-div">
+      ※拖曳可排序
+      <div class="SortingDiv">
+        <div v-for="(item,index) in syllabusList" :key="item.id" class="itemCard"
+          draggable="true"
+          @dragstart="dragStart($event, index)" @dragover="allowDrop" 
+          @drop="drop($event, index)" @dragend="dragEnd">
+          <Icon v-if="item.type ==='share'" type="md-people" size="25" />
+          <Icon v-if="item.type ==='link'" type="ios-link" size="25" />
+          {{ item.name }}
+        </div>
+      </div>      
+    </Modal>
+  </div>
+</template>
+<script>
+//import AddSyllabus from "./addSyllabus.vue"
+
+export default {
+  components: {
+
+  },
+  props: {
+    SortingCtl: Boolean,    
+  },
+  data() {
+    return {
+      SortingBtn:false,
+      syllabusList: [//share同步他人,link被同步
+        {id: 'a1',sort:1,name: '數學一年級上學期課綱(1)',type:'share'},
+        {id: 'b2',sort:2,name: '數學二年級上學期課綱(2)',type:'link'},
+        {id: 'c3',sort:3,name: '數學三年級上學期課綱(3)',type:''},
+        {id: 'a4',sort:4,name: '數學一年級上學期課綱(4)',type:'share'},
+        {id: 'b5',sort:5,name: '數學二年級上學期課綱(5)',type:'link'},
+        {id: 'c6',sort:6,name: '數學三年級上學期課綱(6)',type:''},
+        {id: 'a7',sort:7,name: '數學一年級上學期課綱(7)',type:'share'},
+        {id: 'b8',sort:8,name: '數學二年級上學期課綱(8)',type:'link'},
+        {id: 'c9',sort:9,name: '數學三年級上學期課綱(9)',type:''},
+        {id: 'a10',sort:10,name: '數學一年級上學期課綱(10)',type:'share'},
+        {id: 'b20',sort:11,name: '數學二年級上學期課綱(11)',type:'link'},
+        {id: 'c30',sort:12,name: '數學三年級上學期課綱(12)',type:''},
+      ],
+    }
+  },
+  computed: {
+  },
+  created() {
+    
+  },
+  methods: {
+    ok() {
+      // this.$Message.info('Clicked ok');
+      this.$emit('SortingClose',false);
+    },
+    cancel() {
+      this.$emit('SortingClose',false);
+    },
+    //拖曳相關--str---↓↓--
+    allowDrop(e) {//取消默認行為
+      e.preventDefault();
+    },
+    dragStart(e, index) {//拖曳開始
+      let tar = e.target;
+      e.dataTransfer.setData('Text', index);
+      if (tar.tagName.toLowerCase() == 'li') {
+        // console.log('drag start')
+        // console.log('drag Index: ' + index)
+      }
+    },
+    drop(e, index) {//放置
+      this.allowDrop(e);
+      let arr = this.syllabusList.concat([]),
+      dragIndex = e.dataTransfer.getData('Text');
+      let temp = arr.splice(dragIndex, 1);  
+      arr.splice(index, 0, temp[0]);
+      this.syllabusList = arr;
+
+      //↓改正syllabusList資料的sort
+      for (let i = 0; i < this.syllabusList.length; i++) {
+        this.syllabusList[i].sort = i+1;
+      }   
+    },
+    dragEnd() {//放置結束
+      console.log("dragEnd");
+    },
+    //拖曳相關--end---↑↑--
+  },
+  watch: {
+    SortingCtl(newVal) {
+      this.SortingBtn= newVal;
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./DialogBox.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 90 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/DialogBox/SyncClass.vue

@@ -0,0 +1,90 @@
+<template>
+  <div class="SyncClass-container">
+    <Modal v-model="SyncClassBtn" title="同步對象" @on-ok="ok" @on-cancel="cancel">
+      <div class="showClass-div">
+        本班:
+        <span  class="showClass">
+          七年四班
+        </span>
+      </div>
+      <Transfer :data="data" :target-keys="targetKeys" 
+        @on-change="handleChange"></Transfer>
+    </Modal>
+  </div>
+</template>
+<script>
+//import AddSyllabus from "./addSyllabus.vue"
+
+export default {
+  components: {
+
+  },
+  props: {
+    SyncClassCtl: Boolean,    
+  },
+  data() {
+    return {
+      SyncClassBtn:false,
+      data: [//本班不在選項內
+        { key: 1, label: "一年二班"},
+        { key: 2, label: "9A"},
+        { key: 3, label: "2021級2班"},
+        { key: 4, label: "七年四班"},
+        { key: 5, label: "七年一班"},
+        { key: 6, label: "七年七班"},
+      ],
+      targetKeys: [1, 3,4],
+      targetKeysTemp:[1, 3,4],//儲存未存檔的內容
+    }
+  },
+  computed: {
+  },
+  created() {
+    
+  },
+  methods: {
+    ok() {
+      // this.$Message.info('Clicked ok');
+      this.$emit('SyncClassClose',false);
+    },
+    cancel() {
+      this.targetKeys = this.targetKeysTemp;
+      this.$emit('SyncClassClose',false);
+    },
+    handleChange(newTargetKeys, direction, moveKeys) {
+      if(direction == 'left'){
+        this.$Modal.confirm({
+            title: '你確定要取消同步嗎?',
+            content: '<p>一旦取消同步,雖然分享的班級課綱會保留,但保留的課綱將無法重新與本課綱同步。</p>',
+            onOk: () => {
+                this.$Message.info('Clicked ok');
+                this.changeToTemp(newTargetKeys);
+            },
+            onCancel: () => {
+                this.$Message.info('Clicked cancel');
+            }
+        });
+      }
+      console.log(newTargetKeys);
+      console.log(direction);
+      console.log(moveKeys);
+      
+    },
+    changeToTemp(newTargetKeys){
+      this.targetKeysTemp = this.targetKeys;
+      this.targetKeys = newTargetKeys;
+    }
+  },
+  watch: {
+    SyncClassCtl(newVal) {
+      this.SyncClassBtn= newVal;
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./DialogBox.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 14 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusIndex.less

@@ -0,0 +1,14 @@
+.stu-action-wrap{
+    position: absolute;
+    right: 20px;
+    top: 7px;
+}
+
+.changePage-body{
+    margin: 40px;
+    .title{
+        font-size: 20px;
+        font-weight:bold;
+        margin-bottom: 10px;
+    }
+}

+ 137 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusIndex.vue

@@ -0,0 +1,137 @@
+<template>
+  <div class="SyllabusIndex-container">
+    <div v-if="changePage == 'mainPage'" class="stu-action-wrap common-save-btn"><!--右上角:更多功能下拉選單-->
+      <Dropdown style="margin-top:5px;margin-right:8px">
+        <a href="javascript:void(0)">
+          {{$t('cusMgt.moreFn')}}
+          <Icon type="ios-arrow-down"></Icon>
+        </a>
+        <DropdownMenu slot="list">
+          <DropdownItem @click.native="SortingCtl=true">
+            <span class="action-item">
+              <Icon type="md-settings" />
+              {{$t('cusMgt.cusTab14')}}
+            </span>
+          </DropdownItem>
+          <DropdownItem @click.native="AddCtl=true">
+            <span class="action-item">
+              <Icon type="md-add" />
+              {{$t('cusMgt.cusTab15')}}
+            </span>
+          </DropdownItem>
+        </DropdownMenu>
+      </Dropdown>
+    </div>
+    <div class="changePage-body" v-if="changePage == 'AddSyllabus'">
+      <div class="title">新增課綱</div>
+      <AddSyllabus  class="RadioGroup" :addBtnCtl="true"></AddSyllabus>
+    </div>
+    <div v-else-if="changePage == 'mainPage'" style="display: flex; ">
+      <SyllabusMenu :gradeParams="gradeParams" :grouplistId="grouplistId" :listType="listType" @PageData="PageDatafun"
+        :PageData="PageData"></SyllabusMenu>
+      <SyllabusResource v-if="PageData.mode==='Resource' || PageData.level === 'Title'" 
+        :PageData="PageData" :getResourceImage="getResourceImage">
+      </SyllabusResource>
+      <SyllabusSchedule v-else-if="PageData.mode==='Schedule' && PageData.level !== 'Title'" 
+        :PageData="PageData" :getResourceImage="getResourceImage">
+      </SyllabusSchedule>      
+    </div>
+    <SyllabusSorting :SortingCtl="SortingCtl" @SortingClose="SortingCtl=false"></SyllabusSorting>
+    <SyllabusAdd :AddCtl="AddCtl" @AddClose="AddCtl=false"></SyllabusAdd>
+  </div>
+</template>
+<script>
+import AddSyllabus from "./addSyllabus.vue"
+import SyllabusMenu from "./SyllabusMenu.vue"
+import SyllabusResource from "./SyllabusResource.vue"
+import SyllabusSchedule from "./SyllabusSchedule.vue"
+import SyllabusSorting from "./DialogBox/SyllabusSorting.vue"
+import SyllabusAdd from "./DialogBox/SyllabusAdd.vue"
+export default {
+  components: {
+    AddSyllabus, SyllabusMenu, SyllabusResource, SyllabusSchedule,SyllabusSorting,SyllabusAdd
+  },
+  props: {
+    //收藏id,双向绑定
+    value: {
+      default: () => {
+        return []
+      },
+    },
+    gradeParams: {
+      type: Object,
+      default: () => {
+        return []
+      }
+    },
+    grouplistId: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    listType: {
+      type: String,
+      default: () => {
+        return {}
+      }
+    },
+  },
+  data() {
+    return {
+      changePage: "mainPage",
+      //PageData:{mode:Resource資源/Schedule進度,level:Title標題,Chapter章節,Section資源卡片
+      PageData: { id: 1, mode: 'Resource', level: 'Title', 
+        data: { Title: '數學一年級上學期課綱(1)',Chapter:'',Section:'',type:'' } 
+      },
+      SortingCtl:false,//排序跳窗
+      AddCtl:false,//新增跳窗
+    }
+  },
+  computed: {
+  },
+  created() {
+  },
+  methods: {
+    PageDatafun(newValue) {
+      this.PageData = newValue;
+    },
+    getResourceImage(type) {// 將資源類型對應到圖像文件
+      const imageMap = {
+        image: require("../../../assets/source/image.png"),
+        doc: require("../../../assets/source/word.png"),
+        excel: require("../../../assets/source/excel.png"),
+        ppt: require("../../../assets/source/ppt.png"),
+        pdf: require("../../../assets/source/pdf.png"),
+        video: require("../../../assets/source/video.png"),
+        audio: require("../../../assets/source/audio.png"),
+        item: require("../../../assets/source/item.png"),
+        paper: require("../../../assets/source/folder.png"),
+        link: require("../../../assets/source/link.png"),
+        zip: require("../../../assets/source/zip.png"),
+        other: require("../../../assets/source/unknow.png"),
+      };    
+      return imageMap[type];
+    },
+  },
+  watch: {
+    grouplistId: {
+      deep: true,
+      immediate: true,
+      handler(n, o) {
+        this.tableInfo = {};//AddSyllabus、mainPage
+        this.changePage = "mainPage";//若在第二頁去,只要重新點選課程,一律跳回第一頁
+      }
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./SyllabusIndex.less";
+.SyllabusIndex-container {
+  height: 100%;
+}
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 90 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusMenu.less

@@ -0,0 +1,90 @@
+.div-center{//水平置中
+    display: flex; 
+    justify-content: center; 
+    text-align:center;
+    width:100%;
+}
+.div-centerY{//垂直置中
+    display: flex; 
+    align-items: center;  
+}
+.pointer{//使其滑鼠滑入有小手可點
+    cursor: pointer;
+}
+.SyllabusBody-container{
+    background-color: #f2f2f2;
+    width: 300px;
+    height: calc(100vh - 140px); /* 將高度設置為視窗高度的 80% */
+    margin-top: 0px;
+    padding: 15px 10px 50px 10px;
+    overflow: auto;
+    
+    .title{
+        display: flex; 
+        align-items: center; 
+        // justify-content: space-between;
+
+        /deep/.ivu-select-selection {
+            border: none;
+            border-bottom: 1px solid transparent; /* 可以保留一個底線,可視情況調整顏色 */
+            border-radius: 0; /* 可以移除底線下方的角落 */
+            background-color: transparent; /* 設定背景色為透明 */      
+            font-weight: bold;
+        }
+        /deep/.ivu-select-selected-value {
+            font-size: 16px ;  
+        }
+    }
+    .modelctl{
+        display: flex;
+        justify-content: space-between;
+        .switch-location {
+            margin-right: auto; /* 使靠右方 */
+            margin-top: auto; /* 使自動靠下 */
+            display: flex;
+            align-items: center; //垂直置中
+            .txt{
+                font-size: 10px;
+            }
+        }
+        .poptip{
+            text-align: center;
+        }
+    }
+    .group{
+        cursor: pointer;
+        background-color: #dcdee2;
+        padding:2px 10px;
+        margin: 5px 2px;
+        display: flex;
+        justify-content: space-between;
+        align-items: center; //垂直置中
+
+        .icon1{            
+            margin-right: 5px;
+        }
+    }
+    .card{
+        cursor: pointer;
+        background-color: white;
+        width: 95%;
+        margin: 7px 2.5%;
+        min-height: 50px;
+        border-radius: 10px;
+        padding: 10px;
+        font-weight: bold; 
+        display: flex;
+        justify-content: space-between;
+    }
+    .card:hover,.addCard:hover{
+        border: 2px solid #2b85e4;
+    }    
+    .addCard{
+        cursor: pointer;
+        background-color: white;
+        width: 100%;
+        margin-top: 15px;
+        border-radius: 10px;
+        padding: 5px;
+    }
+}

+ 203 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusMenu.vue

@@ -0,0 +1,203 @@
+<template>
+  <div class="SyllabusBody-container">
+    <div class="title" @click="cardClick(chooseOne.id,'Title')">
+      <Icon v-if="chooseOne.type === 'share'" type="md-people" size="25" />
+      <Icon v-if="chooseOne.type === 'link'" type="ios-link" size="25" />
+      <!-- <Icon v-else type="" size="25" /> -->
+      <Select v-model="chooseOne.id" style="width:250px;" @on-change="selectSyllabus">
+        <Option v-for="item in syllabusList" :value="item.id" :key="item.id">
+          <Icon v-if="item.type ==='share'" type="md-people" size="25" />
+          <Icon v-if="item.type ==='link'" type="ios-link" size="25" />
+          {{ item.name }}
+        </Option>
+      </Select>
+    </div>
+    <div class="modelctl">
+      <div class="switch-location">
+        <span class="txt">資源/進度</span>
+        <i-Switch v-model="modeValue" size="small" @on-change="switchFun" />
+      </div>
+      <div class="poptip">
+        <Poptip title="課綱代碼" content="content" placement="bottom" v-model="poptipShow">
+          <Icon type="md-share" size="20" class="pointer" />
+          <template #content>
+            B148942356 
+            <Button type="primary" @click="poptipFun">複製</Button>
+          </template>
+        </Poptip>
+      </div>
+    </div>
+    <div v-for="(list,listIndex) in cardData" :key="list.id"><!--↓章節+資源卡片↓-->
+      <div class="group" @click="cardClick(list.id,'Chapter',list.type,list.name)" draggable="true"
+        @dragstart="dragStart($event, listIndex, 'Chapter')" @dragover="allowDrop" @drop="ChapterDrop($event, listIndex)"
+        @dragend="dragEnd"><!--↓章節↓-->
+        {{list.name}}
+        <div>
+          <Icon v-if="!modeValue && list.type==='order'" type="md-git-pull-request" size="20" class="icon1" />
+          <Icon v-if="list.btn" type="md-arrow-dropdown" size="20" @click.stop="list.btn=false" />
+          <Icon v-else type="md-arrow-dropup" size="20" @click.stop="list.btn=true" />
+        </div>
+      </div>
+      <div v-if="list.btn"><!--↓資源卡片↓-->
+        <div class="card div-centerY" v-for="(Resource,resourceIndex) in list.item" :key="Resource.id"
+          @click="cardClick(Resource.id,'Section',Resource.type,list.name,Resource.name)" draggable="true"          
+          @dragstart="dragStart($event, resourceIndex, 'Section', listIndex)" 
+          @dragover="allowDrop" @drop="SectionDrop($event, resourceIndex, 'Section', listIndex)"
+          @dragend="dragEnd" >
+          {{Resource.name}}
+          <div>
+            <div v-if="modeValue">100%</div>
+            <Icon v-else-if="!modeValue && Resource.type==='order'" type="md-git-pull-request" size="20"
+              class="icon1" />
+          </div>
+        </div>
+      </div>
+    </div>
+    <div v-if="chooseOne.type !== 'link'" class="addCard div-centerY div-center" @click="addCradBtn=true">
+      <Icon type="md-add-circle" :size="25" />
+    </div>
+    <AddCard :DialogBoxCtl="addCradBtn" :chooseOne="chooseOne" :cardData="cardData" @DialogBoxClose="addCradBtn=false">
+    </AddCard>
+  </div>
+</template>
+<script>
+import AddCard from "./DialogBox/AddCard.vue"
+export default {
+  components: {
+    AddCard
+  },
+  props: {
+    //收藏id,双向绑定
+    value: {
+      default: () => {
+        return []
+      },
+    },
+    gradeParams: Object,
+    grouplistId: Object,
+    listType: String,
+    PageData: Object,
+  },
+  data() {
+    return {
+      tableHeight: 0,//容器高度
+      addCradBtn: false,//新增卡片的跳窗
+      chooseOne: { id: 'a1', type: 'share', name: '數學一年級上學期課綱(1)', typeIcon: '' },
+      syllabusList: [//share同步他人,link被同步
+        { id: 'a1', name: '數學一年級上學期課綱(1)', type: 'share' },
+        { id: 'b2', name: '數學二年級上學期課綱(2)', type: 'link' },
+        { id: 'c3', name: '數學三年級上學期課綱(3)', type: '' },
+      ],
+      modeValue: false,//目前的模式
+      cardData: [//章節與資源卡片的data
+        //type:all全部一覽、order依序一覽
+        {
+          id: 1, sort: 1, name: '第一章節', btn: true, type: 'order', item: [{ id: 11, sort: 1, name: '四則運算', type: 'all' },
+          { id: 12, sort: 2, name: '加法與減法', type: 'all' }, { id: 13, sort: 3, name: '乘法', type: 'order' }]
+        },
+        { id: 2, sort: 2, name: '第二章節', btn: true, type: 'all', item: [{ id: 21, sort: 1, name: '幾何圖形', type: 'order' },] },
+        { id: 3, sort: 3, name: '第3章節', btn: true, type: 'order', item: [{ id: 31, sort: 1, name: '幾何圖形3', type: 'all' },] },
+        { id: 4, sort: 4, name: '第4章節', btn: true, type: 'all', item: [{ id: 41, sort: 1, name: '幾何圖形4', type: 'all' },] },
+        { id: 5, sort: 5, name: '第5章節', btn: true, type: 'all', item: [{ id: 51, sort: 1, name: '幾何圖形5', type: 'order' },] },
+      ],
+      poptipShow: false,//分享窗開關
+      dragItemId: null,
+    }
+  },
+  computed: {
+  },
+  created() {
+  },
+  mounted() {
+  },
+  methods: {
+    selectSyllabus(index) {
+      this.chooseOne.id = index;
+      this.chooseOne.type = this.syllabusList.find(item => item.id === index).type;
+      this.chooseOne.name = this.syllabusList.find(item => item.id === index).name;
+      this.PageData.data.Title = this.syllabusList.find(item => item.id === index).name;
+      this.PageData.type = this.chooseOne.type;
+      this.$emit('PageData', this.PageData);
+    },
+    switchFun() {
+      this.PageData.mode = this.modeValue ? 'Schedule' : 'Resource';
+      this.$emit('PageData', this.PageData);
+    },
+    cardClick(id, level, type, Chapter, Section) {
+      let mode = this.modeValue ? 'Schedule' : 'Resource';
+      let mydata = { Title: this.chooseOne.name, Chapter: Chapter, Section: Section, type: type };
+      //{id:id,mode:mode,level:level,type:是否是被同步的狀態,data:mydata})
+      this.$emit('PageData', { id: id, mode: mode, level: level, type: this.chooseOne.type, data: mydata });
+    },
+    poptipFun() {
+      this.poptipShow = this.poptipShow === true ? false : true;
+      this.$Message.success('已複製');
+    },
+    //拖曳相關--str---↓↓--
+    allowDrop(e) {//取消默認行為
+      e.preventDefault();
+    },
+    dragStart(e, index, type, chapterIndex = null) {//拖曳開始
+      e.dataTransfer.setData('Text', JSON.stringify({ index, type, chapterIndex }));
+    },
+    ChapterDrop(e, listIndex) {//章節放置
+      this.allowDrop(e);
+      const data = JSON.parse(e.dataTransfer.getData('Text'));
+      const { index, type, chapterIndex } = data;
+
+      if(type==='Chapter'){//章節與章節換
+        let arr = this.cardData.concat([]);
+        let temp = arr.splice(index, 1);
+        arr.splice(listIndex, 0, temp[0]);
+        this.cardData = arr;        
+        this.updateSort();// 更新排序
+      }else if(type==='Section'){//資源卡片與章節換
+        const sourceChapter = this.cardData[chapterIndex];
+        const movedResource = sourceChapter.item.splice(index, 1)[0];
+        const targetChapter = this.cardData[listIndex];
+        targetChapter.item.splice(0, 0, movedResource);
+        this.updateSort();
+      }      
+    },
+    SectionDrop(e, targetIndex, targetType, targetChapterIndex = null) {//資源小節放置
+      this.allowDrop(e);
+      const data = JSON.parse(e.dataTransfer.getData('Text'));
+      const { index, type, chapterIndex } = data;
+      if (type === 'Section') {
+        // 处理资源拖拽
+        const sourceChapter = this.cardData[chapterIndex];
+        const movedResource = sourceChapter.item.splice(index, 1)[0];
+        const targetChapter = this.cardData[targetChapterIndex];
+        targetChapter.item.splice(targetIndex, 0, movedResource);
+      }      
+      this.updateSort();// 更新排序
+    },
+    updateSort() {// 更新排序
+      this.cardData.forEach((chapter, chapterIndex) => {
+        chapter.sort = chapterIndex + 1;
+        chapter.item.forEach((resource, resourceIndex) => {
+          resource.sort = resourceIndex + 1;
+        });
+      });
+    },
+    dragEnd() {//放置結束
+      //console.log("dragEnd");
+    },  
+    //拖曳相關--end---↑↑--
+  },
+  watch: {
+    grouplistId: {
+      deep: true,
+      immediate: true,
+      handler(n, o) {
+      }
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./SyllabusMenu.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 146 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusResource.less

@@ -0,0 +1,146 @@
+
+.between{//分兩邊
+    display: flex;
+    justify-content: space-between;
+}
+.center {//中心
+    text-align: center;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+.pointer{//使其滑鼠滑入有小手可點
+    cursor: pointer;
+}
+
+.SyllabusResource-container
+{
+    width: calc(100% - 300px);
+    padding: 10px;
+
+    .SaveDelDiv
+    {
+        .ivu-btn
+        {
+            margin-left: 10px;
+        }
+        .saveDiv
+        {
+            width: 100%;
+            display: flex;
+            justify-content: flex-end;
+
+            /* 將內容向右推送 */
+            .save-info-ok
+            {
+                text-align: right;
+                display: flex;
+                align-items: center;
+                color: #808695;
+            }
+
+            .save-info-erro
+            {
+                text-align: right;
+                display: flex;
+                align-items: center;
+                color: #ed4014;
+            }
+        }
+    }
+
+    .fontSize10
+    {
+        font-size: 10px;
+    }
+
+    .list-name
+    {
+        width: 90%;
+        color: #2d8cf0;
+        padding: 2px 5px;
+        border: 1px solid #e8eaec;
+    }
+    .list-name2
+    {
+        width: 90%;
+        padding: 2px 5px;
+        border: 1px solid #e8eaec;
+    }
+
+    .body
+    {
+        overflow: auto;
+        margin: 0px 10px 10px 10px;
+        margin-top: 0px;
+        
+        .top10{
+            margin-top: 15px;
+        }
+        .linkFor{
+            margin-top: 5px;
+            margin-bottom: 20px;
+        }
+        .group
+        {
+            .title
+            {
+                margin-bottom: 5px;
+            }
+
+            .switch
+            {
+                margin-left: 5px;
+            }
+            .ivu-radio-wrapper{
+                margin-right: 30px;
+            }
+        }
+
+        .showClass-div
+        {
+            margin-top: 10px;
+
+            .showClass
+            {
+                color: #2d8cf0;
+                padding: 5px;
+                border: 1px solid #2d8cf0;
+                border-radius: 5px;
+                margin: 5px;
+            }
+        }
+        .thisTitle{
+            background-color: #e8eaec;
+            padding:2px 20px;
+        }
+        .add-card{
+            padding: 5px 10px;
+            margin: 10px 5px;
+        }
+        .cardRow{
+            overflow: auto;
+            height: calc(100vh - 400px);
+            margin-top: 5px;
+            .card{
+                background-color: white;
+                border-radius: 8px;            
+                // font-weight: 900;
+                border: 1px solid #e8eaec;
+                box-shadow: 0 0 3px #00000011;
+            }
+            .rCard{                
+                margin: 5px;       
+                padding: 10px 10px;
+                .left{                
+                    display: flex;
+                    align-items: center;
+                    img{
+                        height: 20px;
+                        margin-right: 10px;
+                    }
+                }            
+            }
+        }        
+    }
+}

+ 258 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusResource.vue

@@ -0,0 +1,258 @@
+<template>
+  <div class="SyllabusResource-container">
+    <div class="SaveDelDiv between"><!--路徑與存檔刪除鈕-->
+      <div v-if="PageData.level === 'Title'" class="fontSize10">{{PageData.data.Title}}</div>
+      <div v-else-if="PageData.level === 'Chapter'" class="fontSize10">{{PageData.data.Title}} /
+        {{PageData.data.Chapter}}</div>
+      <div v-else-if="PageData.level === 'Section'" class="fontSize10">{{PageData.data.Title}} /
+        {{PageData.data.Chapter}} / {{PageData.data.Section}}</div>
+      <div>
+        <div>
+          <Button @click="deleteFun(PageData.level)">刪除</Button>
+          <Button @click="saveFun(PageData.level)" type="primary">儲存</Button>
+        </div>
+        <div class="saveDiv">
+          <div v-if="isSave" class="save-info-ok">
+            <Icon type="md-checkmark-circle" />已存檔
+          </div>
+          <div v-if="!isSave" class="save-info-erro">
+            <Icon type="md-alert" />未存檔
+          </div>
+        </div>
+      </div>
+    </div>
+    <div v-if="PageData.level === 'Title'">
+      <div class="body" style="height: calc(100vh - 280px);">
+        <div v-if="PageData.type === 'link'" class="group fontSize10 linkFor" ><!--同步於-->
+          同步於 
+          <span class="showClass-div">
+            <span  class="showClass">
+              {{Synchronize[0].name}}
+            </span>
+          </span> 
+          {{Synchronize[0].title}}
+        </div>
+        <div class="group"><!--課綱名稱-->
+          <div class="title">課綱名稱</div>
+          <input v-if="PageData.type !== 'link'" type="text" v-model="titleData.name" 
+            placeholder="" class="list-name" maxlength="50" />
+          <input v-else-if="PageData.type === 'link'" type="text" v-model="titleData.name" 
+            placeholder="" class="list-name2" maxlength="50" disabled/>
+        </div>
+        <div class="group top10"><!--課綱說明-->
+          <div class="title">課綱說明</div>
+          <textarea v-if="PageData.type !== 'link'" type="text" rows="10" cols="30" datatype="*" 
+            class="list-name" placeholder="請輸入..." v-model="titleData.info"></textarea>
+          <textarea v-else-if="PageData.type === 'link'" type="text" rows="10" cols="25" datatype="*" 
+            class="list-name2"  v-model="titleData.info" disabled></textarea>
+        </div>
+        <div class="group top10"><!--上架狀況-->
+          <div class="title">上架狀況</div>
+          <i-Switch v-model="release" size="large" class="switch" :before-change="releaseChangeFun">
+            <template #open>
+              <span>ON</span>
+            </template>
+            <template #close>
+              <span>OFF</span>
+            </template>
+          </i-Switch>
+        </div>
+        <div v-if="PageData.type !== 'link'" class="group top10"><!--同步對象-->
+          <div>同步對象
+            <Icon type="md-settings" size="15" class="pointer" @click="SyncClassCtl=true"/>
+          </div>
+          <div class="showClass-div">
+            <span v-for="value in Synchronize" :key="value.id" class="showClass">
+              {{value.name}}
+            </span>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div v-else>
+      <div class="body"><!--上半部分發佈類型與課綱-->
+        <div class="group">
+          <div>發佈類型
+            <Icon type="md-help-circle" size="15" />
+          </div>
+          <RadioGroup v-model="PageData.data.type" >
+            <Radio label="all" v-if="PageData.type !== 'link' ||PageData.type === 'link' && PageData.data.type ==='all'">
+              <span>全部一覽</span>
+            </Radio>
+            <Radio label="order" v-if="PageData.type !== 'link' ||PageData.type === 'link' && PageData.data.type ==='order'">
+              <span>依序一覽</span>
+              <Icon type="md-git-pull-request" size="17" />
+            </Radio>
+          </RadioGroup>
+        </div>
+        <div class="group top10">
+          <div class="title">課綱名稱</div>
+          <input v-if="PageData.type !== 'link'" type="text" v-model="titleData.name" placeholder="" class="list-name" maxlength="50" />
+          <input v-else-if="PageData.type === 'link'" type="text" v-model="titleData.name" placeholder="" class="list-name2" maxlength="50" disabled/>
+        </div>
+      </div>
+      <div v-if="PageData.level === 'Section'">
+        <div class="body">
+          <div class="thisTitle">本項資源</div>
+          <div class="cardRow">
+            <div v-if="PageData.type !== 'link'" class="card add-card center pointer" @click="AddResourcesBtn=true">
+              <Icon type="md-add-circle" :size="25" />
+            </div>
+            <div v-for="(item,index) in Resource" :key="index" class="card rCard between"
+              draggable="true" @dragstart="dragStart($event, index)" @dragover="allowDrop" 
+              @drop="drop($event, index)" @dragend="dragEnd">
+              <div class="left">
+                <img :src="getResourceImage(item.type)"/>                
+                {{item.name}}
+              </div>
+              <Icon type="ios-trash" v-if="PageData.type !== 'link'" size="20" style="cursor: pointer"></Icon>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <SyncClass :SyncClassCtl="SyncClassCtl" @SyncClassClose="SyncClassCtl=false"></SyncClass>
+    <ReleaseSyllabus :ReleaseCtl="ReleaseCtl" @ReleaseFun="ReleaseCtl=false" @ReleaseOpenFun="ReleaseOpenFun"></ReleaseSyllabus>
+    <AddResources :DialogBoxCtl="AddResourcesBtn" @DialogBoxClose="AddResourcesBtn=false"></AddResources>
+  </div>
+</template>
+<script>
+import SyncClass from "./DialogBox/SyncClass.vue"
+import ReleaseSyllabus from "./DialogBox/ReleaseSyllabus.vue"
+import AddResources from "./DialogBox/AddResources.vue"
+export default {
+  components: {
+    SyncClass,ReleaseSyllabus,AddResources
+  },
+  props: {
+    //收藏id,双向绑定    
+    PageData: Object,
+    getResourceImage:Function,
+  },
+  data() {
+    return {
+      isSave: true,//存檔
+      treeShow: '',//路徑樹
+      titleData: { name: '', info: '課綱說明的內容' },
+      release: false,//發佈
+      SyncClassCtl:false,//同步班級的跳窗開關
+      ReleaseCtl:false,//上架跳窗
+      AddResourcesBtn:false,//新增資源跳窗
+      Synchronize: [//同步對象,如果有title是被同步於哪個課綱的課綱
+        { id: 1, name: '七年一班',title:'數學一年級上學期課綱(1)' },
+        { id: 2, name: '七年七班' },
+      ],
+      Resource: [//資源
+        //type類型:
+        //圖示:image、doc、excel、ppt、video、audio、item、paper、link、zip、other
+        //文字類:教材、評量、活動、投票、問卷
+        { id: 1,sort:1, type: 'image', name: '蘋果有幾個?' },
+        { id: 2,sort: 2, type: 'doc', name: '大樹與小數' },
+        { id: 3,sort: 3, type: 'excel', name: '試算表' },
+        { id: 4,sort: 4, type: 'ppt', name: '投影片' },
+        { id: 5,sort: 5, type: 'video', name: '影片' },
+        { id: 6,sort: 6, type: 'audio', name: '音樂' },
+        { id: 7,sort: 7, type: 'item', name: '物件' },
+        { id: 8,sort: 8, type: 'paper', name: '紙張' },
+        { id: 9,sort: 9, type: 'link', name: '連結' },
+        { id: 10,sort: 10, type: 'zip', name: '壓縮檔' },
+        { id: 11,sort: 11, type: 'other', name: '其它' },
+      ],
+      
+    }
+  },
+  computed: {
+  },
+  created() {
+  },
+  methods: {
+    deleteFun(type) {//刪除按鈕
+      if (type === 'Title') {//標題
+
+      } else if (type === 'Chapter') {//章節
+
+      } else if (type === 'Section') {//資源卡片
+
+      }
+    },
+    saveFun(type) {//存檔案鈕
+      if (type === 'Title') {//標題
+
+      } else if (type === 'Chapter') {//章節
+
+      } else if (type === 'Section') {//資源卡片
+
+      }
+      this.isSave = true;
+    },
+    releaseChangeFun(){
+      return new Promise((resolve) => {
+        if(!this.release)  this.ReleaseCtl=true;
+        else{//下架確認
+          this.$Modal.confirm({
+              title: '詢問',
+              content: '確定要下架嗎?',
+              onOk: () => {
+                  resolve();
+              }
+          });
+        }
+      });
+    },
+    ReleaseOpenFun(value){
+      this.ReleaseCtl=false; 
+      this.release=value;
+    },
+    //拖曳相關--str---↓↓--
+    allowDrop(e) {//取消默認行為
+      e.preventDefault();
+    },
+    dragStart(e, index) {//拖曳開始
+      let tar = e.target;
+      e.dataTransfer.setData('Text', index);
+      if (tar.tagName.toLowerCase() == 'li') {
+        // console.log('drag start')
+        // console.log('drag Index: ' + index)
+      }
+    },
+    drop(e, index) {//放置
+      this.allowDrop(e);
+      let arr = this.Resource.concat([]),
+      dragIndex = e.dataTransfer.getData('Text');
+      let temp = arr.splice(dragIndex, 1);  
+      arr.splice(index, 0, temp[0]);
+      this.Resource = arr;
+
+      //↓改正Resource資料的sort
+      for (let i = 0; i < this.Resource.length; i++) {
+        this.Resource[i].sort = this.Resource.length - i;
+      }   
+    },
+    dragEnd() {//放置結束
+      console.log("dragEnd");
+    },
+    //拖曳相關--end---↑↑--
+  },
+  watch: {
+    PageData: {
+      deep: true,
+      immediate: true,
+      handler(newVal, oldVal) {
+        if (this.PageData.level === 'Title') {
+          this.titleData.name = this.PageData.data.Title;
+        } else if (this.PageData.level === 'Chapter') {
+          this.titleData.name = this.PageData.data.Chapter;
+        } else if (this.PageData.level === 'Section') {
+          this.titleData.name = this.PageData.data.Section;
+        }
+      }
+    },
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./SyllabusResource.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 39 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusSchedule.less

@@ -0,0 +1,39 @@
+.between{//分兩邊
+    display: flex;
+    justify-content: space-between;
+}
+.imgS{
+    height: 20px;
+    margin-right: 10px;
+}
+.SyllabusSchedule-container{
+    width: calc(100% - 300px);
+    padding: 10px;
+
+    .fontSize10{
+        font-size: 10px;
+    }
+    .body
+    {
+        margin: 10px;
+        margin-top: 20px;
+        .title{
+            margin: 10px 0px;
+            img{
+                height: 20px;
+                margin-right: 10px;
+            }
+            .Option{
+                display : flex;
+                align-items: center;
+                img{
+                    height: 20px;
+                    margin-right: 10px;
+                }
+            }            
+        }
+        .tag{
+            margin: 5px ;
+        }        
+    }
+}

+ 155 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/SyllabusSchedule.vue

@@ -0,0 +1,155 @@
+<template>
+  <div class="SyllabusSchedule-container">
+    <div class="SaveDelDiv between"><!--路徑-->
+      <div v-if="PageData.level === 'Title'" class="fontSize10">{{PageData.data.Title}}</div>
+      <div v-else-if="PageData.level === 'Chapter'" class="fontSize10">{{PageData.data.Title}} /
+        {{PageData.data.Chapter}}</div>
+      <div v-else-if="PageData.level === 'Section'" class="fontSize10">{{PageData.data.Title}} /
+        {{PageData.data.Chapter}} / {{PageData.data.Section}}</div>
+    </div>
+    <div v-if="PageData.level === 'Chapter'"><!--章節完成%-->
+      <div class="body">
+        <DataTable :value="ChapterData" tableStyle="min-width: calc(100% - 20px);" stripedRows 
+          :scrollHeight="tableHeight.toString()+'px'" scrollable sortField="irs" :sortOrder="1" removableSort>
+          <Column field="irs" header="IRS" sortable
+            :styles="{ 'min-width': '120px',   'display': 'flex', 'align-items': 'center', 'justify-content': 'center' }"
+            ></Column>
+          <Column field="id" header="學號" sortable
+            :styles="{ 'min-width': '120px',   'display': 'flex', 'align-items': 'center', 'justify-content': 'center' }"
+            ></Column>
+          <Column field="name" header="姓名" sortable
+            :styles="{ 'min-width': '120px',   'display': 'flex', 'align-items': 'center', 'justify-content': 'center' }"
+            ></Column>
+          <Column field="rate" header="章節完成度" sortable
+            :styles="{ 'min-width': '120px',   'display': 'flex', 'align-items': 'center', 'justify-content': 'center' }"
+            ></Column>
+        </DataTable>
+      </div>      
+    </div>
+    <div v-else-if="PageData.level === 'Section'"><!--資源進度-->
+      <div class="body">
+        <div class="between title">
+          <div>
+            資源名稱:
+            <Select v-model="selectNow.id"  style="width:200px" @on-change="selectResource">
+              <template #prefix>
+                <img :src="getResourceImage(selectNow.type)" />
+              </template>
+              <Option v-for="item in resourceTitle" :value="item.id" :key="item.id" class="Option">
+                <img :src="getResourceImage(item.type)" />
+                {{ item.name }}
+              </Option>
+            </Select>
+            <span class="tag">
+              <Tag v-if="stateTag==='start'" color="success">進行中</Tag>
+              <Tag v-else-if="stateTag==='end'" color="warning">已結束</Tag>
+            </span>            
+          </div>
+          <Button type="primary" ghost>分析</Button>
+        </div>
+        <DataTable :value="ChapterData" tableStyle="min-width: calc(100% - 20px); " stripedRows 
+          :scrollHeight="tableHeight.toString()+'px'" scrollable sortField="irs" :sortOrder="1" removableSort>
+          <Column field="irs" header="IRS" sortable
+            :styles="{ 'min-width': '120px',   'display': 'flex', 'align-items': 'center', 'justify-content': 'center' }"
+            ></Column>
+          <Column field="id" header="學號" sortable
+            :styles="{ 'min-width': '120px',   'display': 'flex', 'align-items': 'center', 'justify-content': 'center' }"
+            ></Column>
+          <Column field="name" header="姓名" sortable
+            :styles="{ 'min-width': '120px',   'display': 'flex', 'align-items': 'center', 'justify-content': 'center' }"
+            ></Column>
+          <Column field="rate" header="完成度" sortable
+            :styles="{ 'min-width': '120px',   'display': 'flex', 'align-items': 'center', 'justify-content': 'center' }"
+            >
+            <template #body="rowData">
+              <div>
+                <div v-if="rowData.data.rate" style="color:#19be6b;">
+                  <Icon type="md-checkmark-circle" />
+                  已完成
+                </div>
+                <div v-else style="color:#ed4014;">
+                  <Icon type="md-close-circle" />
+                  未完成
+                </div>
+              </div>
+            </template>  
+          </Column>
+        </DataTable>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import DataTable from 'primevue/datatable'
+import Column from 'primevue/column'
+import 'primevue/resources/themes/saga-blue/theme.css'; // 根據你喜好的主題選擇
+import 'primevue/resources/primevue.min.css';
+
+export default {
+  components: {
+    Column, DataTable,
+  },
+  props: {
+    //收藏id,双向绑定    
+    PageData: Object,
+    getResourceImage:Function,
+  },
+  data() {
+    return {
+      tableHeight: 0,
+      ChapterData: [
+        { irs: 1234, id: 123456, name: 'Jhon', rate: false },
+        { irs: 1235, id: 223456, name: 'Mary', rate: false },
+        { irs: 1236, id: 323456, name: 'Alex', rate: true },
+        { irs: 1234, id: 123456, name: 'Jhon', rate: true },
+        { irs: 1235, id: 223456, name: 'Mary', rate: true },
+        { irs: 1236, id: 323456, name: 'Alex', rate: false },
+        { irs: 1234, id: 123456, name: 'Jhon', rate: false },
+        { irs: 1235, id: 223456, name: 'Mary', rate: true },
+        { irs: 1236, id: 323456, name: 'Alex', rate: true },
+      ],
+      resourceTitle: [//state狀態:start、end
+        { id: 1, name: '蘋果有幾個?',state:'start',type:'image' },
+        { id: 2, name: '大樹與小數',state:'end',type:'doc' },
+      ],
+      selectNow:{id:1,name:'',type:''},//現在選擇的資源
+      stateTag:'start',
+    }
+  },
+  computed: {
+  },
+  created() {
+  },
+  methods: {    
+    selectResource(id) {//選擇資源選項觸發
+      this.selectNow.id = id;
+      this.selectNow.type =  this.resourceTitle.find(item => item.id === id).type;
+      this.selectNow.name = this.resourceTitle.find(item => item.id === id).name;
+    },
+    getTableHeight() {
+      let num = this.PageData.level === 'Section' ? 280 : 240;
+      this.tableHeight = window.innerHeight - num;
+    },
+  },
+  mounted() {
+    window.addEventListener('resize', this.getTableHeight);
+    this.getTableHeight();
+  },
+  watch: {
+    PageData: {
+      deep: true,
+      immediate: true,
+      handler(n, o) {
+        this.getTableHeight();
+        this.selectResource(this.resourceTitle[0].id);//預設顯示第一個資源
+      }
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./SyllabusSchedule.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 15 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/addSyllabus.less

@@ -0,0 +1,15 @@
+.addButton{
+    margin-top: 10px;
+    // position: absolute;
+    // right: 20px;
+}
+.body{
+    margin-left: 20px;
+    .selectGroup{
+        margin-left: 20px ;
+        margin-bottom: 10px;
+        .ivu-select{
+            margin: 0px 3px;
+        }
+    }
+}

+ 100 - 0
TEAMModelOS/ClientApp/src/view/mycourse/syllabus/addSyllabus.vue

@@ -0,0 +1,100 @@
+<template>
+  <div class="addSyllabus-container">
+    <div class="body">
+      <RadioGroup v-model="addData.chooseWay" vertical>
+        <Radio label="Empty">
+          <span>新增空課綱</span>
+        </Radio>
+        <Radio label="Code">
+          <span>貼上課綱代碼:</span>
+          <Input v-model="addData.codeData" placeholder="Enter something..." style="width: 300px" />
+        </Radio>
+        <Radio label="Choose" :tabindex="0">
+          <span>選擇課綱:</span>
+        </Radio>
+        <div class="selectGroup">
+          <Select v-model="model" style="width:100px" placeholder="來源">
+            <Option v-for="item in cityList" :value="item.id" :key="item.id">{{ item.name }}</Option>
+          </Select>
+          <Select v-model="model" style="width:150px" placeholder="課程">
+            <Option v-for="item in cityList" :value="item.id" :key="item.id">{{ item.name }}</Option>
+          </Select>
+          <Select v-model="model" style="width:150px" placeholder="班級">
+            <Option v-for="item in cityList" :value="item.id" :key="item.id">{{ item.name }}</Option>
+          </Select>
+          <Select v-model="model" style="width:150px" placeholder="課綱">
+            <Option v-for="item in cityList" :value="item.id" :key="item.id">{{ item.name }}</Option>
+          </Select>
+        </div>
+        <Button v-if="addBtn" type="primary" class="addButton" @click="addSyllabusFun">新增</Button>
+      </RadioGroup>
+    </div>
+  </div>
+</template>
+<script>
+// import SyllabusBody from "./SyllabusBody.vue"
+export default {
+  components: {
+    // SyllabusBody
+  },
+  props: {
+    //收藏id,双向绑定
+    value: {
+      default: () => {
+        return []
+      },
+    },
+    grouplistId: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    addBtnCtl:Boolean,
+  },
+  data() {
+    return {
+      addBtn:true,//控制新增按鈕是否顯示
+      addData: {//新增課綱的相關內容
+        chooseWay: 'Empty',
+        codeData: '',
+      },
+      cityList: [
+        {
+          id: 'New York',
+          name: 'New York'
+        },
+        {
+          id: 'London',
+          name: 'London'
+        },
+      ],
+      model: '',
+    }
+  },
+  computed: {
+  },
+  created() {
+  },
+  methods: {
+    addSyllabusFun() {
+      console.log("addSyllabusFun 新增新課綱");
+    }
+  },
+  watch: {
+    addBtnCtl: {
+      deep: true,
+      immediate: true,
+      handler(n, o) {
+        this.addBtn = n;
+      }
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./addSyllabus.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 178 - 529
TEAMModelOS/ClientApp/src/view/signupActivity/createActivity.vue

@@ -101,12 +101,24 @@
                                                 <FormItem label="填报信息">
                                                 <FormItem label="填报信息">
                                                     <CheckboxGroup v-model="activityData.infoArr">
                                                     <CheckboxGroup v-model="activityData.infoArr">
                                                         <Checkbox v-for="(item, index) in infoArr" :key="index" :label="item.value">{{ item.label }}</Checkbox>
                                                         <Checkbox v-for="(item, index) in infoArr" :key="index" :label="item.value">{{ item.label }}</Checkbox>
+                                                        <Icon type="md-add-circle" @click="addInfoType = true" v-show="!addInfoType" size="18" />
+                                                        <div v-show="addInfoType">
+                                                            <Input v-model="addInfo" placeholder="自定义填报的信息" style="width: 300px"></Input>
+                                                            <Icon type="md-checkmark-circle" size="18" style="margin: 0 10px;" @click="addInform()" />
+                                                            <Icon type="md-close-circle" size="18" @click="addInfoType = false" />
+                                                        </div>
                                                     </CheckboxGroup>
                                                     </CheckboxGroup>
                                                 </FormItem>
                                                 </FormItem>
                                                 <FormItem label="报名方式">
                                                 <FormItem label="报名方式">
                                                     <RadioGroup v-model="activityData.applicationType">
                                                     <RadioGroup v-model="activityData.applicationType">
                                                         <Radio :label="1">{{ '报名制' }}</Radio>
                                                         <Radio :label="1">{{ '报名制' }}</Radio>
                                                         <Radio :label="2">{{ '邀请制' }}</Radio>
                                                         <Radio :label="2">{{ '邀请制' }}</Radio>
+                                                        <Select v-model="schoolChange" multiple filterable v-show="activityData.applicationType === 2 && isArea === 'area'" style="width: 500px" placeholder="选择参加活动的学校">
+                                                            <Option v-for="format in schoolList" :value="format.code" :key="format.code">{{ format.name }}</Option>
+                                                        </Select>
+                                                        <Select v-model="schoolChange" multiple filterable v-show="activityData.applicationType === 2 && isArea === 'school'" style="width: 500px" placeholder="选择参加活动的学校">
+                                                            <Option v-for="format in teacherList" :value="format.code" :key="format.code">{{ format.name }}</Option>
+                                                        </Select>
                                                     </RadioGroup>
                                                     </RadioGroup>
                                                 </FormItem>
                                                 </FormItem>
                                                 <!-- 邀请制且团队赛,按照教研组分组,组长为教研组组长 -->
                                                 <!-- 邀请制且团队赛,按照教研组分组,组长为教研组组长 -->
@@ -182,13 +194,14 @@
                                                     <DatePicker :editable="false" @on-change="getReviewTime" type="datetimerange" format="yyyy-MM-dd HH:mm" :placeholder="$t('train.create.timeHolder')" style="width: 500px"></DatePicker>
                                                     <DatePicker :editable="false" @on-change="getReviewTime" type="datetimerange" format="yyyy-MM-dd HH:mm" :placeholder="$t('train.create.timeHolder')" style="width: 500px"></DatePicker>
                                                 </FormItem>
                                                 </FormItem>
                                                 <FormItem label="评审规则">
                                                 <FormItem label="评审规则">
-                                                    <Select v-model="activityData.review" style="width:200px">
+                                                    <Select v-model="activityData.review" transfer style="width:200px">
                                                         <Option v-for="item in reviewList" :value="item.value" :key="item.value">
                                                         <Option v-for="item in reviewList" :value="item.value" :key="item.value">
                                                             {{ item.label }}
                                                             {{ item.label }}
-                                                            <span @click="ruleDrawer = true">预览</span>
+                                                            <span @click.stop="ruleDrawer = true">预览</span>
+                                                            <span @click.stop="reviewEditRule()">编辑</span>
                                                         </Option>
                                                         </Option>
                                                     </Select>
                                                     </Select>
-                                                    <Icon size="20" type="md-add-circle" @click="ruleDrawerAdd = true" />
+                                                    <Icon size="20" type="md-add-circle" @click="drawerRule()" />
                                                 </FormItem>
                                                 </FormItem>
                                             </div>
                                             </div>
                                         </div>
                                         </div>
@@ -242,7 +255,7 @@
                 <Table row-key="id" :columns="ruleColumns" :data="ruleInfo.children"></Table>
                 <Table row-key="id" :columns="ruleColumns" :data="ruleInfo.children"></Table>
             </div>
             </div>
         </Drawer>
         </Drawer>
-        <Drawer title="添加评审规则" :width="50" :closable="false" v-model="ruleDrawerAdd">
+        <Drawer title="添加评审规则" :width="50" :closable="false" v-model="ruleDrawerAdd" class="light-iview-form">
             <Form :model="processInfo" :label-width="80" class="create-form">
             <Form :model="processInfo" :label-width="80" class="create-form">
                 <FormItem label="规则名称">
                 <FormItem label="规则名称">
                     <Input v-model="processInfo.name" placeholder="请输入规则名称"></Input>
                     <Input v-model="processInfo.name" placeholder="请输入规则名称"></Input>
@@ -250,23 +263,33 @@
                 <FormItem label="规则描述">
                 <FormItem label="规则描述">
                     <Input v-model="processInfo.describe" placeholder="请输入规则描述"></Input>
                     <Input v-model="processInfo.describe" placeholder="请输入规则描述"></Input>
                 </FormItem>
                 </FormItem>
-                <FormItem label="规则分值">
+                <!-- <FormItem label="规则分值">
                     <Input v-model="processInfo.score" placeholder="请输入分值"></Input>
                     <Input v-model="processInfo.score" placeholder="请输入分值"></Input>
-                </FormItem>
+                </FormItem> -->
                 <div class="rule-header">
                 <div class="rule-header">
                     <span>分项</span>
                     <span>分项</span>
                     <span>描述</span>
                     <span>描述</span>
                     <span>分值</span>
                     <span>分值</span>
                     <span>操作</span>
                     <span>操作</span>
                 </div>
                 </div>
-                <Tree :data="ruleTree"></Tree>
+                <el-tree :data="processInfo.rule" node-key="id" default-expand-all :expand-on-click-node="false">
+                    <div class="custom-tree-node" slot-scope="{ node, data }">
+                        <Input v-model="data.name" placeholder="分项名称" style="width: 200px;"></Input>
+                        <Input v-model="data.describe" placeholder="对分项内容进行描述"></Input>
+                        <InputNumber v-model="data.score" :min="1" style="width: 100px;" :disabled="(data.children && data.children.length) ? true : false" @on-change="scoreChange(node, data)" />
+                        <span>
+                            <Button size="small" style="margin-right: 10px;" :disabled="data.isThree" @click="append(node, data)">添加子项</Button>
+                            <Button size="small" type='error' @click="remove(node, data)">删除</Button>
+                        </span>
+                    </div>
+                </el-tree>
             </Form>
             </Form>
-            <div style="margin: 10px 0; text-align: right;">
-                <!-- <span>总分:0</span> -->
-                <Button @click="addRule">添加分项</Button>
+            <div style="margin: 10px 0; display: flex; justify-content: space-between; align-items: center;">
+                <span style="font-size: 20px;">总分:{{ processInfo.score }}</span>
+                <Button @click="addRule()">添加分项</Button>
             </div>
             </div>
             <div>
             <div>
-                <Button @click="save">仅本次活动使用</Button>
+                <Button @click="save()">仅本次活动使用</Button>
                 <Button>保存为模板</Button>
                 <Button>保存为模板</Button>
             </div>
             </div>
         </Drawer>
         </Drawer>
@@ -588,12 +611,13 @@ export default {
                 },
                 },
                 {
                 {
                     title: '描述',
                     title: '描述',
-                    key: 'describe'
+                    key: 'describe',
                 },
                 },
                 {
                 {
                     title: '分值',
                     title: '分值',
                     key: 'score',
                     key: 'score',
                     width: 100,
                     width: 100,
+                    align: 'center',
                 },
                 },
             ],
             ],
             ruleInfo: {
             ruleInfo: {
@@ -644,334 +668,94 @@ export default {
                                 name: '教学过程',
                                 name: '教学过程',
                                 describe: '',
                                 describe: '',
                                 score: 5,
                                 score: 5,
+                                parentId: '106',
                             },
                             },
                             {
                             {
                                 id: '10601',
                                 id: '10601',
                                 name: '教学设计',
                                 name: '教学设计',
                                 describe: '',
                                 describe: '',
                                 score: 5,
                                 score: 5,
+                                parentId: '106',
                             },
                             },
                             {
                             {
                                 id: '10602',
                                 id: '10602',
                                 name: '融合创新',
                                 name: '融合创新',
                                 describe: '',
                                 describe: '',
                                 score: 5,
                                 score: 5,
+                                parentId: '106',
                             },
                             },
                             {
                             {
                                 id: '10603',
                                 id: '10603',
                                 name: '技术应用',
                                 name: '技术应用',
                                 describe: '',
                                 describe: '',
                                 score: 5,
                                 score: 5,
+                                parentId: '106',
                             },
                             },
                             {
                             {
                                 id: '10604',
                                 id: '10604',
                                 name: '教学效果',
                                 name: '教学效果',
                                 describe: '',
                                 describe: '',
                                 score: 5,
                                 score: 5,
+                                parentId: '106',
                             },
                             },
                         ],
                         ],
                     },
                     },
                 ],
                 ],
             },
             },
-            processInfo: {
-                rule: [
-                    {
+            processInfo: {},
+            timer: null,
+            treeType: '',
+            editRule: false,
+            dataRuleMould: [{
+                id: 1,
+                name: '',
+                describe: '',
+                score: null,
+                children: [{
+                    id: 2,
+                    name: '',
+                    describe: '',
+                    score: null,
+                    children: [{
+                        id: 3,
                         name: '',
                         name: '',
                         describe: '',
                         describe: '',
                         score: null,
                         score: null,
-                        nodeKey: 0,
-                        children: [
-                            {
-                                name: '',
-                                describe: '',
-                                score: null,
-                                nodeKey: 1,
-                                children: [
-                                    {
-                                        name: '',
-                                        describe: '',
-                                        score: null,
-                                    }
-                                ],
-                            }
-                        ],
-                    }
-                ]
-            },
-            ruleTree: [
+                        isThree: true,
+                    }]
+                }]
+            }],
+            addInfoType: false,
+            addInfo: '',
+            schoolList: [
                 {
                 {
-                    title: '1',
-                    expand: true,
-                    name: '',
-                    describe: '',
-                    score: null,
-                    render: (h, { root, node, data }) => {
-                        return h('div', [
-                            h('Input', {
-                                props: {
-                                    value: data.name,
-                                    placeholder: '一级分项',
-                                },
-                                style: {
-                                    width: '20%',
-                                    marginRight: '10px',
-                                },
-                                on: {
-                                    'on-change': value => {
-                                        console.log(data, value);
-                                        if(value.data !== null) {
-                                            that.inputChange(data, value, 'name')
-                                        }
-                                    }
-                                },
-                            }),
-                            h('Input', {
-                                props: {
-                                    value: data.describe,
-                                    placeholder: '对分项内容进行描述',
-                                },
-                                style: {
-                                    width: '65%',
-                                    marginRight: '10px',
-                                },
-                                on: {
-                                    'on-change': value => {
-                                        console.log(data, value);
-                                        if(value.data !== null) {
-                                            that.inputChange(data, value, 'describe')
-                                        }
-                                    }
-                                },
-                            }),
-                            h('Input', {
-                                props: {
-                                    value: data.score,
-                                },
-                                style: {
-                                    width: '9%',
-                                    marginRight: '10px',
-                                },
-                                on: {
-                                    'on-change': value => {
-                                        console.log(data, value);
-                                        if(value.data !== null) {
-                                            that.inputChange(data, value, 'score')
-                                        }
-                                    }
-                                },
-                            }),
-                            h('span', [
-                                h('Button', {
-                                    props: {
-                                        // type: 'error',
-                                        size: 'small',
-                                    },
-                                    style: {
-                                        marginRight: '10px',
-                                    },
-                                    on: {
-                                        click:() => {
-                                            that.append(data)
-                                        }
-                                    },
-                                }, '插入'),
-                                h('Button', {
-                                    props: {
-                                        type: 'error',
-                                        size: 'small',
-                                    },
-                                    /* style: {
-                                        width: '13%',
-                                    }, */
-                                    on: {
-                                        click:() => {
-                                            that.remove(root, node, data)
-                                        }
-                                    },
-                                }, '删除'),
-                            ])
-                        ], data.title)
-                    },
-                    children: [
-                        {
-                            title: '101',
-                            expand: true,
-                            name: '',
-                            describe: '',
-                            score: null,
-                            render: (h, { root, node, data }) => {
-                                return h('div', [
-                                    h('Input', {
-                                        props: {
-                                            value: data.name,
-                                            placeholder: '二级分项',
-                                        },
-                                        style: {
-                                            width: '20%',
-                                            marginRight: '10px',
-                                        },
-                                        on: {
-                                            'on-change': value => {
-                                                console.log(data, value);
-                                                if(value.data !== null) {
-                                                    that.inputChange(data, value, 'name')
-                                                }
-                                            }
-                                        },
-                                    }),
-                                    h('Input', {
-                                        props: {
-                                            value: data.describe,
-                                            placeholder: '对分项内容进行描述',
-                                        },
-                                        style: {
-                                            width: '62.9%',
-                                            marginRight: '10px',
-                                        },
-                                        on: {
-                                            'on-change': value => {
-                                                console.log(data, value);
-                                                if(value.data !== null) {
-                                                    that.inputChange(data, value, 'describe')
-                                                }
-                                            }
-                                        },
-                                    }),
-                                    h('Input', {
-                                        props: {
-                                            value: data.score,
-                                        },
-                                        style: {
-                                            width: '9%',
-                                            marginRight: '10px',
-                                        },
-                                        on: {
-                                            'on-change': value => {
-                                                console.log(data, value);
-                                                if(value.data !== null) {
-                                                    that.inputChange(data, value, 'score')
-                                                }
-                                            }
-                                        },
-                                    }),
-                                    h('span', [
-                                        h('Button', {
-                                            props: {
-                                                // type: 'error',
-                                                size: 'small',
-                                            },
-                                            style: {
-                                                marginRight: '10px',
-                                            },
-                                            on: {
-                                                click:() => {
-                                                    that.append(data, true)
-                                                }
-                                            },
-                                        }, '插入'),
-                                        h('Button', {
-                                            props: {
-                                                type: 'error',
-                                                size: 'small',
-                                            },
-                                            /* style: {
-                                                width: '13%',
-                                            }, */
-                                            on: {
-                                                click:() => {
-                                                    that.remove(root, node, data)
-                                                }
-                                            },
-                                        }, '删除'),
-                                    ])
-                                ])
-                            },
-                            children: [
-                                {
-                                    title: '101',
-                                    expand: true,
-                                    name: '',
-                                    describe: '',
-                                    score: null,
-                                    render: (h, { root, node, data }) => {
-                                        return h('div', [
-                                            h('Input', {
-                                                props: {
-                                                    value: data.name,
-                                                    placeholder: '三级分项',
-                                                },
-                                                style: {
-                                                    width: '20%',
-                                                    marginRight: '10px',
-                                                },
-                                                on: {
-                                                    'on-change': value => {
-                                                        console.log(data, value);
-                                                        if(value.data !== null) {
-                                                            that.inputChange(data, value, 'name')
-                                                        }
-                                                    }
-                                                },
-                                            }),
-                                            h('Input', {
-                                                props: {
-                                                    value: data.describe,
-                                                    placeholder: '对分项内容进行描述',
-                                                },
-                                                style: {
-                                                    width: '61.3%',
-                                                    marginRight: '10px',
-                                                },
-                                                on: {
-                                                    'on-change': value => {
-                                                        console.log(data, value);
-                                                        if(value.data !== null) {
-                                                            that.inputChange(data, value, 'describe')
-                                                        }
-                                                    }
-                                                },
-                                            }),
-                                            h('Input', {
-                                                props: {
-                                                    value: data.score,
-                                                },
-                                                style: {
-                                                    width: '9%',
-                                                    marginRight: '10px',
-                                                },
-                                                on: {
-                                                    'on-change': value => {
-                                                        console.log(data, value);
-                                                        if(value.data !== null) {
-                                                            that.inputChange(data, value, 'score')
-                                                        }
-                                                    }
-                                                },
-                                            }),
-                                            h('Button', {
-                                                props: {
-                                                    type: 'error',
-                                                    size: 'small',
-                                                },
-                                                style: {
-                                                    marginLeft: '50px',
-                                                },
-                                                on: {
-                                                    click:() => {
-                                                        that.remove(root, node, data)
-                                                    }
-                                                },
-                                            }, '删除'),
-                                        ])
-                                    },
-                                }
-                            ],
-                        }
-                    ],
+                    code: '111',
+                    name: '醍摩豆学校'
+                },
+                {
+                    code: '222',
+                    name: '研发学校'
                 },
                 },
             ],
             ],
-            timer: null,
-            treeType: '',
+            teacherList: [
+                {
+                    code: '111',
+                    name: '教研组1'
+                },
+                {
+                    code: '222',
+                    name: '教研组2'
+                },
+            ],
+            schoolChange: [],
+        }
+    },
+    created () {
+        this.processInfo = {
+            name: '',
+            describe: '',
+            score: 0,
+            rule: this.dataRuleMould
         }
         }
     },
     },
     computed: {
     computed: {
@@ -1094,245 +878,83 @@ export default {
             this.createData.file.splice(index, 1)
             this.createData.file.splice(index, 1)
         },
         },
         addRule() {
         addRule() {
-            this.ruleTree.push({
-                title: this.ruleTree.length,
-                expand: true,
+            this.processInfo.rule.push({
+                id: Math.random() * 1000000,
                 name: '',
                 name: '',
                 describe: '',
                 describe: '',
                 score: null,
                 score: null,
-                render: (h, { root, node, data }) => {
-                    return h('div', [
-                        h('Input', {
-                            props: {
-                                value: data.name,
-                                placeholder: '一级分项',
-                            },
-                            style: {
-                                width: '20%',
-                                marginRight: '10px',
-                            },
-                            on: {
-                                'on-change': value => {
-                                    console.log(data, value);
-                                    if(value.data !== null) {
-                                        this.inputChange(data, value, 'name')
-                                    }
-                                }
-                            },
-                        }),
-                        h('Input', {
-                            props: {
-                                value: data.describe,
-                                placeholder: '对分项内容进行描述',
-                            },
-                            style: {
-                                width: '65%',
-                                marginRight: '10px',
-                            },
-                            on: {
-                                'on-change': value => {
-                                    console.log(data, value);
-                                    if(value.data !== null) {
-                                        this.inputChange(data, value, 'describe')
-                                    }
-                                }
-                            },
-                        }),
-                        h('Input', {
-                            props: {
-                                value: data.score,
-                            },
-                            style: {
-                                width: '9%',
-                                marginRight: '10px',
-                            },
-                            on: {
-                                'on-change': value => {
-                                    console.log(data, value);
-                                    if(value.data !== null) {
-                                        this.inputChange(data, value, 'score')
-                                    }
-                                }
-                            },
-                        }),
-                        h('span', [
-                            h('Button', {
-                                props: {
-                                    // type: 'error',
-                                    size: 'small',
-                                },
-                                style: {
-                                    marginRight: '10px',
-                                },
-                                on: {
-                                    click:() => {
-                                        this.append(data)
-                                    }
-                                },
-                            }, '插入'),
-                            h('Button', {
-                                props: {
-                                    type: 'error',
-                                    size: 'small',
-                                },
-                                /* style: {
-                                    width: '13%',
-                                }, */
-                                on: {
-                                    click:() => {
-                                        this.remove(root, node, data)
-                                    }
-                                },
-                            }, '删除'),
-                        ])
-                    ])
-                },
             })
             })
-            this.$forceUpdate()
         },
         },
-        append(data, isThree) {
+        append(node, data) {
+            console.log(node.parent.parent);
             const children = data.children || [];
             const children = data.children || [];
             children.push({
             children.push({
-                title: '101',
-                expand: true,
+                id: Math.random() * 1000000,
                 name: '',
                 name: '',
                 describe: '',
                 describe: '',
                 score: null,
                 score: null,
-                render: (h, { root, node, data }) => {
-                    return h('div', [
-                        h('Input', {
-                            props: {
-                                value: data.name,
-                                placeholder: isThree ? '三级分项' : '二级分项',
-                            },
-                            style: {
-                                width: '20%',
-                                marginRight: '10px',
-                            },
-                            on: {
-                                'on-change': value => {
-                                    console.log(data, value);
-                                    if(value.data !== null) {
-                                        this.inputChange(data, value, 'name')
-                                    }
-                                }
-                            },
-                        }),
-                        h('Input', {
-                            props: {
-                                value: data.describe,
-                                placeholder: '对分项内容进行描述',
-                            },
-                            style: {
-                                width: isThree ? '61.3%' : '62.9%',
-                                marginRight: '10px',
-                            },
-                            on: {
-                                'on-change': value => {
-                                    console.log(data, value);
-                                    if(value.data !== null) {
-                                        this.inputChange(data, value, 'describe')
-                                    }
-                                }
-                            },
-                        }),
-                        h('Input', {
-                            props: {
-                                value: data.score,
-                            },
-                            style: {
-                                width: '9%',
-                                marginRight: '10px',
-                            },
-                            on: {
-                                'on-change': value => {
-                                    console.log(data, value);
-                                    if(value.data !== null) {
-                                        this.inputChange(data, value, 'score')
-                                    }
-                                }
-                            },
-                        }),
-                        h('span', {
-                            style: {
-                                display: isThree ? 'none' : 'inline-block'
-                            },
-                        }, [
-                            h('Button', {
-                                props: {
-                                    // type: 'error',
-                                    size: 'small',
-                                },
-                                style: {
-                                    marginRight: '10px',
-                                },
-                                on: {
-                                    click:() => {
-                                        this.append(data, true)
-                                    }
-                                },
-                            }, '插入'),
-                            h('Button', {
-                                props: {
-                                    type: 'error',
-                                    size: 'small',
-                                },
-                                /* style: {
-                                    width: '13%',
-                                }, */
-                                on: {
-                                    click:() => {
-                                        this.remove(root, node, data)
-                                    }
-                                },
-                            }, '删除'),
-                        ]),
-                        
-                        h('Button', {
-                            props: {
-                                type: 'error',
-                                size: 'small',
-                            },
-                            style: {
-                                marginLeft: '50px',
-                                display: isThree ? 'inline-block' : 'none'
-                            },
-                            on: {
-                                click:() => {
-                                    this.remove(root, node, data)
-                                }
-                            },
-                        }, '删除'),
-                    ])
-                },
-            });
+                isThree: node.parent.parent ? true : false
+            })
             this.$set(data, 'children', children)
             this.$set(data, 'children', children)
         },
         },
-        remove(root, node, data) {
-            console.log(root, node, data);
-            const parentKey = root.find(el => el === node).parent;
-            console.log(parentKey);
-            if(parentKey === undefined) {
-                // this.ruleTree = this.ruleTree.filter(i => i.nodeKey !== data.nodeKey)
-                let index = this.ruleTree.findIndex(i => i.nodeKey === data.nodeKey)
-                this.$delete(this.ruleTree,index)
-                console.log(JSON.stringify(this.ruleTree))
-            } else {
-                const parent = root.find(el => el.nodeKey === parentKey).node;
-                console.log(parent);
-                const index = parent.children.indexOf(data);
-                console.log(index);
-                parent.children.splice(index, 1);
-                console.log(parent);
-            }
+        remove(node, data) {
+            const parent = node.parent;
+            const children = parent.data.children || parent.data;
+            const index = children.findIndex(d => d.id === data.id);
+            children.splice(index, 1);
         },
         },
         save() {
         save() {
-            console.log(this.ruleTree);
-            console.log(JSON.stringify(this.ruleTree))
+            console.log(this.processInfo);
+            console.log(JSON.stringify(this.processInfo))
         },
         },
-        inputChange(data, value, type) {
-            console.log(data, value.target._value, value.data);
-            data[type] = (value.target._value === null ? '' : value.target._value) + (value.data === null ? '' : value.data)
+        reviewEditRule() {
+            this.processInfo = {
+                name: this.ruleInfo.name,
+                describe: this.ruleInfo.describe,
+                score: this.ruleInfo.score,
+                rule: this.ruleInfo.children
+            }
+            this.ruleDrawerAdd = true
+        },
+        drawerRule() {
+            this.processInfo = {
+                name: '',
+                describe: '',
+                score: 0,
+                rule: this.dataRuleMould
+            }
+            this.ruleDrawerAdd = true
+        },
+        addInform() {
+            this.infoArr.push({
+                value: this.addInfo,
+                label: this.addInfo,
+            })
+            this.addInfoType = false
+            this.addInfo = ''
+        },
+        scoreChange(node, data) {
+            // console.log(node, data);
+            this.setParentScore(node)
+        },
+        setParentScore(node) {
+            const parent = node.parent
+            if(!Array.isArray(parent.data)) {
+                let score = 0
+                parent.childNodes.forEach(item => {
+                    score += item.data.score
+                })
+                parent.data.score = score
+            } else {
+                let proScore = 0
+                this.processInfo.score = parent.data.forEach(item => {
+                    proScore += item.score
+                })
+                this.processInfo.score = proScore
+            }
+            if(parent.parent) {
+                this.setParentScore(parent)
+            }
         },
         },
     },
     },
 }
 }
@@ -1388,6 +1010,7 @@ export default {
         }
         }
     }
     }
 
 
+
 }
 }
 </style>
 </style>
 <style lang="less">
 <style lang="less">
@@ -1420,4 +1043,30 @@ export default {
         padding-left: 10px;
         padding-left: 10px;
     }
     }
 }
 }
+
+.rule-box {
+    .edit-title {
+        display: flex;
+        align-items: center;
+        margin-bottom: 10px;
+
+        &>span {
+            width: 100px;
+            text-align: right;
+        }
+    }
+}
+.el-tree-node__content {
+    height: 40px;
+}
+.custom-tree-node {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    width: 100%;
+    .ivu-input-wrapper,
+    .ivu-input-number {
+        margin-right: 10px;
+    }
+}
 </style>
 </style>

+ 306 - 143
TEAMModelOS/ClientApp/src/view/signupActivity/infoActivity copy.vue

@@ -53,28 +53,32 @@
             <TabPane label="报名数据" name="1">
             <TabPane label="报名数据" name="1">
                 <div class="tab-header join-data">
                 <div class="tab-header join-data">
                     <div>
                     <div>
-                        <p>报名制</p>
                         <p>报名方式</p>
                         <p>报名方式</p>
+                        <p>报名制</p>
                     </div>
                     </div>
                     <div>
                     <div>
-                        <p>团队赛</p>
                         <p>参赛方式</p>
                         <p>参赛方式</p>
+                        <p>团队赛</p>
                     </div>
                     </div>
                     <div>
                     <div>
-                        <p>34/50</p>
                         <p>已报名</p>
                         <p>已报名</p>
+                        <p style="color: #14b53b;">
+                            34
+                            <span style="font-size: 16px; color: #737373;">/50</span>
+                        </p>
                     </div>
                     </div>
                     <div>
                     <div>
-                        <p>27</p>
                         <p>已上传</p>
                         <p>已上传</p>
+                        <p style="color: #4b93ff;">27</p>
                     </div>
                     </div>
                     <div>
                     <div>
-                        <p>10</p>
                         <p>已评审</p>
                         <p>已评审</p>
+                        <p style="color: #ff9900;">10</p>
                     </div>
                     </div>
                 </div>
                 </div>
-                <div>
-                    <Table :columns="applicationColumns" :data="applicationList">
+                <div class="data-box">
+                    <Input placeholder="搜索醍摩豆帐号" style="width: 300px" />
+                    <Table :columns="applicationColumns" :data="applicationList" row-key="id" stripe>
                         <template #action="{row, index}">
                         <template #action="{row, index}">
                             <Button type="error" size="small" @click="deleteApplica(row, index, 'join')">删除</Button>
                             <Button type="error" size="small" @click="deleteApplica(row, index, 'join')">删除</Button>
                         </template>
                         </template>
@@ -83,7 +87,8 @@
             </TabPane>
             </TabPane>
             <TabPane label="评审管理" name="2">
             <TabPane label="评审管理" name="2">
                 <div class="tab-header">
                 <div class="tab-header">
-                    <Button>添加评审专家</Button>
+                    <Button @click="processShow = true">添加评审专家</Button>
+                    <Button style="margin-left: 20px;">自动分配评审作品</Button>
                     <Button style="float: right;" @click="ruleDrawer = true">评审规则</Button>
                     <Button style="float: right;" @click="ruleDrawer = true">评审规则</Button>
                 </div>
                 </div>
                 <div>
                 <div>
@@ -99,17 +104,37 @@
             </TabPane>
             </TabPane>
             <TabPane label="成绩统计" name="3">
             <TabPane label="成绩统计" name="3">
                 <div class="tab-header">
                 <div class="tab-header">
-                    <Button>公示成绩</Button>
+                    <Button v-show="!awardsing" @click="setAwards()">设置奖项</Button>
+                    <Button v-show="awardsing" @click="awardsShow = true">批量设置</Button>
+                    <Button style="margin-left: 20px;">公示成绩</Button>
                 </div>
                 </div>
-                <div>
-                    <Table :columns="scoreColumns" :data="scoreList">
-                        <!-- <template #actions="{row, index}">
-                            <Button size="small" @click="deleteApplica(row, index, 'score')">修改</Button>
-                        </template> -->
+                <div style="height: 80%;">
+                    <Table :columns="scoreColumns" :data="scoreList" height="600">
+                        <template #awards="{row}">
+                            <span v-if="!awardsing">{{ row.awards }}</span>
+                            <div v-else>
+                                <Select v-model="row.awards" style="width:200px" :transfer="true">
+                                    <Option v-for="item in awardsList" :value="item.value" :key="item.value">{{ item.label }}</Option>
+                                </Select>
+                            </div>
+                        </template>
                     </Table>
                     </Table>
                 </div>
                 </div>
             </TabPane>
             </TabPane>
         </Tabs>
         </Tabs>
+        <Modal v-model="processShow" title="邀请评审专家" width="800" :footer-hide="true">
+            <Table :columns="inviteColumns" :data="processList">
+                <template #process="{row, index}">
+                    <Progress :percent="25" :stroke-width="10" />
+                </template>
+                <template #actions="{row, index}">
+                    <Button type="error" size="small" @click="deleteApplica(row, index, 'process')">删除</Button>
+                </template>
+            </Table>
+            <div style="margin: 30px 0 10px 0; text-align: center;">
+                <Button type="primary" long>邀请</Button>
+            </div>
+        </Modal>
         <Drawer title="评审规则" :width="50" :closable="false" v-model="ruleDrawer">
         <Drawer title="评审规则" :width="50" :closable="false" v-model="ruleDrawer">
             <p style="font-size: 18px; font-weight: bold;">{{ ruleInfo.name }}</p>
             <p style="font-size: 18px; font-weight: bold;">{{ ruleInfo.name }}</p>
             <p>描述:{{ ruleInfo.describe }}</p>
             <p>描述:{{ ruleInfo.describe }}</p>
@@ -118,17 +143,11 @@
                 <Table row-key="id" :columns="ruleColumns" :data="ruleInfo.children"></Table>
                 <Table row-key="id" :columns="ruleColumns" :data="ruleInfo.children"></Table>
             </div>
             </div>
         </Drawer>
         </Drawer>
-        <!-- <Drawer title="评审规则" :width="50" :closable="false" v-model="ruleDrawer">
-            <p>名称:{{ ruleInfo.name }}</p>
-            <p>描述:{{ ruleInfo.describe }}</p>
-            <p>总分:{{ ruleInfo.score }}</p>
-            <div>
-                <Tree :data="ruleTree" :render="renderContent" @on-contextmenu="handleContextMenu"></Tree>
-            </div>
-        </Drawer> -->
-        <!-- <Modal v-model="modal" title="修改成绩" @on-ok="ok" @on-cancel="cancel">
-            <p></p>
-        </Modal> -->
+        <Modal v-model="awardsShow" title="批量设置奖项">
+            <Select v-model="awardsSel" style="width:200px">
+                <Option v-for="item in awardsList" :value="item.value" :key="item.value">{{ item.label }}</Option>
+            </Select>
+        </Modal>
     </div>
     </div>
 </template>
 </template>
 
 
@@ -141,23 +160,30 @@ export default {
             applicationColumns: [
             applicationColumns: [
                 {
                 {
                     title: '姓名',
                     title: '姓名',
-                    key: 'name'
+                    key: 'name',
+                    tree: true,
+                    // width: 120,
+                    // fixed: 'left'
                 },
                 },
                 {
                 {
                     title: '性别',
                     title: '性别',
-                    key: 'sex'
+                    key: 'sex',
+                    // width: 80,
                 },
                 },
                 {
                 {
                     title: '手机号码',
                     title: '手机号码',
-                    key: 'phone'
+                    key: 'phone',
+                    // width: 100,
                 },
                 },
                 {
                 {
                     title: '电子邮箱',
                     title: '电子邮箱',
-                    key: 'email'
+                    key: 'email',
+                    // width: 500,
                 },
                 },
                 {
                 {
                     title: '学校',
                     title: '学校',
                     key: 'school',
                     key: 'school',
+                    // width: 100,
                     filters: [
                     filters: [
                         {
                         {
                             label: '醍摩豆学校',
                             label: '醍摩豆学校',
@@ -175,23 +201,23 @@ export default {
                 },
                 },
                 {
                 {
                     title: '职务',
                     title: '职务',
-                    key: 'zhiwu'
+                    key: 'zhiwu',
+                    // width: 100,
                 },
                 },
                 {
                 {
                     title: '学段',
                     title: '学段',
-                    key: 'period'
+                    key: 'period',
+                    // width: 100,
                 },
                 },
                 {
                 {
                     title: '学科',
                     title: '学科',
-                    key: 'subject'
-                },
-                {
-                    title: '报名时间',
-                    key: 'time'
+                    key: 'subject',
+                    // width: 100,
                 },
                 },
                 {
                 {
                     title: '组名',
                     title: '组名',
                     key: 'team',
                     key: 'team',
+                    // width: 100,
                     filters: [
                     filters: [
                         {
                         {
                             label: '数学组',
                             label: '数学组',
@@ -210,6 +236,7 @@ export default {
                 {
                 {
                     title: '组内身份',
                     title: '组内身份',
                     key: 'identity',
                     key: 'identity',
+                    // width: 100,
                     filters: [
                     filters: [
                         {
                         {
                             label: '组长',
                             label: '组长',
@@ -225,15 +252,23 @@ export default {
                         return row.identity === value
                         return row.identity === value
                     }
                     }
                 },
                 },
+                {
+                    title: '报名时间',
+                    key: 'time',
+                    // width: 100,
+                },
                 {
                 {
                     title: '作品',
                     title: '作品',
-                    key: 'work'
+                    key: 'work',
+                    // width: 100,
+                    // fixed: 'right',
                 },
                 },
                 {
                 {
                     title: '操作',
                     title: '操作',
                     slot: 'action',
                     slot: 'action',
-                    width: 150,
                     align: 'center',
                     align: 'center',
+                    // width: 100,
+                    // fixed: 'right',
                 },
                 },
             ],
             ],
             processColumns: [
             processColumns: [
@@ -277,10 +312,41 @@ export default {
                     align: 'center',
                     align: 'center',
                 },
                 },
             ],
             ],
+            inviteColumns: [
+                {
+                    type: 'selection',
+                    width: 60,
+                    align: 'center'
+                },
+                {
+                    title: '姓名',
+                    key: 'name'
+                },
+                {
+                    title: '性别',
+                    key: 'sex'
+                },
+                {
+                    title: '手机号码',
+                    key: 'phone'
+                },
+                {
+                    title: '电子邮箱',
+                    key: 'email'
+                },
+                /* {
+                    title: '擅长学段',
+                    key: 'period'
+                },
+                {
+                    title: '擅长学科',
+                    key: 'subject'
+                }, */
+            ],
             scoreColumns: [
             scoreColumns: [
                 {
                 {
                     title: '姓名/组名',
                     title: '姓名/组名',
-                    key: 'name'
+                    key: 'name',
                 },
                 },
                 {
                 {
                     title: '专家评分',
                     title: '专家评分',
@@ -290,6 +356,10 @@ export default {
                     title: '建议分数',
                     title: '建议分数',
                     key: 'score1'
                     key: 'score1'
                 },
                 },
+                {
+                    title: '奖项',
+                    slot: 'awards'
+                },
                 /* {
                 /* {
                     title: '操作',
                     title: '操作',
                     slot: 'actions',
                     slot: 'actions',
@@ -299,6 +369,7 @@ export default {
             ],
             ],
             applicationList: [
             applicationList: [
                 {
                 {
+                    id: '000',
                     name: '张三',
                     name: '张三',
                     sex: '男',
                     sex: '男',
                     phone: '110',
                     phone: '110',
@@ -311,22 +382,42 @@ export default {
                     team: '数学组',
                     team: '数学组',
                     identity: '组长',
                     identity: '组长',
                     work: '',
                     work: '',
+                    _showChildren: true,
+                    children: [
+                        {
+                            id: '001',
+                            name: '李四',
+                            sex: '女',
+                            phone: '911',
+                            email: '331321@qq.com',
+                            school: '醍摩豆学校',
+                            zhiwu: '普通教师',
+                            period: '初中',
+                            subject: '数学',
+                            time: '2023-08-10',
+                            team: '数学组',
+                            identity: '组员',
+                            work: '',
+                        },
+                        {
+                            id: '002',
+                            name: '李四',
+                            sex: '女',
+                            phone: '911',
+                            email: '331321@qq.com',
+                            school: '醍摩豆学校',
+                            zhiwu: '普通教师',
+                            period: '初中',
+                            subject: '数学',
+                            time: '2023-08-10',
+                            team: '数学组',
+                            identity: '组员',
+                            work: '',
+                        },
+                    ],
                 },
                 },
                 {
                 {
-                    name: '李四',
-                    sex: '女',
-                    phone: '911',
-                    email: '331321@qq.com',
-                    school: '醍摩豆学校',
-                    zhiwu: '普通教师',
-                    period: '初中',
-                    subject: '数学',
-                    time: '2023-08-10',
-                    team: '数学组',
-                    identity: '组员',
-                    work: '',
-                },
-                {
+                    id: '010',
                     name: '柳五',
                     name: '柳五',
                     sex: '女',
                     sex: '女',
                     phone: '110',
                     phone: '110',
@@ -339,21 +430,40 @@ export default {
                     team: '语文组',
                     team: '语文组',
                     identity: '组长',
                     identity: '组长',
                     work: '',
                     work: '',
+                    children: [
+                        {
+                            id: '011',
+                            name: '李四',
+                            sex: '女',
+                            phone: '911',
+                            email: '331321@qq.com',
+                            school: '研发学校',
+                            zhiwu: '普通教师',
+                            period: '初中',
+                            subject: '数学',
+                            time: '2023-08-10',
+                            team: '数学组',
+                            identity: '组员',
+                            work: '',
+                        },
+                        {
+                            id: '012',
+                            name: '李四',
+                            sex: '女',
+                            phone: '911',
+                            email: '331321@qq.com',
+                            school: '研发学校',
+                            zhiwu: '普通教师',
+                            period: '初中',
+                            subject: '数学',
+                            time: '2023-08-10',
+                            team: '数学组',
+                            identity: '组员',
+                            work: '',
+                        },
+                    ],
                 },
                 },
-                {
-                    name: '李四',
-                    sex: '女',
-                    phone: '911',
-                    email: '331321@qq.com',
-                    school: '研发学校',
-                    zhiwu: '普通教师',
-                    period: '初中',
-                    subject: '数学',
-                    time: '2023-08-10',
-                    team: '数学组',
-                    identity: '组员',
-                    work: '',
-                },
+                
             ],
             ],
             processList: [
             processList: [
                 {
                 {
@@ -380,11 +490,85 @@ export default {
                     name: '数学组',
                     name: '数学组',
                     score: '67',
                     score: '67',
                     score1: '85',
                     score1: '85',
+                    awards: '',
+                },
+                {
+                    name: '语文组',
+                    score: '92',
+                    score1: '85',
+                    awards: '',
+                },
+                {
+                    name: '数学组',
+                    score: '67',
+                    score1: '85',
+                    awards: '',
+                },
+                {
+                    name: '语文组',
+                    score: '92',
+                    score1: '85',
+                    awards: '',
+                },
+                {
+                    name: '数学组',
+                    score: '67',
+                    score1: '85',
+                    awards: '',
+                },
+                {
+                    name: '语文组',
+                    score: '92',
+                    score1: '85',
+                    awards: '',
+                },
+                {
+                    name: '数学组',
+                    score: '67',
+                    score1: '85',
+                    awards: '',
+                },
+                {
+                    name: '语文组',
+                    score: '92',
+                    score1: '85',
+                    awards: '',
+                },
+                {
+                    name: '数学组',
+                    score: '67',
+                    score1: '85',
+                    awards: '',
+                },
+                {
+                    name: '语文组',
+                    score: '92',
+                    score1: '85',
+                    awards: '',
+                },
+                {
+                    name: '数学组',
+                    score: '67',
+                    score1: '85',
+                    awards: '',
                 },
                 },
                 {
                 {
                     name: '语文组',
                     name: '语文组',
                     score: '92',
                     score: '92',
                     score1: '85',
                     score1: '85',
+                    awards: '',
+                },
+                {
+                    name: '数学组',
+                    score: '67',
+                    score1: '85',
+                    awards: '',
+                },
+                {
+                    name: '语文组',
+                    score: '92',
+                    score1: '85',
+                    awards: '',
                 },
                 },
             ],
             ],
             ruleDrawer: false,
             ruleDrawer: false,
@@ -405,77 +589,6 @@ export default {
                     width: 100,
                     width: 100,
                 },
                 },
             ],
             ],
-            ruleTree: [
-                {
-                    title: 'parent 1',
-                    expand: true,
-                    render: (h, { root, node, data }) => {
-                        return h('span', {
-                            style: {
-                                display: 'inline-block',
-                                width: '100%'
-                            }
-                        }, [
-                            /* h('span', [
-                                h(resolveComponent('Icon'), {
-                                    type: 'ios-folder-outline',
-                                    style: {
-                                        marginRight: '8px'
-                                    }
-                                }),
-                                h('span', data.title)
-                            ]), */
-                            h('span', {
-                                style: {
-                                    display: 'inline-block',
-                                    float: 'right',
-                                    marginRight: '32px'
-                                }
-                            }, /* [
-                                h(resolveComponent('Button'), {
-                                    ...this.buttonProps,
-                                    icon: 'ios-add',
-                                    type: 'primary',
-                                    style: {
-                                        width: '64px'
-                                    },
-                                    onClick: () => { this.append(data) }
-                                })
-                            ] */)
-                        ]);
-                    },
-                    children: [
-                        {
-                            title: 'child 1-1',
-                            expand: true,
-                            children: [
-                                {
-                                    title: 'leaf 1-1-1',
-                                    expand: true
-                                },
-                                {
-                                    title: 'leaf 1-1-2',
-                                    expand: true
-                                }
-                            ]
-                        },
-                        {
-                            title: 'child 1-2',
-                            expand: true,
-                            children: [
-                                {
-                                    title: 'leaf 1-2-1',
-                                    expand: true
-                                },
-                                {
-                                    title: 'leaf 1-2-1',
-                                    expand: true
-                                }
-                            ]
-                        }
-                    ]
-                }
-            ],
             ruleInfo: {
             ruleInfo: {
                 id: '100',
                 id: '100',
                 name: '创新课堂评价标准',
                 name: '创新课堂评价标准',
@@ -557,7 +670,29 @@ export default {
             buttonProps: {
             buttonProps: {
                 type: 'default',
                 type: 'default',
                 size: 'small',
                 size: 'small',
-            }
+            },
+            awardsing: false,
+            awardsList: [
+                {
+                    value: '特等奖',
+                    label: '特等奖'
+                },
+                {
+                    value: '一等奖',
+                    label: '一等奖'
+                },
+                {
+                    value: '二等奖',
+                    label: '二等奖'
+                },
+                {
+                    value: '三等奖',
+                    label: '三等奖'
+                },
+            ],
+            processShow: false,
+            awardsShow: false,
+            awardsSel: '',
         }
         }
     },
     },
     mounted () {
     mounted () {
@@ -701,7 +836,16 @@ export default {
             const parent = root.find(el => el.nodeKey === parentKey).node;
             const parent = root.find(el => el.nodeKey === parentKey).node;
             const index = parent.children.indexOf(data);
             const index = parent.children.indexOf(data);
             parent.children.splice(index, 1);
             parent.children.splice(index, 1);
-        }
+        },
+        setAwards() {
+            this.awardsing = true
+            this.scoreColumns.unshift({
+                type: 'selection',
+                width: 60,
+                align: 'center'
+            })
+            this.$forceUpdate()
+        },
     }
     }
 }
 }
 </script>
 </script>
@@ -773,16 +917,35 @@ export default {
         display: flex;
         display: flex;
         justify-content: space-around;
         justify-content: space-around;
         width: 100%;
         width: 100%;
-        margin-bottom: 30px;
+        margin-bottom: 50px;
+        margin-top: 30px;
         &>div {
         &>div {
-            text-align: center;
+            // text-align: center;
             margin: 0 30px;
             margin: 0 30px;
-            &>p:first-of-type{
+
+            &>p:first-of-type {
+                border-left: 5px solid #70B1F0;
+                padding-left: 5px;
+                height: 15px;
+                line-height: 15px;
+                margin-bottom: 5px;
+            }
+            &>p:nth-child(2){
                 font-size: 30px;
                 font-size: 30px;
                 font-weight: bold;
                 font-weight: bold;
+                color: #6a6a6a;
             }
             }
         }
         }
     }
     }
+
+    .data-box {
+        border-top: 1px dashed #d0d0d0;
+        padding-top: 20px;
+
+        .ivu-input-wrapper {
+            margin-bottom: 10px;
+        }
+    }
 }
 }
 </style>
 </style>
 <style lang="less">
 <style lang="less">

+ 119 - 0
TEAMModelOS/ClientApp/src/view/signupActivity/setActivity.vue

@@ -0,0 +1,119 @@
+<template>
+    <div>
+        <Tabs v-model="activeName">
+            <TabPane label="分站管理" name="subs">
+                <Form :model="formItem" :label-width="120" style="width: 98%;">
+                    <FormItem label="授权单位/组织">
+                        <Input v-model="formItem.unit" placeholder="请输入..." disabled></Input>
+                    </FormItem>
+                    <FormItem label="分站代码">
+                        <Input v-model="formItem.code" placeholder="请输入..." disabled></Input>
+                    </FormItem>
+                    <FormItem label="分站路由">
+                        <Input v-model="formItem.route" placeholder="请输入..." disabled></Input>
+                    </FormItem>
+                </Form>
+            </TabPane>
+            <TabPane label="首页管理" name="homepage">
+                <Table :columns="columns" :data="data" class="banner-set">
+                    <template #type="{row}">
+                        <span>{{ row.type ? '区级' : '公开' }}</span>
+                    </template>
+                    <template #state="{row}">
+                        <Alert :type="row.state === 1 ? 'success' : 'warning'" v-if="row.state">
+                            {{ row.state === 1 ? '进行中' : '已结束' }}
+                        </Alert>
+                        <Alert v-else>未开始</Alert>
+                    </template>
+                    <template #image="{row}">
+                        <img :src="row.image" alt="">
+                    </template>
+                    <template #action="{row}">
+                        <Button type="error" size="small">删除</Button>
+                    </template>
+                </Table>
+            </TabPane>
+        </Tabs>
+    </div>
+</template>
+
+
+<script>
+export default {
+    data () {
+        return {
+            activeName: 'subs',
+            formItem: {
+                unit: '醍摩豆(成都)信息技术有限公司',
+                code: 'TMD',
+                route: '/TeamModel',
+            },
+            columns: [
+                {
+                    title: '活动名称',
+                    key: 'name',
+                    align: 'center',
+                },
+                {
+                    title: '申办人',
+                    key: 'people',
+                    align: 'center',
+                    width: '100',
+                },
+                {
+                    title: '醍摩豆ID',
+                    key: 'tmdid',
+                    align: 'center',
+                    width: '200',
+                },
+                {
+                    title: '活动类型',
+                    slot: 'type',
+                    align: 'center',
+                    width: '100',
+                },
+                {
+                    title: '活动状态',
+                    slot: 'state',
+                    width: '150',
+                    align: 'center',
+                },
+                {
+                    title: '图片',
+                    slot: 'image',
+                    width: '200',
+                    align: 'center',
+                },
+                {
+                    title: '操作',
+                    slot: 'action',
+                    width: '100',
+                    align: 'center',
+                }
+            ],
+            data: [
+                {
+                    name: '2019第八届科技领导卓越奖',
+                    people: '罗老师',
+                    tmdid: '1595321354',
+                    type: 0,
+                    state: 0,
+                    image: require('./demo.jpeg'),
+                },
+            ]
+        }
+    }
+}
+</script>
+
+<style lang="less" scoped>
+.banner-set {
+    img{
+        width: 100%;
+    }
+    .ivu-alert {
+        text-align: center;
+        padding: 5px 0;
+    }
+}
+</style>

+ 14 - 1
TEAMModelOS/ClientApp/src/view/student-web/AppiView.less

@@ -105,4 +105,17 @@
     .myNav .ivu-menu-horizontal .ivu-menu-item {
     .myNav .ivu-menu-horizontal .ivu-menu-item {
         padding: 0 11px !important;
         padding: 0 11px !important;
     }
     }
-}
+}
+
+@media screen and (max-width: 520px) {
+    .myNav .selectClass {
+        .ivu-select {
+            &:first-child {
+                width: 105px !important;
+            }
+            &:nth-child(2) {
+                width: 150px !important;
+            }
+        }
+    }
+}

+ 4 - 14
TEAMModelOS/Controllers/Both/CourseBaseController.cs

@@ -16,21 +16,11 @@ using Azure;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Configuration;
 using TEAMModelOS.Filter; 
 using TEAMModelOS.Filter; 
 using HTEXLib.COMM.Helpers; 
 using HTEXLib.COMM.Helpers; 
-using System.Globalization;
 using TEAMModelOS.SDK;
 using TEAMModelOS.SDK;
-using Microsoft.AspNetCore.Authorization;
 using StackExchange.Redis;
 using StackExchange.Redis;
-using Azure.Storage.Blobs.Models;
-using Microsoft.Azure.Amqp.Sasl;
-using DocumentFormat.OpenXml.Drawing.Charts;
-using FastJSON;
-using OpenXmlPowerTools;
-using DocumentFormat.OpenXml.Drawing.Spreadsheet;
+
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
-using System.Security.Claims;
-using DocumentFormat.OpenXml.Bibliography;
-using DocumentFormat.OpenXml.Spreadsheet;
-using static SKIT.FlurlHttpClient.Wechat.TenpayV3.Models.CreateApplyForSubjectApplymentRequest.Types;
+using Microsoft.AspNetCore.Authorization;
 
 
 namespace TEAMModelOS.Controllers.Both
 namespace TEAMModelOS.Controllers.Both
 {
 {
@@ -2045,9 +2035,9 @@ namespace TEAMModelOS.Controllers.Both
         [ProducesDefaultResponseType]
         [ProducesDefaultResponseType]
         [AuthToken(Roles = "teacher,admin")]
         [AuthToken(Roles = "teacher,admin")]
         [HttpPost("teacher")]
         [HttpPost("teacher")]
-#if !DEBUG
+ 
         [Authorize(Roles = "IES")]
         [Authorize(Roles = "IES")]
-#endif
+ 
         public async Task<IActionResult> Teacher(JsonElement request)
         public async Task<IActionResult> Teacher(JsonElement request)
         {
         {
 
 

+ 34 - 33
TEAMModelOS/Controllers/Both/ScoreCalcController.cs

@@ -736,7 +736,7 @@ namespace TEAMModelOS.Controllers
                             zeroScores.Add(0);
                             zeroScores.Add(0);
                         }
                         }
                         for (int k = 0; k < scoreCalcActivityBaseList_copy.Count; k++)
                         for (int k = 0; k < scoreCalcActivityBaseList_copy.Count; k++)
-                        {                         
+                        {
                             switch (scoreCalcActivityBaseList_copy[k].type)
                             switch (scoreCalcActivityBaseList_copy[k].type)
                             {
                             {
                                 case "lessonrecord":
                                 case "lessonrecord":
@@ -773,12 +773,12 @@ namespace TEAMModelOS.Controllers
                                 case "homework":
                                 case "homework":
                                     // ===設定作業活動===
                                     // ===設定作業活動===
                                     await setCopyAct(scoreCalcActivityBaseList_copy[k].id, teammodelId, scoreCalcActivity_homework, zeroScores);
                                     await setCopyAct(scoreCalcActivityBaseList_copy[k].id, teammodelId, scoreCalcActivity_homework, zeroScores);
-                                    scoreCalcActivity_homework = await clientTeacher.CreateItemAsync(scoreCalcActivity_homework, new PartitionKey($"{scoreCalcActivity_homework.code}"));                                   
+                                    scoreCalcActivity_homework = await clientTeacher.CreateItemAsync(scoreCalcActivity_homework, new PartitionKey($"{scoreCalcActivity_homework.code}"));
                                     break;
                                     break;
                                 case "exam":
                                 case "exam":
                                     // ===設定評量活動===
                                     // ===設定評量活動===
                                     await setCopyAct(scoreCalcActivityBaseList_copy[k].id, teammodelId, scoreCalcActivity_eaxm, zeroScores);
                                     await setCopyAct(scoreCalcActivityBaseList_copy[k].id, teammodelId, scoreCalcActivity_eaxm, zeroScores);
-                                    scoreCalcActivity_eaxm = await clientTeacher.CreateItemAsync(scoreCalcActivity_eaxm, new PartitionKey($"{scoreCalcActivity_eaxm.code}"));                                   
+                                    scoreCalcActivity_eaxm = await clientTeacher.CreateItemAsync(scoreCalcActivity_eaxm, new PartitionKey($"{scoreCalcActivity_eaxm.code}"));
                                     break;
                                     break;
                                 case "custom":
                                 case "custom":
                                     // ===自訂項目===
                                     // ===自訂項目===
@@ -793,21 +793,21 @@ namespace TEAMModelOS.Controllers
                                     scoreCalcActivity.editScores = editScores;
                                     scoreCalcActivity.editScores = editScores;
                                     scoreCalcActivity.code = scoreCalcActivityBaseList_copy[k].pk + "-" + teammodelId;
                                     scoreCalcActivity.code = scoreCalcActivityBaseList_copy[k].pk + "-" + teammodelId;
                                     await setCopyAct(scoreCalcActivityBaseList_copy[k].id, teammodelId, scoreCalcActivity, zeroScores);
                                     await setCopyAct(scoreCalcActivityBaseList_copy[k].id, teammodelId, scoreCalcActivity, zeroScores);
-                                    
+
                                     // 新增項目及子項目
                                     // 新增項目及子項目
-                                    scoreCalcActivity = await clientTeacher.CreateItemAsync(scoreCalcActivity, new PartitionKey($"{scoreCalcActivity.pk + "-" + teammodelId}"));                                                                     
+                                    scoreCalcActivity = await clientTeacher.CreateItemAsync(scoreCalcActivity, new PartitionKey($"{scoreCalcActivity.pk + "-" + teammodelId}"));
                                     break;
                                     break;
                             }
                             }
                         }
                         }
                     }
                     }
-                    else 
+                    else
                     {// 沒有複製id的資料  走原本的新增動作
                     {// 沒有複製id的資料  走原本的新增動作
-                        isCopyMode = false;                        
-                    }                                      
+                        isCopyMode = false;
+                    }
                 }
                 }
                 else
                 else
                 {// 沒有複製id  走原本的新增動作
                 {// 沒有複製id  走原本的新增動作
-                    isCopyMode = false;                    
+                    isCopyMode = false;
                 }
                 }
 
 
                 if (!isCopyMode) // 不是複製模式  走原本的新增動作
                 if (!isCopyMode) // 不是複製模式  走原本的新增動作
@@ -829,7 +829,7 @@ namespace TEAMModelOS.Controllers
                     await foreach (var item in clientTeacher.GetItemQueryIterator<ScoreCalcFunc>(queryText: sql_FormulaCopy))
                     await foreach (var item in clientTeacher.GetItemQueryIterator<ScoreCalcFunc>(queryText: sql_FormulaCopy))
                     {
                     {
                         scoreCalcFuncList_copy.Add(item);
                         scoreCalcFuncList_copy.Add(item);
-                    }                   
+                    }
 
 
 
 
                     for (int i = 0; i < scoreCalcFuncList_copy.Count; i++)
                     for (int i = 0; i < scoreCalcFuncList_copy.Count; i++)
@@ -1224,29 +1224,6 @@ namespace TEAMModelOS.Controllers
                 // 比對資料  決定哪些公式及項目表要更新
                 // 比對資料  決定哪些公式及項目表要更新
                 for (int i = 0; i < updateFormulaRq.scoreCalcFunc.Count; i++)
                 for (int i = 0; i < updateFormulaRq.scoreCalcFunc.Count; i++)
                 {
                 {
-                    #region 更新項目表公式id
-                    if (updateFormulaRq.scoreCalcFunc[i].use)
-                    {
-                        // 更新項目使用的公式id
-                        // 取課堂紀錄資料
-                        // ToDo...以後可能需要其他活動也可以用公式
-                        ScoreCalcLsRecord scoreCalcLsRecord = await clientTeacher.ReadItemAsync<ScoreCalcLsRecord>(updateFormulaRq.scoreCalcActId, new PartitionKey($"ScoreCalcAct-{teammodelId}"));
-                        switch (updateFormulaRq.method)
-                        {
-                            case "attend":
-                                scoreCalcLsRecord.stuAttendFunctionId = updateFormulaRq.scoreCalcFunc[i].id;
-                                break;
-                            case "point":
-                                scoreCalcLsRecord.stuPointFunctionId = updateFormulaRq.scoreCalcFunc[i].id;
-                                break;
-                            case "interaction":
-                                scoreCalcLsRecord.stuItactFunctionId = updateFormulaRq.scoreCalcFunc[i].id;
-                                break;
-                        }
-                        scoreCalcLsRecord = await clientTeacher.ReplaceItemAsync(scoreCalcLsRecord, $"{scoreCalcLsRecord.id}", new PartitionKey(scoreCalcLsRecord.code));
-                    }
-                    #endregion
-
                     #region 更新 or 新增公式
                     #region 更新 or 新增公式
                     for (int j = 0; j < scoreCalcFuncs.Count; j++)
                     for (int j = 0; j < scoreCalcFuncs.Count; j++)
                     {
                     {
@@ -1264,6 +1241,7 @@ namespace TEAMModelOS.Controllers
                         ScoreCalcFunc scoreCalcFunc = new ScoreCalcFunc();
                         ScoreCalcFunc scoreCalcFunc = new ScoreCalcFunc();
                         scoreCalcFunc.code = $"ScoreCalcActFormula-{teammodelId}";
                         scoreCalcFunc.code = $"ScoreCalcActFormula-{teammodelId}";
                         scoreCalcFunc.id = Guid.NewGuid().ToString();
                         scoreCalcFunc.id = Guid.NewGuid().ToString();
+                        updateFormulaRq.scoreCalcFunc[i].id = scoreCalcFunc.id;// 同時設定要新增的公式Id給Act
                         scoreCalcFunc.name = updateFormulaRq.scoreCalcFunc[i].name;
                         scoreCalcFunc.name = updateFormulaRq.scoreCalcFunc[i].name;
                         scoreCalcFunc.scorecalcActId = updateFormulaRq.scoreCalcActId;
                         scoreCalcFunc.scorecalcActId = updateFormulaRq.scoreCalcActId;
                         // ToDo...以後可能需要其他活動也可以用公式
                         // ToDo...以後可能需要其他活動也可以用公式
@@ -1275,6 +1253,29 @@ namespace TEAMModelOS.Controllers
                         scoreCalcFunc = await clientTeacher.CreateItemAsync(scoreCalcFunc, new PartitionKey($"{scoreCalcFunc.code}"));
                         scoreCalcFunc = await clientTeacher.CreateItemAsync(scoreCalcFunc, new PartitionKey($"{scoreCalcFunc.code}"));
                     }
                     }
                     #endregion
                     #endregion
+
+                    #region 更新項目表公式id
+                    if (updateFormulaRq.scoreCalcFunc[i].use)
+                    {
+                        // 更新項目使用的公式id
+                        // 取課堂紀錄資料
+                        // ToDo...以後可能需要其他活動也可以用公式
+                        ScoreCalcLsRecord scoreCalcLsRecord = await clientTeacher.ReadItemAsync<ScoreCalcLsRecord>(updateFormulaRq.scoreCalcActId, new PartitionKey($"ScoreCalcAct-{teammodelId}"));
+                        switch (updateFormulaRq.method)
+                        {
+                            case "attend":
+                                scoreCalcLsRecord.stuAttendFunctionId = updateFormulaRq.scoreCalcFunc[i].id;
+                                break;
+                            case "point":
+                                scoreCalcLsRecord.stuPointFunctionId = updateFormulaRq.scoreCalcFunc[i].id;
+                                break;
+                            case "interaction":
+                                scoreCalcLsRecord.stuItactFunctionId = updateFormulaRq.scoreCalcFunc[i].id;
+                                break;
+                        }
+                        scoreCalcLsRecord = await clientTeacher.ReplaceItemAsync(scoreCalcLsRecord, $"{scoreCalcLsRecord.id}", new PartitionKey(scoreCalcLsRecord.code));
+                    }
+                    #endregion
                 }
                 }
 
 
 
 

+ 628 - 51
TEAMModelOS/Controllers/Client/AClassONEController.cs

@@ -1,9 +1,12 @@
 using Azure.Cosmos;
 using Azure.Cosmos;
 using Azure.Storage.Blobs.Models;
 using Azure.Storage.Blobs.Models;
+using Azure.Storage.Sas;
 using DocumentFormat.OpenXml.Drawing.Charts;
 using DocumentFormat.OpenXml.Drawing.Charts;
 using DocumentFormat.OpenXml.Office2010.Excel;
 using DocumentFormat.OpenXml.Office2010.Excel;
 using DocumentFormat.OpenXml.Office2021.DocumentTasks;
 using DocumentFormat.OpenXml.Office2021.DocumentTasks;
+using DocumentFormat.OpenXml.Presentation;
 using DocumentFormat.OpenXml.Spreadsheet;
 using DocumentFormat.OpenXml.Spreadsheet;
+using DocumentFormat.OpenXml.Wordprocessing;
 using HTEXLib.COMM.Helpers;
 using HTEXLib.COMM.Helpers;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http;
@@ -25,6 +28,8 @@ using System.Text;
 using System.Text.Json;
 using System.Text.Json;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using TEAMModelOS.Controllers.Analysis;
 using TEAMModelOS.Controllers.Analysis;
+using TEAMModelOS.Controllers.Both;
+using TEAMModelOS.Filter;
 using TEAMModelOS.Models;
 using TEAMModelOS.Models;
 using TEAMModelOS.SDK;
 using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.DI;
@@ -32,8 +37,13 @@ using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos.Common;
 using TEAMModelOS.SDK.Models.Cosmos.Common;
 using TEAMModelOS.SDK.Models.Cosmos.Student;
 using TEAMModelOS.SDK.Models.Cosmos.Student;
+using TEAMModelOS.SDK.Models.Service;
 using TEAMModelOS.SDK.Services;
 using TEAMModelOS.SDK.Services;
+using TEAMModelOS.Services;
 using static TEAMModelOS.SDK.Services.BlobService;
 using static TEAMModelOS.SDK.Services.BlobService;
+using CourseDto = TEAMModelOS.Controllers.Both.CourseDto;
+using Period = TEAMModelOS.SDK.Models.Period;
+
 namespace TEAMModelOS.Controllers
 namespace TEAMModelOS.Controllers
 {
 {
 
 
@@ -61,13 +71,16 @@ namespace TEAMModelOS.Controllers
         private readonly Option _option;
         private readonly Option _option;
         private readonly SnowflakeId _snowflakeId;
         private readonly SnowflakeId _snowflakeId;
         private readonly IConfiguration _configuration;
         private readonly IConfiguration _configuration;
+        private readonly CoreAPIHttpService _coreAPIHttpService;
+        private readonly HttpTrigger _httpTrigger;
+        private readonly IPSearcher _searcher;
         public AClassONEController(
         public AClassONEController(
             AzureStorageFactory azureStorage,
             AzureStorageFactory azureStorage,
             AzureRedisFactory azureRedis,
             AzureRedisFactory azureRedis,
             AzureCosmosFactory azureCosmos,
             AzureCosmosFactory azureCosmos,
             DingDing dingDing,
             DingDing dingDing,
             SnowflakeId snowflakeId,
             SnowflakeId snowflakeId,
-            IOptionsSnapshot<Option> option, IHttpClientFactory httpClient, IConfiguration configuration)
+            IOptionsSnapshot<Option> option, IHttpClientFactory httpClient, IConfiguration configuration, CoreAPIHttpService coreAPIHttpService, IPSearcher searcher, HttpTrigger httpTrigger)
         {
         {
             _azureStorage = azureStorage;
             _azureStorage = azureStorage;
             _azureRedis = azureRedis;
             _azureRedis = azureRedis;
@@ -77,6 +90,9 @@ namespace TEAMModelOS.Controllers
             _option = option?.Value;
             _option = option?.Value;
             _httpClient = httpClient;
             _httpClient = httpClient;
             _configuration = configuration;
             _configuration = configuration;
+            _coreAPIHttpService=coreAPIHttpService;
+            _searcher=searcher;
+            _httpTrigger=httpTrigger;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -119,21 +135,527 @@ namespace TEAMModelOS.Controllers
                 return BadRequest(Content);
                 return BadRequest(Content);
             }
             }
         }
         }
-
         /// <summary>
         /// <summary>
-        /// 根据家长手机号获取监护学生的信息
+        /// 获取教师信息
         /// </summary>
         /// </summary>
         /// <param name="json"></param>
         /// <param name="json"></param>
         /// <returns></returns>
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [ProducesDefaultResponseType]
-        [HttpPost("get-students-by-mobile")]
+        [HttpPost("get-teacher-info")]
 #if !DEBUG
 #if !DEBUG
         [Authorize(Roles = "AClassONE")]
         [Authorize(Roles = "AClassONE")]
 #endif
 #endif
-        public async Task<IActionResult> GetStudentsByPhone(JsonElement json) {
+        public async Task<IActionResult> GetTeacherInfo(JsonElement json)
+        {
+            string head_lang = "";
+
+            if (HttpContext.Request.Headers.TryGetValue("lang", out var _lang))
+            {
+                head_lang = $"{_lang}";
+            }
+            if (!json.TryGetProperty("code", out JsonElement _code)) return BadRequest("code is null");
+            var phoneInfo = await GetWeChatPhoneNumber(_code.ToString());
+            if (phoneInfo.code==200)
+            {
+                string _mobile = phoneInfo.phone.phoneNumber;
+                var coreUser = await _coreAPIHttpService.GetUserInfo(new Dictionary<string, string> { { "key", $"{_mobile}" } }, _option.Location, _configuration);
+                if (coreUser != null && coreUser.id != null)
+                {
+                    (string ip, string region) = await LoginService.LoginIp(HttpContext, _searcher);
+                    Teacher teacher = null;
+                    TeacherInfo teacherInfo = await TeacherService.TeacherInfo(_azureCosmos, teacher, $"{coreUser.name}", $"{coreUser.picture}", coreUser.id, _azureStorage, _option, _azureRedis, ip, _httpTrigger, $"{_lang}");
+                    return Ok(new
+                    {
+                        teacherInfo.auth_token,
+                        teacherInfo.blob_uri,
+                        teacherInfo.blob_sas,
+                        teacherInfo.schools,
+                        teacherInfo.defaultschool,
+                    });
+                }
+                else return Ok(new { state = 404, msg = "未找到关联账号" });
+            }
             return Ok();
             return Ok();
         }
         }
+        /// <summary>
+        /// 获取学校信息
+        /// </summary>
+        /// <param name="json"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-school-info")]
+#if !DEBUG
+        [Authorize(Roles = "AClassONE")]
+#endif
+        [AuthToken(Roles = "teacher")]
+        public async Task<IActionResult> GetSchoolInfo(JsonElement json) {
+            (string tmdid, _, _, string school) = HttpContext.GetAuthTokenInfo();
+            if (!json.TryGetProperty("school_code", out JsonElement _school_code)) return BadRequest();
+            string school_code = $"{_school_code}";
+            List<string> roles = new List<string>();
+            List<string> permissions = new List<string>();
+            var client = _azureCosmos.GetCosmosClient();
+            int size = 0;
+            Teacher teacher = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<Teacher>(tmdid, new PartitionKey("Base"));
+            List<AreaDto> areas = new List<AreaDto>();
+            HashSet<string> areaIds = new HashSet<string>();
+            if (teacher.areas.IsNotEmpty())
+            {
+                teacher.areas.ForEach(x => {
+                    areaIds.Add(x.areaId);
+                });
+            }
+            if (teacher.schools.IsNotEmpty())
+            {
+                teacher.schools.ForEach(x => {
+                    if (!string.IsNullOrEmpty(x.areaId))
+                    {
+                        areaIds.Add(x.areaId);
+                    }
 
 
+                });
+            }
+            List<Area> areasDbs = new List<Area>();
+            List<AreaSetting> areaSettings = new List<AreaSetting>();
+            if (areaIds.Count > 0)
+            {
+                string queryText = $"select value(c) from c where c.id in ({string.Join(",", areaIds.Select(x => $"'{x}'"))})";
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Area>(queryText: queryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base-Area") }))
+                {
+                    areasDbs.Add(item);
+                }
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<AreaSetting>(queryText: queryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("AreaSetting") }))
+                {
+                    areaSettings.Add(item);
+                }
+            }
+            if (teacher.areas.IsNotEmpty())
+            {
+                foreach (var areat in teacher.areas)
+                {
+
+                    Area area = areasDbs.Find(x => x.id.Equals(areat.areaId));
+                    AreaSetting setting = null;
+                    if (area != null)
+                    {
+                        setting = areaSettings.Find(x => x.id.Equals(areat.areaId));
+                    }
+
+                    int access = 0;
+                    if (setting != null && !string.IsNullOrWhiteSpace(setting.accessConfig))
+                    {
+                        access = 1;
+                    }
+                    //if (setting != null)
+                    //{
+                    //    setting.accessConfig = null;
+                    //}
+                    areas.Add(new AreaDto { shortCode=area?.shortCode, areaId = area?.id, name = area?.name, standard = area?.standard, standardName = area?.standardName, setting = setting, access = access });
+                }
+            }
+            if (school_code.Equals(teacher.defaultSchool) && teacher.schools.IsNotEmpty() && !teacher.schools.Select(x => x.schoolId).Contains(school_code))
+            {
+                school_code = teacher.schools[0].schoolId;
+                teacher.defaultSchool = school_code;
+                teacher = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, tmdid, new PartitionKey("Base"));
+            }
+            var response = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(tmdid, new PartitionKey($"Teacher-{school_code}"));
+            string defaultPeriodId = "";
+            if (response.Status == 200)
+            {
+                using var jsonData = await JsonDocument.ParseAsync(response.ContentStream);
+                if (jsonData.RootElement.TryGetProperty("size", out JsonElement _size) && _size.ValueKind == JsonValueKind.Number)
+                {
+                    size = _size.GetInt32();
+                }
+                if (jsonData.RootElement.TryGetProperty("periodId", out JsonElement _periodId))
+                {
+                    defaultPeriodId =$"{_periodId}";
+                }
+                if (jsonData.RootElement.TryGetProperty("roles", out JsonElement _roles) && _roles.ValueKind != JsonValueKind.Null)
+                {
+                    foreach (var obj in _roles.EnumerateArray())
+                    {
+                        roles.Add(obj.GetString());
+                    }
+                }
+                if (jsonData.RootElement.TryGetProperty("permissions", out JsonElement _permissions) && _permissions.ValueKind != JsonValueKind.Null)
+                {
+                    foreach (var obj in _permissions.EnumerateArray())
+                    {
+                        permissions.Add(obj.GetString());
+                    }
+                }
+                var scteacher = jsonData.RootElement.ToObject<SchoolTeacher>();
+                if (!$"{teacher.name}".Equals($"{scteacher?.name}") || !$"{teacher.picture}".Equals($"{scteacher?.picture}"))
+                {
+                    scteacher.name=teacher.name;
+                    scteacher.picture=teacher.picture;
+                    await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<SchoolTeacher>(scteacher, scteacher.id, new PartitionKey(scteacher.code));
+                }
+            }
+            if (roles.Count == 0)
+            {
+                //助理,管家
+                //roles.Add("assist");
+                roles.Add("teacher");
+            }
+            School school_base = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{school_code}", new PartitionKey("Base"));
+            string currAreaId = "";
+            dynamic currArea = new ExpandoObject();
+            if (!string.IsNullOrEmpty(school_base.areaId))
+            {
+                try
+                {
+                    Area area = areasDbs.Find(x => x.id.Equals(school_base.areaId));
+                    AreaSetting setting = null;
+                    if (area != null)
+                    {
+                        //setting =await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<AreaSetting>(school_base.areaId, new PartitionKey("AreaSetting"));
+                        setting = areaSettings.Find(x => x.id.Equals(school_base.areaId));
+                    }
+
+                    int access = 0;
+                    AccessConfig accessConfig = null;
+                    if (setting != null && !string.IsNullOrWhiteSpace(setting.accessConfig))
+                    {
+                        access = 1;
+                        accessConfig = setting.accessConfig.ToObject<AccessConfig>();
+                    }
+                    //if (setting!=null&& !string.IsNullOrEmpty(setting.accessConfig)) {
+                    //    setting.accessConfig = null;
+                    //}
+                    currArea = new
+                    {
+                        shortCode = area?.shortCode,
+                        areaId = area?.id,
+                        name = area?.name,
+                        standard = area?.standard,
+                        standardName = area?.standardName,
+                        setting = setting,
+                        access = access,
+                        //submitType=accessConfig?.submitType,
+                        homeworkType = accessConfig != null && accessConfig.homeworkType.IsNotEmpty() ? accessConfig.homeworkType : new List<string> { "pdf" },
+                    };
+                    currAreaId = area?.id;
+                }
+                catch (CosmosException)
+                {
+                    //数据库捞不到数据
+
+                }
+            }
+            if (areas.Count > 0)
+            {
+                roles.Add("area");
+            }
+            areas.ForEach(x => { { if (x.setting != null) { x.setting.accessConfig = x.setting.accessConfig; } } });
+
+            var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName,teacher. id, teacher.name, teacher.picture, _option.JwtSecretKey, Website: "IES", scope: Constant.ScopeTeacher, schoolID: school_code.ToString(), areaId: currAreaId, standard: school_base.standard, roles: roles.ToArray(), permissions: permissions.ToArray(), expire: 1);
+            string school_code_blob = school_code.ToLower();
+            var container = _azureStorage.GetBlobContainerClient(school_code_blob);
+            await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建School容器,如存在則不做任何事,保障容器一定存在
+            var (blob_uri, blob_sas) = (roles.Contains("admin") || permissions.Contains("schoolAc-upd")) ? _azureStorage.GetBlobContainerSAS(school_code_blob, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete) : _azureStorage.GetBlobContainerSAS(school_code_blob, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Write);
+
+            return Ok(new {
+                auth_token,
+                blob_uri,
+                blob_sas,
+                school_base,
+                areas,
+                currArea,
+            });
+        }
+        /// <summary>
+        /// 获取教师的教学信息
+        /// </summary>
+        /// <param name="json"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-teach-info")]
+#if !DEBUG
+        [Authorize(Roles = "AClassONE")]
+#endif
+        [AuthToken(Roles = "teacher")]
+        public async Task<IActionResult> GetTeachInfo(JsonElement json) {
+            (string tmdid, _, _, string school) = HttpContext.GetAuthTokenInfo();
+            List<KeyValuePair<string, CourseTask>> schoolTeacherTask = new List<KeyValuePair<string, CourseTask>>();
+            List<KeyValuePair<string, CourseTask>> schoolAssistantTask = new List<KeyValuePair<string, CourseTask>>();
+
+            List<KeyValuePair<string, CourseTask>> privateTeacherTask = new List<KeyValuePair<string, CourseTask>>();
+            List<KeyValuePair<string, CourseTask>> privateAssistantTask = new List<KeyValuePair<string, CourseTask>>();
+            List<Both.CourseDto> schoolCourses = new List<CourseDto>();
+            List<CourseDto> teahcerCourses = new List<CourseDto>();
+            List<string> groupIds = new List<string>();
+            HashSet<string> hashGroupIds = new HashSet<string>();
+            List<Class> classes = new List<Class>();
+            Period periodSchool = null;
+            if (!string.IsNullOrWhiteSpace(school)) {
+                //班主任
+                string sqlClassTeacher = $"select value c from c where c.teacher.id='{tmdid}'";
+                var resultClass =   await  _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<Class>(sqlClassTeacher, $"Class-{school}");
+                if (resultClass.list.IsNotEmpty()) 
+                {
+                    classes.AddRange(resultClass.list);
+                    hashGroupIds = new HashSet<string>(resultClass.list.Select(z=>z.id));
+                }
+                //执教
+                //协同
+                //管理员
+                string sql = $"SELECT distinct value c FROM c  join b in c.schedules where c.pk='CourseTask' and (ARRAY_CONTAINS(b.assistants,'{tmdid}')or  b.teacherId  ='{tmdid}' )";
+               
+                School schoolBase = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(school, new PartitionKey("Base"));
+                JsonElement year = default, semesterId = default, _periodId = default;
+                int _year = -1;
+                string _semesterId=string.Empty;
+                if (!json.TryGetProperty("periodId", out _periodId)) return BadRequest();
+                if (json.TryGetProperty("year", out year))
+                {
+                    _year= int.Parse($"{_year}");
+                }
+                if (json.TryGetProperty("semesterId", out semesterId))
+                {
+                    _semesterId=$"{semesterId}";
+                }
+             
+                var period = schoolBase.period.Find(x => x.id.Equals($"{_periodId}"));
+                periodSchool=period;
+                if (_year==-1 || string.IsNullOrWhiteSpace(_semesterId))
+                {
+
+                    var semesterInfo = SchoolService.GetSemester(period, DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());
+                    if (_year==-1) {
+                        _year=semesterInfo.studyYear;                    
+                    }
+                    if (string.IsNullOrWhiteSpace(_semesterId)) {
+                        _semesterId=semesterInfo.currSemester.id;
+                    }
+                }
+               
+                //string date = SchoolService.GetOpensByStudyYearAndSemester(period.semesters, int.Parse($"{_year}"), $"{_semesterId}");
+                sql = $"{sql} and  c.year={_year} and c.semesterId='{_semesterId}'";
+                HashSet<string> courseIds = new HashSet<string>();
+                var resultSchool = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<CourseTask>(sql, $"CourseTask-{school}");
+                if (resultSchool.list.IsNotEmpty())
+                {
+                    resultSchool.list.ForEach(x => {
+                        var schedulesTeacher = x.schedules.Where(z => !string.IsNullOrWhiteSpace(z.teacherId)   && z.teacherId.Equals(tmdid));
+                        if (schedulesTeacher.Any())
+                        {
+                            courseIds.Add(x.courseId);
+                            CourseTask courseTask = x.ToJsonString().ToObject<CourseTask>();
+                            courseTask.schedules=schedulesTeacher.ToList();
+                            schoolTeacherTask.Add(new KeyValuePair<string, CourseTask>(x.courseId, courseTask));
+
+                            //groupIds.AddRange(schedulesTeacher.Where(z => !string.IsNullOrWhiteSpace(z.groupId)).Select(x => x.groupId));
+                            var gpids=  schedulesTeacher.Where(z => !string.IsNullOrWhiteSpace(z.groupId)).Select(x => x.groupId);
+                            if (gpids!=null  && gpids.Count()>0) 
+                            {
+                                foreach (var gp in gpids) {
+                                    hashGroupIds.Add(gp);
+                                }
+                            }
+                        }
+                        var schedulesAssistant = x.schedules.Where(z => z.assistants.Contains(tmdid));
+                        if (schedulesAssistant.Any())
+                        {
+                            courseIds.Add(x.courseId);
+                            CourseTask courseTask = x.ToJsonString().ToObject<CourseTask>();
+                            courseTask.schedules=schedulesAssistant.ToList();
+                            schoolAssistantTask.Add(new KeyValuePair<string, CourseTask>(x.courseId, courseTask));
+                            //groupIds.AddRange(schedulesAssistant.Where(z => !string.IsNullOrWhiteSpace(z.groupId)).Select(x => x.groupId));
+                            var gpids = schedulesAssistant.Where(z => !string.IsNullOrWhiteSpace(z.groupId)).Select(x => x.groupId);
+                            if (gpids!=null  && gpids.Count()>0)
+                            {
+                                foreach (var gp in gpids)
+                                {
+                                    hashGroupIds.Add(gp);
+                                }
+                            }
+                        }
+                    });
+                }
+                if (courseIds.Any())
+                {
+                    string sqlCourse = $"select value c from c where c.id in ({string.Join(",", courseIds.Select(b => $"'{b}'"))})";
+                    var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<CourseBase>(sqlCourse, $"CourseBase-{school}");
+                    if (result.list.IsNotEmpty())
+                    {
+                        foreach (var item in result.list)
+                        {
+                            List<CourseTaskDto> courseTaskDtos = new List<CourseTaskDto>();
+                            var teacher = schoolTeacherTask.Where(x => x.Key.Equals(item.id)).Select(z => new CourseTaskDto { courseTask=z.Value, type="teacher" });
+                            if (teacher.Any())
+                            {
+                                courseTaskDtos.AddRange(teacher.ToList());
+                            }
+                            var assistant = schoolAssistantTask.Where(x => x.Key.Equals(item.id)).Select(z => new CourseTaskDto { courseTask=z.Value, type="assistant" });
+                            if (assistant.Any())
+                            {
+                                courseTaskDtos.AddRange(assistant.ToList());
+                            }
+                            schoolCourses.Add(new Both.CourseDto { courseBase=item, courseTasks=courseTaskDtos });
+                        }
+                    }
+                }
+            }
+
+
+            //个人
+            {
+                HashSet<string> courseIds = new HashSet<string>();
+                string sqlCoursePrivate = $"select value c.id from c where  c.creatorId='{tmdid}'";
+                var resultCourseBasePrivate = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<string>(sqlCoursePrivate, $"CourseBase");
+                if (resultCourseBasePrivate.list.IsNotEmpty())
+                {
+                    courseIds=new HashSet<string>(resultCourseBasePrivate.list);
+                }
+                string sqlprivate = $"SELECT distinct value c FROM c  join b in c.schedules where c.pk='CourseTask' and (ARRAY_CONTAINS(b.assistants,'{tmdid}')or  b.teacherId  ='{tmdid}' )";
+                var resultTeacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<CourseTask>(sqlprivate, $"CourseTask");
+                if (resultTeacher.list.IsNotEmpty())
+                {
+
+                    resultTeacher.list.ForEach(x => {
+                        var schedulesTeacher = x.schedules.Where(z => !string.IsNullOrWhiteSpace(z.teacherId)  &&  z.teacherId.Equals(tmdid));
+                        if (schedulesTeacher.Any())
+                        {
+                            courseIds.Add(x.courseId);
+                            CourseTask courseTask = x.ToJsonString().ToObject<CourseTask>();
+                            courseTask.schedules=schedulesTeacher.ToList();
+                            privateTeacherTask.Add(new KeyValuePair<string, CourseTask>(x.courseId, courseTask));
+                            groupIds.AddRange(schedulesTeacher.Where(z => !string.IsNullOrWhiteSpace(z.groupId)).Select(x => x.groupId));
+                            var gpids = schedulesTeacher.Where(z => !string.IsNullOrWhiteSpace(z.groupId));
+                            if (gpids!=null  && gpids.Count()>0)
+                            {
+                                foreach (var gp in gpids)
+                                {
+                                    if (!string.IsNullOrWhiteSpace(gp.school))
+                                    {
+                                        if (!string.IsNullOrWhiteSpace(school) && gp.school.Equals(school))
+                                        {
+                                            hashGroupIds.Add(gp.groupId);
+                                        }
+                                    }
+                                    else {
+                                        hashGroupIds.Add(gp.groupId);
+                                    }
+                                   
+                                }
+                            }
+                        }
+                        var schedulesAssistant = x.schedules.Where(z => z.assistants.Contains(tmdid));
+                        if (schedulesAssistant.Any())
+                        {
+                            courseIds.Add(x.courseId);
+                            CourseTask courseTask = x.ToJsonString().ToObject<CourseTask>();
+                            courseTask.schedules=schedulesAssistant.ToList();
+                            privateAssistantTask.Add(new KeyValuePair<string, CourseTask>(x.courseId, courseTask));
+                            groupIds.AddRange(schedulesAssistant.Where(z => !string.IsNullOrWhiteSpace(z.groupId)).Select(x => x.groupId));
+                            var gpids = schedulesAssistant.Where(z => !string.IsNullOrWhiteSpace(z.groupId));
+                            if (gpids!=null  && gpids.Count()>0)
+                            {
+                                foreach (var gp in gpids)
+                                {
+                                    if (!string.IsNullOrWhiteSpace(gp.school))
+                                    {
+                                        if (!string.IsNullOrWhiteSpace(school) && gp.school.Equals(school)) {
+                                            hashGroupIds.Add(gp.groupId);
+                                        }
+                                    }
+                                    else
+                                    {
+                                        hashGroupIds.Add(gp.groupId);
+                                    }
+                                }
+                            }
+                        }
+                    });
+
+                }
+                if (courseIds.Any())
+                {
+                    string sqlCourse = $"select distinct value c from c where c.code='CourseBase' and  ( c.creatorId='{tmdid}' or  c.id in ({string.Join(",", courseIds.Select(b => $"'{b}'"))}))";
+                    var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<CourseBase>(sqlCourse, $"CourseBase");
+                    if (result.list.IsNotEmpty())
+                    {
+                        foreach (var item in result.list)
+
+                        {
+                            List<CourseTaskDto> courseTaskDtos = new List<CourseTaskDto>();
+                            var teacher = privateTeacherTask.Where(x => x.Key.Equals(item.id)).Select(z => new CourseTaskDto { courseTask=z.Value, type="teacher" });
+                            if (teacher.Any())
+                            {
+                                courseTaskDtos.AddRange(teacher.ToList());
+                            }
+                            var assistant = privateAssistantTask.Where(x => x.Key.Equals(item.id)).Select(z => new CourseTaskDto { courseTask=z.Value, type="assistant" });
+                            if (assistant.Any())
+                            {
+                                courseTaskDtos.AddRange(assistant.ToList());
+                            }
+                            teahcerCourses.Add(new CourseDto { courseBase=item, courseTasks=courseTaskDtos });
+                        }
+                    }
+                }
+            }
+            var groupInfo = await  GroupListService.GetMemberByListids(_coreAPIHttpService, _azureCosmos.GetCosmosClient(), _dingDing, hashGroupIds.ToList(), school);
+            var groupIdsRel = groupIds.GroupBy(z => z).Select(z => new { groupId = z.Key, count = z.ToList().Count() });
+            List<dynamic> groupLists= new List<dynamic>();
+            foreach (var item in teahcerCourses)
+            {
+                
+                foreach (var z in item.courseTasks) {
+                    var groups = z.courseTask.schedules.Select(z => z.groupId);
+                    if (groups!=null) {
+                        var groupList = groupInfo.groups.Where(z => groups.Contains(z.id));
+                        if (groupList!=null)
+                        {
+                            foreach (var gp in groupList) {
+                                string subjectId = null;
+                                string subjectName = null;
+                                string subjectBindId = null;
+                                groupLists.Add(new { role = z.type,scope= "private", groupList= gp, subjectId, subjectName , subjectBindId });
+                            }
+                        }
+                    }
+                }
+            }
+            foreach (var item in schoolCourses)
+            {
+                string subjectBindId = null;
+                if (!string.IsNullOrWhiteSpace(school) && periodSchool!=null  && item.courseBase.scope.Equals("school") && !string.IsNullOrWhiteSpace(item.courseBase?.subject?.id))
+                {
+                    subjectBindId=periodSchool.subjects.Find(z => z.id.Equals(item.courseBase.subject.id))?.bindId;
+                }
+                foreach (var z in item.courseTasks)
+                {
+                    var groups = z.courseTask.schedules.Select(z => z.groupId);
+                    if (groups!=null)
+                    {
+                        var groupList = groupInfo.groups.Where(z => groups.Contains(z.id));
+                        if (groupList!=null)
+                        {
+                            foreach (var gp in groupList)
+                            {
+
+                                groupLists.Add(new { role = z.type, scope = "school", groupList = gp, subjectId = item.courseBase?.subject?.id, subjectName = item.courseBase?.subject?.name, subjectBindId });
+                            }
+                        }
+                    }
+                }
+            }
+            foreach (var item in classes) {
+                var groupList = groupInfo.groups.Where(z => item.id.Equals(z.id));
+                if (groupList!=null)
+                {
+                    foreach (var gp in groupList)
+                    {
+
+                        groupLists.Add(new { role = "charge", scope = "school", groupList = gp });
+                    }
+                }
+            }
+            return Ok(new { teahcerCourses, schoolCourses, groupIdsRel, groupLists });
+        }
         /// <summary>
         /// <summary>
         /// 根据家长手机号获取监护学生的信息
         /// 根据家长手机号获取监护学生的信息
         /// </summary>
         /// </summary>
@@ -367,51 +889,6 @@ namespace TEAMModelOS.Controllers
                     arts = result.list;
                     arts = result.list;
                     token = result.continuationToken;
                     token = result.continuationToken;
                 }
                 }
-                //await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: stringBuilder.ToString(), continuationToken: token, requestOptions: new QueryRequestOptions() { MaxItemCount = topcout, PartitionKey = new PartitionKey($"Art-{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())
-                //        {
-                //            arts.Add(obj.ToObject<ArtEvaluation>());
-                //        }
-                //    }
-                //    if (iscontinuation)
-                //    {
-                //        continuationToken = item.GetContinuationToken();
-                //        break;
-                //    }
-                //}
-                // arts = arts.Where((x, i) => arts.FindIndex(z => z.id == x.id) == i).ToList();
-                //List<(string artId, double count)> attachments = new();
-               /* foreach (ArtEvaluation art in arts) {
-                    List<StudentArtResult> artResults = new();
-                    string stu = string.Format("{0}{1}{2}", code.GetString(), "-", stuId.GetString());
-                    string sql = $"select value(c) from c where c.artId = '{art.id}' and c.id = '{stu}' and c.pk = 'ArtResult'";
-                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(
-                    queryText: sql))
-                    {
-                        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())
-                            {
-                                artResults.Add(obj.ToObject<StudentArtResult>());
-                            }
-                        }
-                    }
-                    if (artResults.Count > 0)
-                    {
-                        var attCount = artResults[0].results.Where(z => z.files != null).SelectMany(c => c.files).ToList().Count;
-                        attachments.Add((art.id, attCount));
-                    }
-                    else {
-                        attachments.Add((art.id, 0));
-                    }
-                   
-                }*/
                 List<string> artIds = new();
                 List<string> artIds = new();
                 artIds = arts.Select(c => c.id).ToList();
                 artIds = arts.Select(c => c.id).ToList();
                 List<ArtAttachment> artAttachments = new();
                 List<ArtAttachment> artAttachments = new();
@@ -442,7 +919,7 @@ namespace TEAMModelOS.Controllers
                     c.period,
                     c.period,
                     c.periodType,
                     c.periodType,
                     c.zymusicstds,c.code,
                     c.zymusicstds,c.code,
-                    count = artAttachments.Where(z => z.artId.Equals(c.id)).SelectMany(k => k.files).ToList().Count
+                    count = artAttachments.Where(z => z.artId.Equals(c.id)).ToList().Count
 
 
                 });
                 });
                 return Ok(new { arts = newArts ,token});
                 return Ok(new { arts = newArts ,token});
@@ -451,7 +928,95 @@ namespace TEAMModelOS.Controllers
                 return BadRequest("500错误");
                 return BadRequest("500错误");
             }
             }
         }
         }
+        /// <summary>
+        /// 获取当前老师所在范围的活动列表
+        /// </summary>
+        /// <param name="json"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("find-teacher-activity")]
+#if !DEBUG
+        [Authorize(Roles = "AClassONE")]
+#endif
+        public async Task<IActionResult> getTeacherActivity(JsonElement request)
+        {
+            try
+            {
+                if (!request.TryGetProperty("studentId", out JsonElement teacId)) return BadRequest();
+                if (!request.TryGetProperty("classIds", out JsonElement classIds)) return BadRequest();
+                if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();//学校编码
+                List<string> cIds = classIds.ToObject<List<string>>();
+                var client = _azureCosmos.GetCosmosClient();
+                StringBuilder stringBuilder = new($"select value(c) from c where (c.status<>404 or IS_DEFINED(c.status) = false )");
+                string continuationToken = string.Empty;
+                string token = default;
+                stringBuilder.Append("order by c.createTime desc");
+                //是否需要进行分页查询,默认不分页
+                if (request.TryGetProperty("token", out JsonElement token_1))
+                {
+                    token = token_1.GetString();
+                };
+                //默认不指定返回大小
+                int? topcout = null;
+                if (request.TryGetProperty("count", out JsonElement jcount))
+                {
+                    if (!jcount.ValueKind.Equals(JsonValueKind.Undefined) && !jcount.ValueKind.Equals(JsonValueKind.Null) && jcount.TryGetInt32(out int data))
+                    {
+                        topcout = data;
+                    }
+                }
+
+                List<ArtEvaluation> arts = new();
+                var result = await client.GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<ArtEvaluation>(stringBuilder.ToString(), $"Art-{code}", token, 5);
+                if (result.list.IsNotEmpty())
+                {
+                    arts = result.list;
+                    token = result.continuationToken;
+                }
+                arts = arts.Where(c => c.classes.Intersect(cIds).Any()).Where((x, i) => arts.FindIndex(z => z.id == x.id) == i).ToList();
+                List<string> artIds = new();
+                artIds = arts.Select(c => c.id).ToList();
+                List<ArtAttachment> artAttachments = new();
+                string sqlTask = $"select value(c)  from c where c.studentId = '{teacId}' and c.artId in ({string.Join(",", artIds.Select(s => $"'{s}'"))})";
+                await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).
+                GetItemQueryIterator<ArtAttachment>(queryText: sqlTask, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"ArtAttachment-{code}") }))
+                {
+                    artAttachments.Add(item);
+                }
+                var newArts = arts.Select(c => new {
 
 
+                    c.id,
+                    c.name,
+                    c.school,
+                    c.createTime,
+                    c.type,
+                    c.classes,
+                    c.progress,
+                    c.scope,
+                    c.areaId,
+                    c.pId,
+                    c.topic,
+                    c.startTime,
+                    c.endTime,
+                    c.uploadSTime,
+                    c.uploadETime,
+                    c.publish,
+                    c.subjects,
+                    c.period,
+                    c.periodType,
+                    c.zymusicstds,
+                    c.code,
+                    count = artAttachments.Where(z => z.artId.Equals(c.id)).ToList().Count
+
+                });
+                return Ok(new { arts = newArts, token });
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},art/find-children-activity()\n{e.Message}\n{e.StackTrace}\n", GroupNames.醍摩豆服務運維群組);
+                return BadRequest("500错误");
+            }
+        }
 
 
         [ProducesDefaultResponseType]
         [ProducesDefaultResponseType]
         [HttpPost("find-summary-activity")]
         [HttpPost("find-summary-activity")]
@@ -554,6 +1119,18 @@ namespace TEAMModelOS.Controllers
                 var client = _azureCosmos.GetCosmosClient();
                 var client = _azureCosmos.GetCosmosClient();
                 if (!element.TryGetProperty("id", out JsonElement id)) return BadRequest();
                 if (!element.TryGetProperty("id", out JsonElement id)) return BadRequest();
                 if (!element.TryGetProperty("code", out JsonElement code)) return BadRequest();
                 if (!element.TryGetProperty("code", out JsonElement code)) return BadRequest();
+                ArtAttachment attachment = new();
+                var res = await client.GetContainer(Constant.TEAMModelOS, "Student").ReadItemStreamAsync(id.ToString(), new PartitionKey($"ArtAttachment-{code}"));
+                if (res.Status == 200)
+                {
+                    using var json = await JsonDocument.ParseAsync(res.ContentStream);
+                    attachment = json.ToObject<ArtAttachment>();
+
+                }
+                List<Attachment> atts = attachment.files;
+                foreach (Attachment att in atts) {
+                    await _azureStorage.GetBlobServiceClient().DeleteBlobs(_dingDing, code.GetString(), new List<string> { $"{att.blob}" });
+                }
                 await client.GetContainer("TEAMModelOS", "Student").DeleteItemStreamAsync(id.GetString(), new PartitionKey($"ArtAttachment-{code}"));
                 await client.GetContainer("TEAMModelOS", "Student").DeleteItemStreamAsync(id.GetString(), new PartitionKey($"ArtAttachment-{code}"));
                 return Ok();
                 return Ok();
             }
             }

+ 131 - 0
TEAMModelOS/Controllers/Common/ActivityController.cs

@@ -0,0 +1,131 @@
+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;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using Azure;
+using Microsoft.Extensions.Configuration;
+using TEAMModelOS.Filter;
+using HTEXLib.COMM.Helpers;
+using TEAMModelOS.SDK;
+using StackExchange.Redis;
+
+using System.Text.RegularExpressions;
+using Microsoft.AspNetCore.Authorization;
+
+namespace TEAMModelOS.Controllers
+{
+ 
+
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+
+    [Route("activity")]
+    [ApiController]
+    public class ActivityController : ControllerBase
+    {
+        private AzureCosmosFactory _azureCosmos;
+        private readonly DingDing _dingDing;
+        private readonly CoreAPIHttpService _coreAPIHttpService;
+        private readonly Option _option;
+        private readonly AzureServiceBusFactory _serviceBus;
+        private readonly AzureStorageFactory _azureStorage;
+        private readonly AzureRedisFactory _azureRedis;
+        public IConfiguration _configuration { get; set; }
+        public ActivityController(AzureRedisFactory azureRedis, AzureCosmosFactory azureCosmos, DingDing dingDing, IOptionsSnapshot<Option> option, CoreAPIHttpService coreAPIHttpService, AzureServiceBusFactory serviceBus, AzureStorageFactory azureStorage, IConfiguration configuration)
+        {
+            _azureCosmos = azureCosmos;
+            _dingDing = dingDing;
+            _option = option?.Value;
+            _serviceBus = serviceBus;
+            _configuration = configuration;
+            _azureStorage = azureStorage;
+            _azureRedis = azureRedis; 
+            _coreAPIHttpService = coreAPIHttpService;
+        }
+        /// <summary>
+        /// 活动创建
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [AuthToken(Roles = "teacher,admin,area")]
+        [HttpPost("manage")]
+        [Authorize(Roles = "IES")]
+
+        public async Task<IActionResult> Manage(JsonElement request)
+        {
+            try
+            {
+                (string tmdid, _, _, string school) = HttpContext.GetAuthTokenInfo();
+                if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
+               
+                var client = _azureCosmos.GetCosmosClient();
+                switch (true)
+                {
+                    case bool when $"{grant_type}".Equals("create", StringComparison.OrdinalIgnoreCase):
+                        {
+                            if (!request.TryGetProperty("Activity", out JsonElement _activity)) return Ok(new { error = ResponseCode._400ParamsError, msg = "活动信息参数错误" });
+
+                            Activity activity = _activity.ToObject<Activity>();
+                            activity.id=!string.IsNullOrWhiteSpace(activity.id)?activity.id: Guid.NewGuid().ToString();
+                            activity.code="Activity";
+                            activity.pk="Activity";
+                            ValidResult validResult = activity.Valid();
+                            if (validResult.isVaild)
+                            {
+                                activity.creatorId=tmdid;
+                                activity.createTime= DateTimeOffset.Now.ToUnixTimeMilliseconds();
+                                activity.year=DateTimeOffset.Now.Year;
+                                foreach (var module in activity.modules) {
+                                    switch (true) 
+                                    {
+                                        //赛课
+                                        case bool when module.Equals("Contest"):
+                                            {
+                                                if (!request.TryGetProperty("Contest", out JsonElement _contest)) return Ok(new { error = ResponseCode._400ParamsError, msg = "赛课信息参数错误" });
+                                                Contest contest = _activity.ToObject<Contest>();
+                                                contest.id=activity.id;
+                                                contest.code="Contest";
+                                                contest.pk="Contest";
+
+                                                break;
+                                            }
+                                        //培训
+                                        case bool when module.Equals("Training"):
+                                            {
+                                                break;
+                                            }
+                                        //教研
+                                        case bool when module.Equals("Research"):
+                                            {
+                                                break;
+                                            }
+                                    }
+                                }
+                            }
+                            else
+                            {
+                                return Ok(validResult);
+                            }
+                            break;
+                        }
+                   
+                }
+            }catch (Exception ex)
+            {
+
+            }
+            return Ok();
+        }
+    }
+}

File diff suppressed because it is too large
+ 30 - 2
TEAMModelOS/Controllers/System/WeChatPayController.cs


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

@@ -791,6 +791,7 @@ namespace TEAMModelOS.Controllers
                         //}
                         //}
                         currArea = new
                         currArea = new
                         {
                         {
+                            shortCode = area?.shortCode,
                             areaId = area?.id,
                             areaId = area?.id,
                             name = area?.name,
                             name = area?.name,
                             standard = area?.standard,
                             standard = area?.standard,