فهرست منبع

Merge branch 'develop' of http://52.130.252.100:10000/TEAMMODEL/TEAMModelOS into develop

CrazyIter_Bin 1 سال پیش
والد
کامیت
75b7cc1d50
25فایلهای تغییر یافته به همراه5542 افزوده شده و 21 حذف شده
  1. 1 1
      TEAMModelOS.FunctionV4/CosmosDB/TriggerArt.cs
  2. 1 0
      TEAMModelOS/ClientApp/package.json
  3. 118 0
      TEAMModelOS/ClientApp/public/lang/en-US.js
  4. 118 0
      TEAMModelOS/ClientApp/public/lang/zh-CN.js
  5. 121 0
      TEAMModelOS/ClientApp/public/lang/zh-TW.js
  6. 64 1
      TEAMModelOS/ClientApp/src/api/learnActivity.js
  7. 7 0
      TEAMModelOS/ClientApp/src/boot-app.js
  8. 0 0
      TEAMModelOS/ClientApp/src/common/BaseCountDown.vue
  9. 7 3
      TEAMModelOS/ClientApp/src/common/QrcodeModal.vue
  10. 20 0
      TEAMModelOS/ClientApp/src/utils/loadmore.js
  11. 9 0
      TEAMModelOS/ClientApp/src/utils/plugins.js
  12. 3 3
      TEAMModelOS/ClientApp/src/view/joinclass/JoinClass.vue
  13. 83 13
      TEAMModelOS/ClientApp/src/view/mycourse/MyCourse.vue
  14. 255 0
      TEAMModelOS/ClientApp/src/view/mycourse/score/AddProject.less
  15. 975 0
      TEAMModelOS/ClientApp/src/view/mycourse/score/AddProject.vue
  16. 126 0
      TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBox.less
  17. 441 0
      TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBoxAttend.vue
  18. 401 0
      TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBoxScoreCont.vue
  19. 285 0
      TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBoxStudentScore.vue
  20. 0 0
      TEAMModelOS/ClientApp/src/view/mycourse/score/Score.less
  21. 89 0
      TEAMModelOS/ClientApp/src/view/mycourse/score/Score.vue
  22. 180 0
      TEAMModelOS/ClientApp/src/view/mycourse/score/ScoreBody.less
  23. 2171 0
      TEAMModelOS/ClientApp/src/view/mycourse/score/ScoreBody.vue
  24. 23 0
      TEAMModelOS/ClientApp/src/view/mycourse/score/ScoreIndex.less
  25. 44 0
      TEAMModelOS/ClientApp/src/view/mycourse/score/ScoreIndex.vue

+ 1 - 1
TEAMModelOS.FunctionV4/CosmosDB/TriggerArt.cs

@@ -189,7 +189,7 @@ namespace TEAMModelOS.FunctionV4.CosmosDB
                                             pk = "Activity",
                                             id = art.id,
                                             code = $"Activity-{x.code.Replace("Base-", "")}-{x.id}",
-                                            type = "Atr",
+                                            type = "Art",
                                             name = art.name,
                                             startTime = art.startTime,
                                             endTime = art.endTime,

+ 1 - 0
TEAMModelOS/ClientApp/package.json

@@ -49,6 +49,7 @@
     "lodash": "^4.17.21",
     "node-fetch": "^2.6.1",
     "oidc-client": "^1.9.1",
+    "primevue": "^2.10.1",
     "qrcodejs2": "0.0.2",
     "snapsvg": "^0.5.1",
     "spark-md5": "^3.0.2",

+ 118 - 0
TEAMModelOS/ClientApp/public/lang/en-US.js

@@ -7547,5 +7547,123 @@ const LANG_EN_US = {
             classNum: 'Classrooms',
             totalTime: 'Total Time'
         }
+    },
+    scoreCalc:{
+        description1:'Underlined words',
+        description1_2:' can be clicked to edit detailed items',
+         blueWord:'Blue word',
+         canModifyable:' can be modified',
+         description2: ' the content can be modified, the number in (brackets) is the result of score x percentage%',
+         simple_complete: 'Simplified / Complete',
+         name:'Name',
+         id:'Student ID',
+         class:'Class',
+         th_homework:'Homework',
+         th_exam: 'Exam',
+         totalScore: 'Total score',
+         PRScore:'P-Rating',
+         gradesInClass: 'Classroom grades',
+         attend:'Attend',
+         point:'Scoreboard',
+         interactiveScore: 'Interactive score',
+         absence: ' Abs',//Absence
+         sickLeave:'SL',//Sick leave
+         personalLeave: 'PL',//Personal leave
+         publicLeave: 'PH',//Public holiday
+         absence2:'Absence',
+         sickLeave2:'Sick leave',
+         personalLeave2:'Personal leave',
+         publicLeave2:'Public holiday',
+         isSave: 'Archived',
+         notSave: 'Not archived',
+         delete:'Delete',
+         export:'Export',
+         print:'Print',
+         save:'Save',
+         scoreCalculation: 'Score Calculation',
+         simpleAttendanceCalculation:'Simple Attend. Calc.',//Simple Attendance Calculation
+         attendanceCalculationMethod: 'Attendance Calc. Method',//Attendance calculation method
+         customCalculation: 'Custom Calc.',//Custom calculation
+         percentageScore:'Normalization Score',
+         standardizedsScoring:'Percentage Scoring',
+         customScoring:'Custom Scoring',
+         calculationDescription1: 'The teacher gives the score directly according to the attendance of the students. Usually full attendance is the standard, and a certain point will be deducted for one absence. ',
+         calculationDescription2: 'Enter points for one absence',
+         marks:'Marks',
+         example:'Example:',
+         attendance:'Attendance results',
+         absences: 'Number of absences',
+         calculationDescription3: 'Absent a deduction ',
+         calculationFormula:'Calculation formula',
+         calculationDescription4: 'Check is absent:',
+         checkOk:'OK',
+         cancel:'Cancel',
+         calculationDescription5: 'Calculate the attendance rate based on the attendance times of the students, and then use it as the basis for the attendance score. The attendance rate is expressed as a percentage. For example, if the attendance rate exceeds 90%, a full score will be awarded, and a certain point will be deducted for each percentage point lower than the attendance rate. ',
+         calculationDescription6: '1% deduction for every absence',
+         attendanceOver: 'Attendance Over',
+         isFullMark: '% is full mark',
+         classGrades:'Class grades:',
+         totalNumberClasses: 'Total classes',
+         attendQwen:'Attendance',
+         formula:'Formula:',
+         calculationDescription7: 'Please fill in the calculation formula according to the following variables:',
+         numberOfSick: 'Number of sick leave',
+         numberOfPerson: 'Number of personal leave',
+         numberOfPublic: 'Number of public holidays',
+         calculationDescription8: 'Example of the formula (the following is directly based on the attendance rate of the attendance score):',
+         calculationDescription9:'※Excel formulas can be used to write! ',
+         instantPreview:'Preview Formula',
+         calculationDescription10: "Use the normalization method to convert the student's score to a standard score. ",
+         gravityCalculationScore:'Gravity calculation score',
+         averageScore: 'Average score',
+         standardDeviation: 'Standard deviation',
+         standardScoreZFormula: 'Standard score (Z) formula:',
+         derivedStandardScoreTFormula: 'Derived standard score (T) formula:',
+         calculationDescription11: '(Usually used to solve decimal and negative number problems)',
+         indicatesAverageScore: 'Represents the average score',
+         calculationDescription12: "Divides the student's score by the activity's highest score. This is then multiplied by 100 to calculate the student's percentile grade. ",
+         highestScore: 'Highest score',
+         calculationDescription13: 'Please fill in the calculation formula according to the following variables:',
+         classQwen:'Total number of classes',
+         totalScoreClass: 'The Class Total',
+         totalNumberStudents: 'The Class Size',
+         formulaExample:'Formula example:',
+         writtenas: 'written as:',
+         scoreboardScore: 'Scoreboard scores',
+         lessonRecordTitle: 'Classroom Record',
+         homeworkTitle: 'Job Activity',
+         examTitle: 'Assessment Activity',
+         totalRate: 'Total weighted',
+         itemName:'Item name',
+         percentage:'Percentage',
+         tickIncludedScore:'↓tick to be included in the score. ',
+         dropSort:'※Drag can be sorted',
+         itemRate: 'Proportion',
+         logStudentScore: 'Log student score',
+         average: 'Average',
+         login:'Login',
+         score: 'Score',
+         attendState:' ※ Attendance score: 1 attendance 2 absence 3 leave 4 sick leave 5 personal leave 6 public holiday',
+         pasteMultiple: 'Multiple paste',
+         pasteEXCEL:' ※It can be pasted directly from EXCEL',
+         back:'Return',
+         warringTotalRate: 'The total weight cannot exceed 100%',
+         dataIsSave: 'Data has been saved',
+         remind: 'Reminder',
+         remindMessage1:'<p>There are unsaved settings, do you want to continue switching active projects? </p>',
+         remindMessage2:'<p>There are unsaved settings, do you want to continue adding activity items? </p>',
+         deleteRemind1: 'Delete active sub-items',
+         remindMessage3:'<p>The data of the active sub-item will not be retrieved after deletion. Are you sure to delete the current active sub-item? </p>',
+         deleteRemind2: 'Delete active item',
+         remindMessage3:'<p>The data of the active item will not be retrieved after it is deleted. Are you sure to delete the current active item? </p>',
+         remindMessage4: 'The active item has been deleted',
+         remindMessage5: 'Score login complete',
+         scoreCalc:'Score Calculation',
+         modifyContent:'Modifyable content',   
+         ask:'Inquire',
+         DelTableQuestion:'<p>The data of the score sheet will not be retrieved after it is deleted. Are you sure to delete the current score sheet?<p>', 
+         saveAsk:'<p>Do you want to save all the content in this data table?</p>',
+         addAsk:'<p>Do you want to add a new activity item?</p>',
+         APIerr:'API request failed',          
     }
 }

+ 118 - 0
TEAMModelOS/ClientApp/public/lang/zh-CN.js

@@ -7538,5 +7538,123 @@ const LANG_ZH_CN = {
             classNum: '教室数',
             totalTime: '总时间数'
         }
+    },
+    scoreCalc:{
+        description1:'底线字',
+        description1_2:'可点击编辑细项',
+        blueWord:'蓝字',
+        canModifyable:'可修改',
+        description2:'可修改内容,(括弧)的数字为分数 x 百分比%的结果',
+        simple_complete:'精简模式/完整模式',        
+        name:'姓名',
+        id:'学号',
+        class:'课堂',
+        th_homework:'作业',
+        th_exam:'评量',
+        totalScore:'总评分',
+        PRScore:'PR值',
+        gradesInClass:'课堂细项成绩',        
+        attend:'出席',
+        point:'计分板',
+        interactiveScore:'互动分',
+        absence:'缺席',//英文版Abs
+        sickLeave:'病假',//英文版SL
+        personalLeave:'事假',//英文版PL
+        publicLeave:'公假',//英文版PH
+        absence2:'缺席',//英文版Absence
+        sickLeave2:'病假',//英文版Sick leave
+        personalLeave2:'事假',//英文版Personal leave
+        publicLeave2:'公假',//英文版Public holiday
+        isSave:'已存档',
+        notSave:'未存档',
+        delete:'删除',
+        export:'汇出',
+        print:'列印',
+        save:'储存',
+        scoreCalculation:'成绩计算',
+        simpleAttendanceCalculation:'简单出席计算法',
+        attendanceCalculationMethod:'出席率计算法',
+        customCalculation:'自订计算',
+        percentageScore:'标准化评分',
+        standardizedsScoring:'百分比评分',
+        customScoring:'自定义评分',
+        calculationDescription1:'教师根据学生的出席情况,直接给予分数。通常是以全勤为标准,缺席一次扣一定分数。 ',
+        calculationDescription2:'请输入一次缺席扣多少分数',
+        marks:'分',
+        example:'范例:',
+        attendance:'出席成绩',
+        absences:'缺席次数',
+        calculationDescription3:'缺席一次扣 ',
+        calculationFormula:'计算公式',
+        calculationDescription4:'勾选即为缺席状态:',                   
+        checkOk:'确定',
+        cancel:'取消',
+        calculationDescription5:'根据学生的出席次数计算出席率,再以此作为出席分数的依据。出席率以百分比表示,例如出席率超过90%可得满分,每低于一个百分点扣一定分数。 ',
+        calculationDescription6:'每缺席1% 扣',
+        attendanceOver:'出席率超过',
+        isFullMark:'% 为满分',
+        classGrades:'课堂成绩:',
+        totalNumberClasses:'课堂总次数',
+        attendQwen:'出席次数',
+        formula:'公式:',
+        calculationDescription7:'请依照下列变数填写计算公式:',
+        numberOfSick:'病假次数',
+        numberOfPerson:'事假次数',
+        numberOfPublic:'公假次数',
+        calculationDescription8:'公式范例(以下直接以出席率为出席分数):',
+        calculationDescription9:'※可使用excel公式写! ',
+        instantPreview:'算式写法即时预览',
+        calculationDescription10:'使用标准化方法将学生的得分转换为标准分数。 ',
+        gravityCalculationScore:'比重计算分数',
+        averageScore:'平均分数',
+        standardDeviation:'标准差',
+        standardScoreZFormula:'标准分数(Z)公式:',
+        derivedStandardScoreTFormula:'衍生标准分数(T)公式:',
+        calculationDescription11:'(通常用于解决小数及负数问题)',
+        indicatesAverageScore:'表示平均分数',
+        calculationDescription12:'将学生的得分除以活动的最高分数。然后乘以100,即可计算出学生的百分比评分。 ',
+        highestScore:'最高分数',
+        calculationDescription13:'请依照下列变数填写计算公式:',        
+        classQwen:'课堂总数',
+        totalScoreClass:'全班总分',        
+        totalNumberStudents:'学生总数',
+        formulaExample:'公式范例:',
+        writtenas:'写法为:',
+        scoreboardScore:'记分板成绩',          
+        lessonRecordTitle: '课堂纪录',
+        homeworkTitle: '作业活动',
+        examTitle: '评量活动',        
+        totalRate:'总加权',
+        itemName:'项目名称',
+        percentage:'百分比',
+        tickIncludedScore:'↓勾选则计入成绩。 ',
+        dropSort:'※拖曳可排序',
+        itemRate:'比重',
+        logStudentScore:'登录学生分数',
+        average:'平均',
+        loging:'登录',
+        score:'成绩',
+        attendState:' ※出席分数:1出席 2缺席 3请假 4病假 5事假 6公假',
+        pasteMultiple:' 多笔贴上',
+        pasteEXCEL:' ※可直接从EXCEL贴上',       
+        back:'返回',        
+        warringTotalRate:'总加权不可超过100%',
+        dataIsSave:'资料已储存',
+        remind:'提醒',
+        remindMessage1:'<p>有未储存的设定,要继续切换活动项目吗? </p>',
+        remindMessage2:'<p>有未储存的设定,要继续新增活动项目吗? </p>',
+        deleteRemind1:'删除活动子项目',
+        remindMessage3:'<p>活动子项目数据删除后将无法找回,确认删除当前活动子项目吗? </p>',
+        deleteRemind2:'删除活动项目',
+        remindMessage3:'<p>活动项目数据删除后将无法找回,确认删除当前活动项目吗? </p>',
+        remindMessage4:'活动项目已删除',
+        remindMessage5:'分数登录完成',
+        scoreCalc:'成绩计算',        
+        modifyContent:'可修改内容       ',
+        ask:'询问',
+        DelTableQuestion:'<p>成绩表数据删除后将无法找回,确定要删除此成绩表吗?<p>',
+        saveAsk:'<p>是否确定要保存此数据表的所有内容呢?</p>',  
+        addAsk:'<p>是否确定要新增活动项目呢?</p>',
+        APIerr:'API请求失败',            
     }
 }

+ 121 - 0
TEAMModelOS/ClientApp/public/lang/zh-TW.js

@@ -7534,5 +7534,126 @@ const LANG_ZH_TW = {
             classNum: '教室數',
             totalTime: '總時間數'
         }
+    },
+    scoreCalc:{
+        description1:'底線字',
+        description1_2:'可點擊編輯細項',
+        blueWord:'藍字',
+        canModifyable:'可修改',
+        description2:'可修改內容,(括弧)的數字為分數 x 百分比%的結果',
+        simple_complete:'精簡模式/完整模式',                
+        name:'姓名',
+        id:'學號',
+        class:'課堂',
+        th_homework:'作業',
+        th_exam:'評量',
+        totalScore:'總評分',
+        PRScore:'PR值',
+        gradesInClass:'課堂細項成績',        
+        attend:'出席',
+        point:'計分板',
+        interactiveScore:'互動分',
+        absence:'缺席',//英文版Abs
+        sickLeave:'病假',//英文版SL
+        personalLeave:'事假',//英文版PL
+        publicLeave:'公假',//英文版PH
+        absence2:'缺席',//英文版Absence
+        sickLeave2:'病假',//英文版Sick leave
+        personalLeave2:'事假',//英文版Personal leave
+        publicLeave2:'公假',//英文版Public holiday
+        isSave:'已存檔',
+        notSave:'未存檔',
+        delete:'刪除',
+        export:'匯出',
+        print:'列印',
+        save:'儲存',
+        scoreCalculation:'成績計算',
+        simpleAttendanceCalculation:'簡單出席計算法',
+        attendanceCalculationMethod:'出席率計算法',
+        customCalculation:'自訂計算',
+        percentageScore:'標準化評分',
+        standardizedsScoring:'百分比評分',
+        customScoring:'自訂評分',
+        calculationDescription1:'教師根據學生的出席情況,直接給予分數。通常是以全勤為標準,缺席一次扣一定分數。',
+        calculationDescription2:'請輸入一次缺席扣多少分數',
+        marks:'分',
+        example:'範例:',
+        attendance:'出席成績',
+        absences:'缺席次數',
+        calculationDescription3:'缺席一次扣 ',
+        calculationFormula:'計算公式',
+        calculationDescription4:'勾選即為缺席狀態:',                   
+        checkOk:'確定',
+        cancel:'取消',
+        calculationDescription5:'根據學生的出席次數計算出席率,再以此作為出席分數的依據。出席率以百分比表示,例如出席率超過90%可得滿分,每低於一個百分點扣一定分數。',
+        calculationDescription6:'每缺席1% 扣',
+        attendanceOver:'出席率超過',
+        isFullMark:'% 為滿分',
+        classGrades:'課堂成績:',
+        totalNumberClasses:'課堂總次數',
+        attendQwen:'出席次數', 
+        formula:'公式:',
+        calculationDescription7:'請依照下列變數填寫計算公式:',
+        numberOfSick:'病假次數',
+        numberOfPerson:'事假次數',
+        numberOfPublic:'公假次數',
+        calculationDescription8:'公式範例(以下直接以出席率為出席分數):',
+        calculationDescription9:'※可使用excel公式寫!',
+        instantPreview:'算式寫法即時預覽',
+        calculationDescription10:'使用標準化方法將學生的得分轉換為標準分數。',
+        gravityCalculationScore:'比重計算分數',
+        averageScore:'平均分數',
+        standardDeviation:'標準差',
+        standardScoreZFormula:'標準分數(Z)公式:',
+        derivedStandardScoreTFormula:'衍生標準分數(T)公式:',
+        calculationDescription11:'(通常用於解決小數及負數問題)',
+        indicatesAverageScore:'表示平均分數',
+        calculationDescription12:'將學生的得分除以活動的最高分數。然後乘以100,即可計算出學生的百分比評分。',
+        highestScore:'最高分數',
+        calculationDescription13:'請依照下列變數填寫計算公式:',        
+        classQwen:'課堂總數',
+        totalScoreClass:'全班總分',        
+        totalNumberStudents:'學生總數',
+        formulaExample:'公式範例:',
+        writtenas:'寫法為:',
+        scoreboardScore:'記分板成績',          
+        lessonRecordTitle: '課堂紀錄',
+        homeworkTitle: '作業活動',
+        examTitle: '評量活動',        
+        totalRate:'總加權',
+        itemName:'項目名稱',
+        percentage:'百分比',
+        tickIncludedScore:'↓勾選則計入成績。 ',
+        dropSort:'※拖曳可排序',
+        itemRate:'比重',
+        logStudentScore:'登錄學生分數',
+        average:'平均',
+        loging:'登錄',
+        score:'成績',
+        attendState:' ※出席分數:1出席 2缺席 3請假 4病假 5事假 6公假',
+        pasteMultiple:' 多筆貼上',
+        pasteEXCEL:' ※可直接從EXCEL貼上',       
+        back:'返回',        
+        warringTotalRate:'總加權不可超過100%',
+        dataIsSave:'資料已儲存',
+        remind:'提醒',
+        remindMessage1:'<p>有未儲存的設定,要繼續切換活動項目嗎?</p>',
+        remindMessage2:'<p>有未儲存的設定,要繼續新增活動項目嗎?</p>',
+        deleteRemind1:'刪除活動子項目',
+        remindMessage3:'<p>活動子項目數據刪除後將無法找回,確認刪除當前活動子項目嗎?</p>',
+        deleteRemind2:'刪除活動項目',
+        remindMessage3:'<p>活動項目數據刪除後將無法找回,確認刪除當前活動項目嗎?</p>',
+        remindMessage4:'活動項目已刪除',
+        remindMessage5:'分數登錄完成',
+        scoreCalc:'成績計算',        
+        modifyContent:'可修改內容       ',
+        ask:'詢問',
+        DelTableQuestion:'<p>成績表數據刪除後將無法找回,確認刪除此成績表嗎?<p>',
+        saveAsk:'<p>是否確定要儲存此資料表所有內容呢?</p>', 
+        addAsk:'<p>是否確定要新增活動項目呢?</p>',
+        APIerr:'API請求失敗',          
     }
+
+
+
 }

+ 64 - 1
TEAMModelOS/ClientApp/src/api/learnActivity.js

@@ -352,5 +352,68 @@ export default {
 	getGradeInfo: function (data) {
 	    return post('/common/exam/score', data)
 	},
-
+    /* 查詢班級歷次成績列表標題 */
+	getScoreCalctitle: function (data) {
+	    return post('/score/get-scorecalc-list', data)
+	},
+    /* 查詢班級歷次成績所有細項資料 */
+	getScoreCalcAll: function (data) {
+	    return post('/score/get-scorecalc-All', data)
+	},
+    /* 修改成績表排序 */
+	updateProjectListSort: function (data) {
+	    return post('/score/update-scorecalc-sort', data)
+	},
+    /* 修改成績表資料 */
+	updateProjectList: function (data) {
+	    return post('/score/update-scorecalc', data)
+	},  
+    /* 新增成績表 */
+	addScorecalc: function (data) {
+	    return post('/score/add-scorecalc', data)
+	},
+    /* 刪除成績表 */
+	deleteScorecalc: function (data) {
+	    return post('/score/delete-scorecalc', data)
+	},
+    /* 新增成績表子項目 */
+	addScorecalcact: function (data) {
+	    return post('/score/add-scorecalcact', data)
+	},
+    /* 更新成績表 */
+	updateScorecalc: function (data) {
+	    return post('/score/update-formula', data)
+    },
+    /* 新增自訂項目及其子項目資料 */
+	addScoreCalcAct: function (data) {
+	    return post('/score/add-scorecalcact', data)
+	},
+    /* 刪除自訂項目 */
+	deleteScoreCalcAct: function (data) {
+	    return post('/score/delete-scorecalcact', data)
+	},
+     /* 更新項目及子項目資料 */
+     updateScoreCalcAct: function (data) {
+	    return post('/score/update-scorecalcact', data)
+	},
+     /* 更新活動項目順序 */
+     updateScoreCalcActSort: function (data) {
+	    return post('/score/update-scorecalcact-sort', data)
+	},
+     /* 新增子項目 */
+     addScoreCalcActItem: function (data) {
+	    return post('/score/add-scorecalcact-item', data)
+	},
+     /* 刪除子項目 */
+     deleteScoreCalcActItem: function (data) {
+	    return post('/score/delete-scorecalcactitem', data)
+	},
+     /* 更新活動子項目順序 */
+     updateScoreCalcActItemSort: function (data) {
+	    return post('/score/update-scorecalcactitem-sort', data)
+	},
+     /* 登錄指定子項目成績 */
+     updateItemScore: function (data) {
+	    return post('/score/update-itemscore', data)
+	},
 }

+ 7 - 0
TEAMModelOS/ClientApp/src/boot-app.js

@@ -47,11 +47,18 @@ import fabric from 'fabric'
 import VideoPlayer from 'vue-video-player'
 import NewChooseContent from '@/components/selflearn/NewChooseContent'
 import VueWordcloud from 'vue-b2wordcloud'
+import plugins from './utils/plugins';
+import PrimeVue from 'primevue/config';
+
 Vue.use(VueWordcloud)
 
 jsFn.setLocalLang()
 require('video.js/dist/video-js.css')
 require('vue-video-player/src/custom-theme.css')
+//加入PrimeVue UI套件(主要為了使用Table)
+Vue.use(PrimeVue);
+//加入載入表單資料顯示的模組
+Vue.use(plugins)
 // 图片预览组件
 Vue.use(hevueImgPreview)
 // Dashboard边框组件

+ 0 - 0
TEAMModelOS/ClientApp/src/common/BaseCountDown.vue


+ 7 - 3
TEAMModelOS/ClientApp/src/common/QrcodeModal.vue

@@ -3,6 +3,8 @@
         <div class="qr-code-info" @click.stop>
             <p class="qr-code-title">
                 {{config.title}}
+            </p>
+            <p>
                 <slot name="switch"></slot>
             </p>
             <div id="qrcode" :class="showQrStatus ? 'animated fadeIn':'animated fadeOut'" ref="qrcode" style="padding:15px 25px 20px 25px;background-color:white;width:330px;margin:auto;">
@@ -132,8 +134,10 @@ export default {
     display: block;
     margin: auto;
     text-align: center;
-    color: black;
-    font-size: 18px;
+    color: #2d8cf0;
+    font-size: 20px;
+    font-weight: bold;
+    margin-bottom: 20px;
 }
 .qr-code-text {
     display: block;
@@ -142,7 +146,7 @@ export default {
     margin-top: -5px;
     margin-bottom: 5px;
     color: #0058e7;
-    font-size: 20px;
+    // font-size: 20px;
 }
 .invite-url-text {
     text-overflow: ellipsis;

+ 20 - 0
TEAMModelOS/ClientApp/src/utils/loadmore.js

@@ -0,0 +1,20 @@
+export default {
+    bind(el, binding) {
+        // 获取iview-ui定义好的scroll盒子
+        const selectWrap = el.querySelector('.ivu-table-body')
+        selectWrap.addEventListener('scroll', function () {
+            /*
+             * scrollHeight 元素标签内容高度
+             * scrollTop 获取元素滚动的偏移值,
+             * clientHeight 元素标签的可见高度
+             * 如果元素滚动到底, 下面等式返回true, 没有则返回false:
+             * ele.scrollHeight - ele.scrollTop === ele.clientHeight;
+             */
+            let sign = 100
+            const scrollDistance = this.scrollHeight - this.scrollTop - this.clientHeight
+            if (scrollDistance <= sign) {
+                binding.value()
+            }
+        })
+    }
+}

+ 9 - 0
TEAMModelOS/ClientApp/src/utils/plugins.js

@@ -0,0 +1,9 @@
+//view-table加载更多
+import loadmore from './loadmore';
+
+export default {
+    async install (Vue, options) {
+        // 指令
+        Vue.directive('loadmore', loadmore);
+    }    
+}

+ 3 - 3
TEAMModelOS/ClientApp/src/view/joinclass/JoinClass.vue

@@ -172,10 +172,10 @@ export default {
                             sessionStorage.setItem('identity', 'student')
                         } else if (res.status == 4) {// 个人名单未开放加入
                             this.$Message.warning(this.$t('cusMgt.join.joinLock'))
-                        } else if (res.status == 5) {// 没有开启审核模式
+                        } else if (res.status == 6) {// 没有开启审核模式
                             this.$Message.warning('没有开启审核模式')
-                        } else if (res.status == 6) {// 人数已满,需要审核通过再加入
-                            this.$Message.warning('人数已满,需要审核通过再加入')
+                        } else if (res.status == 5) {// 人数已满,需要审核通过再加入
+                            this.$Message.warning('需要审核通过再加入')
                         } else if (res.status == 7) {// 二维码设置已经过期
                             this.$Message.warning('二维码设置已经过期')
                         }

+ 83 - 13
TEAMModelOS/ClientApp/src/view/mycourse/MyCourse.vue

@@ -56,7 +56,7 @@
 						<vuescroll>
 							<div v-for="(item, index) in teaClassList" :key="index" @click="selectClass(index)" :class="['block-bg', 'tea-class-item', curClassIndex == index ? 'block-bg-active' : '']">
 								<p class="class-attr-item">
-									<span class="attr-label" v-show="listType === 'school'">{{ item.classId ? $t("cusMgt.listType1") : $t("cusMgt.listType2") }}: </span>
+									<span class="attr-label" v-show="listType === 'school'">{{ item.classId ? $t("cusMgt.listType1") : $t("cusMgt.listType2") }}:</span>
 									<span class="attr-label" v-show="listType === 'private'">{{ $t("cusMgt.nameList") }}:</span>
 									<span class="class-name">{{ item.classId ? item.classInfo.name : item.listName || "--" }}</span>
 									<Tag v-if="item.graduate === 1" color="gold">
@@ -68,10 +68,10 @@
 									<span class="attr-label">{{ $t("cusMgt.stuCount") }}</span>
 									<span class="class-name">{{ getStudenCount(item.classId || item.stulist) }}{{ $t("unit.text7") }}</span>
 								</p>
-								<Icon size="25" custom="iconfont icon-qr-code" :class="['qr-code-icon', { 'qr-code-icon-color': item.joinLock }]" @click="showQrCode(index)" v-if="listType == 'private'" :title="$t('cusMgt.qrCodeLabel')" />
+								<Icon size="25" custom="iconfont icon-qr-code" :class="['qr-code-icon', item.joinLock ? 'qr-code-icon-color' : '']" @click="showQrCode(index)" v-if="listType == 'private'" :title="$t('cusMgt.qrCodeLabel')" />
 								<span v-if="hasCCAuth" :class="['qr-code-icon', hasCCAuth ? 'cc-icon' : 'no-cc-auth']" @click="startCus(index)"> CC </span>
 							</div>
-							<EmptyData v-if="teaClassList.length == 0" :top="160" :textContent="$t('cusMgt.noClassList')"></EmptyData>
+							<EmptyData v-if="teaClassList.length == 0" :top="160" :textContent="$t('cusMgt.noClassList')"> </EmptyData>
 						</vuescroll>
 					</div>
 				</div>
@@ -102,24 +102,54 @@
 						<span @click="selectTab('discussion')" :class="tabName == 'discussion' ? 'course-classroom-label pane active' : 'course-classroom-label pane'">
 							{{ $t("studentWeb.type.discussionBoard") }}
 						</span>
+						<span @click="selectTab('score')" :class="tabName == 'score' ? 'course-classroom-label pane active':'course-classroom-label pane'">
+							{{$t('cusMgt.cusTab7')}}
+						</span>
 					</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>
 					<Homework v-else-if="tabName == 'hw'" v-model="fIds" :classInfo="teaClassList[curClassIndex]" :courseInfo="courseInfo"></Homework>
 					<Survey v-else-if="tabName == 'survey'" v-model="fIds" :classInfo="teaClassList[curClassIndex]" :courseInfo="courseInfo"></Survey>
 					<Vote v-else-if="tabName == 'vote'" v-model="fIds" :classInfo="teaClassList[curClassIndex]" :courseInfo="courseInfo"></Vote>
 					<Record v-else-if="tabName == 'record'" v-model="fIds" :rcdParams="rcdParams" :isFull="isFull"></Record>
-					<Student v-else-if="tabName == 'student'" :classInfo="teaClassList[curClassIndex]" :stuList="curStuList" @on-del-student="onDelStudent" @on-add-student="onAddStudent" @on-update-students="onSetIrs"></Student>
+					<Student v-else-if="tabName == 'student'" :classInfo="teaClassList[curClassIndex]" :stuList="curStuList" @on-del-student="onDelStudent" @on-add-student="onAddStudent" @on-update-students="onSetIrs"> </Student>
 					<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>
+					<Score v-else-if="tabName == 'score'" :gradeParams="gradeParams" :grouplistId="teaClassList[curClassIndex]" :listType="listType"></Score>
 				</div>
 			</Split>
 		</div>
 		<QrcodeModal v-model="showQrStatus" :config="qrConfig">
-			<span style="margin-left: 10px" slot="switch">
+			<div style="font-size: 14px;padding: 0 20px" slot="switch">
 				<!-- <span>{{ agreeJoin ? '已同意扫码加入' : '禁止扫码加入' }}</span> -->
-				<i-switch v-model="agreeJoin" size="small" @on-change="agreeJoinClass" />
-			</span>
+				<!-- <i-switch v-model="agreeJoin" size="small" @on-change="agreeJoinClass" /> -->
+				<p style="display: flex;justify-content:space-between;margin:15px 0">
+					<span>
+						允许加入
+						<i-switch v-model="agreeJoin" size="small" @on-change="agreeJoinClass" />
+					</span>
+					
+					<span>
+						最多人数限制
+						<InputNumber :max="999" :min="0" size="small" v-model="qrSetting.limitCount" style="width:70px;margin-left: 5px;" @on-blur="onSettingChange"></InputNumber>
+					</span>
+				</p>
+				<p style="display: flex;justify-content:space-between;margin:15px 0">
+					<span>
+						开启审核
+						<i-switch v-model="qrSetting.review" size="small" @on-change="onSettingChange" />
+					</span>
+					<span>
+						二维码有效期
+						<Select v-model="qrSetting.qrcodeDays" size="small" style="width:70px;margin-left: 5px;" @on-change="onSettingChange">
+							<Option :value="1" :key="1">1天</Option>
+							<Option :value="3" :key="3">3天</Option>
+							<Option :value="7" :key="7">7天</Option>
+						</Select>
+					</span>
+				</p>
+				<!-- <BaseCountDown :timestamp="1691468827882"></BaseCountDown> -->
+			</div>
 			<!-- 支持自定义内容 -->
 			<p class="qr-code-text" slot="tips-content">
 				(<span style="font-size: 17px">{{ $t("cusMgt.qrCodeText") }}</span> {{ stuListNo }})
@@ -209,7 +239,7 @@
 					</FormItem>
 					<FormItem :label="$t('cusMgt.listLabel')" v-else-if="type == 'select'">
 						<Select v-model="listId">
-							<Option v-for="(item, index) in groupList" :value="item.id" :key="index">{{ item.name }}</Option>
+							<Option v-for="(item, index) in groupList" :value="item.id" :key="index">{{ item.name }} </Option>
 						</Select>
 					</FormItem>
 					<FormItem :label="$t('cusMgt.listLabel')" v-else-if="type == 'school'">
@@ -254,6 +284,7 @@
 	import Student from "./student/Student.vue";
 	import Notice from "./notice/Notice.vue";
 	import Discussion from "./discussion/Discussion.vue";
+	import Score from "./score/Score.vue"
 	export default {
 		components: {
 			Exam,
@@ -263,7 +294,8 @@
 			Record,
 			Student,
 			Notice,
-			Discussion
+			Discussion,
+			Score
 		},
 		data() {
 			// 验证只能是字母和数字
@@ -276,6 +308,12 @@
 				}
 			};
 			return {
+				expireTime:1595656565,
+				qrSetting:{
+					review:false,
+					limitCount:200,
+					qrcodeDays: 1
+				},
 				schoolClassInfo: [],
 				isGraduate: false,
 				pdfList: [
@@ -458,6 +496,33 @@
 			}, 100);
 		},
 		methods: {
+			onSettingChange(){
+				console.error('xxxxxxxxx')
+				let stulist = this.courseGroupList.find((item) => {
+					return item.id == this.teaClassList[this.curClassIndex].stulist;
+				});
+				if (stulist) {
+					console.log(stulist)
+					let params = stulist;
+					params.review = this.qrSetting.review ? 1 : 0;
+					params.qrcodeDays = this.qrSetting.qrcodeDays;
+					params.limit = this.qrSetting.limitCount;
+					this.listLoading = true;
+					this.$api.common
+						.upsertGroupInfo(params)
+						.then(
+							(res) => {
+								this.$Message.info(this.$t("cusMgt.updOk"));
+							},
+							(err) => {
+								this.$Message.error(this.$t("cusMgt.updOk"));
+							}
+						)
+						.finally(() => {
+							this.listLoading = false;
+						});
+				}
+			},
 			handleSelectClass(data) {
 				console.log(data);
 				this.schoolClassInfo = data;
@@ -616,13 +681,13 @@
 				}
 			},
 			async showQrCode(index) {
-				console.log(this.courseInfo)
+				console.log(this.courseInfo);
 				let loginUrl = window.location.host;
 				let tName = this.$store.state.userInfo.name;
 				let listId = this.teaClassList[index].stulist;
 				let listName = this.teaClassList[index].listName;
 				let cusName = this.courseInfo.name;
-        		let cusDesc = this.courseInfo.desc;
+				let cusDesc = this.courseInfo.desc;
 				let cusId = this.courseInfo.id;
 				let stulistInfo = this.courseGroupList.find((item) => {
 					return item.id == listId;
@@ -638,7 +703,7 @@
 					// 处理分享内容
 					try {
 						let shortUrl = await this.$api.getShortUrl(encodeURI(this.inviteUrl));
-						let shareText = `${this.$t("cusMgt.inviteInfo1")}\n\n${this.$t("cusMgt.inviteInfo2")}${cusName}\n${this.$t("cusMgt.inviteInfo3")}${listName}\n${this.$t("cusMgt.inviteInfo4")}${tName}\n${this.$t('cusMgt.cusDesc')}:${cusDesc}\n\n${this.$t("cusMgt.inviteInfo5")}\n${shortUrl.result || encodeURI(this.inviteUrl)}\n\n${this.$t("cusMgt.inviteInfo6")}\nURL:https://${loginUrl}/login/student\n${this.$t("cusMgt.inviteInfo7")}${this.stuListNo}`;
+						let shareText = `${this.$t("cusMgt.inviteInfo1")}\n\n${this.$t("cusMgt.inviteInfo2")}${cusName}\n${this.$t("cusMgt.inviteInfo3")}${listName}\n${this.$t("cusMgt.inviteInfo4")}${tName}\n${this.$t("cusMgt.cusDesc")}:${cusDesc}\n\n${this.$t("cusMgt.inviteInfo5")}\n${shortUrl.result || encodeURI(this.inviteUrl)}\n\n${this.$t("cusMgt.inviteInfo6")}\nURL:https://${loginUrl}/login/student\n${this.$t("cusMgt.inviteInfo7")}${this.stuListNo}`;
 						this.qrConfig.shareContent = shareText;
 					} catch (e) {
 						this.qrConfig.shareContent = "";
@@ -1273,13 +1338,16 @@
 		.ivu-radio-group-button .ivu-radio-wrapper:first-child {
 			border: none;
 		}
+
 		.ivu-radio-group-button .ivu-radio-wrapper:after {
 			display: none;
 		}
+
 		.ivu-radio-wrapper {
 			margin-right: 5px;
 			border: none;
 			box-shadow: none;
+
 			.ivu-icon {
 				margin-bottom: 2px;
 			}
@@ -1295,11 +1363,13 @@
 			box-shadow: none !important;
 			color: white !important;
 		}
+
 		.ivu-radio-group-button .ivu-radio-wrapper {
 			height: 28px;
 			line-height: 26px;
 		}
 	}
+
 	.ivu-radio-wrapper-checked .cus-action-icon-wrap {
 		display: inline-block;
 	}

+ 255 - 0
TEAMModelOS/ClientApp/src/view/mycourse/score/AddProject.less

@@ -0,0 +1,255 @@
+.score-container {
+    position: absolute;
+    top: 45px;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    display: flex;
+}
+
+.absolute {
+    /* 設置為絕對定位 */
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+}
+
+.center {
+    text-align: center;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+.left {
+    width: 250px;
+    //border: 1px solid #d7dde4;   
+    padding: 10px;
+    background: #f2f2f2;
+    position: relative;
+    border-radius: 4px;
+
+    .row {
+        overflow: auto;
+        top: 10px;
+        bottom: 10px;
+        padding: 10px;
+        // height: 75vh;
+
+        .card {
+            cursor: pointer;
+        }
+
+        .tableNameClass {
+            font-weight: bold;
+            //font-size: 16px;
+            //display: grid;
+            //place-items: center;
+            margin: 0px 10px 10px 10px;
+        }
+
+        .card,
+        .card0 {
+            margin: 5px;
+            background-color: white;
+            padding: 15px 10px;
+            border-radius: 10px;
+            display: flex;
+            justify-content: space-between;
+            font-weight: 900;
+        }
+
+        .card:hover,
+        .icon-card:hover,
+        .card.active {
+            border: 2px solid #2b85e4;
+        }
+
+        .icon-card {
+            margin: 20px 5px;
+            background-color: white;
+            padding: 5px;
+            border-radius: 10px;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            cursor: pointer;
+        }
+
+        .icon-card2 {
+            margin: 20px 5px;
+            border-radius: 10px;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+        }
+    }
+}
+
+.save-info-ok {
+    text-align: right;
+    color: #808695;
+    margin-bottom: 10px;
+}
+
+.save-info-erro {
+    text-align: right;
+    color: #ed4014;
+    margin-bottom: 10px;
+}
+
+.right {
+    flex: 1;
+    background: hsl(0, 0%, 95%);
+    display: flex;
+    padding: 10px;
+
+    .content {
+        background: white;
+        padding: 10px;
+        margin: 10px 0;
+        position: relative;
+        width: 100%;
+
+        /* 加入絕對定位 */
+        //overflow:scroll;
+        .head {
+            //height: 10%;            
+            display: flex;
+
+            .txtInput-div {
+                flex: 2;
+                display: flex;
+                align-items: center;
+                margin-bottom: 10px;
+
+                .label {
+                    text-align: left;
+                    margin-right: 6px;
+                }
+
+                input {
+                    color: #2d8cf0;
+                    margin: 0px 5px;
+                    padding: 2px;
+                    border: 1px solid #e8eaec;
+                    box-shadow: none;
+                    text-align: right;
+                    width: 200px;
+                }
+
+                .content-input {
+                    text-align: left;
+                    margin-left: auto;
+                }
+
+                .none-input {
+                    border: none;
+                    pointer-events: none;
+                    color: black;
+                }
+
+                .input-container {
+                    white-space: nowrap;
+                }
+
+                .input2 {
+                    width: 40px;
+                }
+            }
+
+            .down {
+                display: flex;
+                flex-direction: column;
+                justify-content: flex-end;
+
+                button {
+                    position: relative;
+                    z-index: 9999;
+                }
+            }
+
+            .button-div {
+                display: flex;
+                justify-content: flex-start;
+            }
+        }
+
+        .body {
+            top: 55px;
+            padding: 10px;
+
+            .title {
+                background-color: #f2f2f2;
+                padding: 2px;
+            }
+
+            .felx1{
+                flex: 1 1 0%;
+            }
+            .felx2{
+                flex: 2 1 0%;
+            }
+            .felxAuto{
+                flex: 1 1 auto;
+            }
+
+            .content-in {
+                top: 60px;
+                right: 10px;
+                bottom: 10px;
+                padding: 10px 10px;
+                overflow: auto;
+
+                .add-card {
+                    margin-top: 15px;
+                    justify-content: center;
+                    cursor: pointer;
+                }
+
+                .card {
+                    border: 1px solid #e8eaec;
+                    display: flex;
+                    border-radius: 5px;
+                    padding: 5px;
+                    margin-bottom: 5px;
+
+                    input,
+                    .ivu-input {
+                        color: #2d8cf0;
+                        border: 1px solid #e8eaec;
+                        box-shadow: none;
+                        text-align: center;
+                        width: 100%;
+                        border-radius: 5px;
+                    }
+
+                    .average-div {
+                        text-align: center;
+                        height: 100%;
+
+                        .average {
+                            background-color: rgb(255, 217, 160);
+                            padding: 0px 10px;
+                            border-radius: 2px;
+                            font-size: 5px;
+                        }
+                    }
+
+                    .btn-left {
+                        display: flex;
+                        justify-content: start;
+                        margin-left: 5px;
+                    }
+
+                    .ivu-btn {
+                        height: auto;
+                    }                    
+                }
+            }
+        }
+    }
+
+}

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

@@ -0,0 +1,975 @@
+<template>
+  <div class="score-container">
+    <div class="left">
+      <div class="row absolute">
+        <div class="tableNameClass">{{ tableInfo.tableName }}</div>
+        <div class="card" @click="changeItem(0)" :class="{ active: getProjectDatasClick(0) }">
+          <div>{{ getProjectName(0) }}</div>
+          <div style="margin-right: 20px">{{ getPercentage(0) }}%</div>
+        </div>
+        <div class="card" @click="changeItem(1)" :class="{ active: getProjectDatasClick(1) }">
+          <div>{{ getProjectName(1) }}</div>
+          <div style="margin-right: 20px">{{ getPercentage(1) }}%</div>
+        </div>
+        <div class="card" @click="changeItem(2)" :class="{ active: getProjectDatasClick(2) }">
+          <div>{{ getProjectName(2) }}</div>
+          <div style="margin-right: 20px">{{ getPercentage(2) }}%</div>
+        </div>
+        <div v-if="projectDatas.length > 3" style="display: flex; justify-content: center; align-items: center">
+          <Icon type="md-add" :size="20" />
+        </div>
+        <div class="card" v-for="(projectData, index) in projectDatas.slice(3)" :class="{
+          active: projectDatas[index + 3].click ? projectDatas[index + 3].click : false,
+        }" draggable="true" @dragstart="dragStart($event, index + 3)" @click="changeItem(index + 3)"
+          @dragover="allowDrop" @drop="drop($event, index + 3, 'projectDatas')" v-bind:key="index + 3" @dragend="dragEnd">
+          <!--這邊待新增程式判斷-->
+          <div>{{ projectData.projectName }}</div>
+          <div style="display: flex">
+            <div>{{ projectData.percentage }}%</div>
+            <div>
+              <Icon type="ios-trash" size="20" style="cursor: pointer" @click.stop="delProject(index)" />
+            </div>
+          </div>
+        </div>
+        <span v-if="projectDatas.length > 4" style="font-size: 6px">
+          {{ $t("scoreCalc.dropSort") }}
+        </span>
+
+        <div class="icon-card" @click="addProject">
+          <div class="add">
+            <Icon type="md-add-circle" :size="25" />
+          </div>
+        </div>
+        <div class="icon-card2">
+          <Icon type="md-pause" :size="25" color="#2b85e4" />
+        </div>
+        <div class="card0">
+          <div>
+            {{ $t("scoreCalc.totalRate") }}
+          </div>
+          <div v-if="totalNum == 100">{{ totalNum }}%</div>
+          <div v-if="totalNum != 100" style="color: #ed4014">
+            <Icon type="md-alert" />{{ totalNum }}%
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="right">
+      <div class="content">
+        <div class="head">
+          <div class="txtInput-div">
+            <div class="input-container">
+              <div class="label">{{ $t("scoreCalc.itemName") }}</div>
+              <input v-if="thisClassData.index <= 2" type="text" v-model="thisClassData.projectName" maxlength="20"
+                class="content-input none-input" />
+              <input v-if="thisClassData.index > 2" type="text" v-model="thisClassData.projectName" maxlength="20"
+                class="content-input" @input="updateInputprojectName" />
+            </div>
+            <div class="input-container">
+              <div class="label" style="margin-right: 26px">
+                {{ $t("scoreCalc.percentage") }}
+              </div>
+              <div class="input-container" style="margin-right: 10px">
+                <input type="text" v-model="thisClassData.percentage" maxlength="2" class="input2"
+                  @input="updateInputpercentage" />
+                <span>%</span>
+              </div>
+            </div>
+          </div>
+          <div class="down">
+            <div v-if="isSave" class="save-info-ok">
+              <Icon type="md-checkmark-circle" />{{ $t("scoreCalc.isSave") }}
+            </div>
+            <div v-if="!isSave" class="save-info-erro">
+              <Icon type="md-alert" />{{ $t("scoreCalc.notSave") }}
+            </div>
+            <div class="button-div">
+              <Button type="text" style="z-index: 500" @click="ProjectGoback('back')">{{
+                $t("scoreCalc.back")
+              }}</Button>
+              <Button type="primary" style="z-index: 500" @click="ProjectGoback('save')">{{ $t("scoreCalc.save")
+              }}</Button>
+            </div>
+          </div>
+        </div>
+        <div class="body absolute">
+          <span style="font-size: 6px"> {{ $t("scoreCalc.tickIncludedScore") }} {{
+            $t("scoreCalc.dropSort")
+          }}</span>
+          <div>
+            <Row class="title">
+              <Col style="flex: 0 0 40px;">
+              </Col>
+              <Col class="felx1">{{ $t("scoreCalc.itemName") }}</Col>
+              <Col class="felx1">{{ $t("scoreCalc.itemRate") }}</Col>
+            </Row>
+            <div class="content-in absolute">
+              <div v-for="(classData, index) in classDatas" draggable="true" @dragstart="dragStart($event, index)"
+                @dragover="allowDrop" @drop="drop($event, index, 'classDatas')" v-bind:key="index" @dragend="dragEnd">
+                <Row class="card">
+                  <Col flex="40px" style="flex: 0 0 40px;" class="center">
+                  <Checkbox v-model="classData.single"></Checkbox>
+                  </Col>
+                  <Col flex="1"  class="felx1">
+                  <Row>
+                    <Col flex="2" class="felx2" style="display: flex; align-items: center;">
+                    <div v-if="!classData.custom" class="center">
+                      {{ classData.className }}
+                    </div>
+                    <!-- <Input type="textarea" :value="classData.className" :autosize="{ minRows: 1, maxRows: 2 }" -->
+                    <Input type="textarea" v-model="classData.className" :autosize="{ minRows: 1, maxRows: 2 }"
+                      v-if="classData.custom" maxlength="60" @input="isInput" />
+                    <!-- <input type="text" :value="classData.className" v-if="classData.custom" maxlength="40"
+                        @input="isInput" /> -->
+                    </Col>
+                    <Col flex="1" class="felx1" v-if="!classData.islessonrecord">
+                    <div class="average-div center">
+                      <span class="average">{{ $t("scoreCalc.average") }}{{ classData.score }}分</span>
+                    </div>
+                    </Col>
+                  </Row>
+                  </Col>
+                  <Col flex="1" class="felx1" style="display: flex; align-items: center;">
+                  <Row :wrap="false" >
+                    <Col flex="50px" style="flex: 0 0 50px;">
+                    <input type="text" v-model="classData.proportion" maxlength="1" @input="isInput" />
+                    </Col>
+                    <Col flex="auto" class="btn-left center felxAuto">
+                    <Button type="primary" @click="
+                      keyScore(
+                        classData.id,
+                        classData.islessonrecord,
+                        classData.className
+                      )
+                      ">{{ $t("scoreCalc.logStudentScore") }}</Button>
+                    </Col>
+                    <Col flex="auto" class="center">
+                    <Icon type="ios-trash" size="20" v-if="classData.custom" style="cursor: pointer"
+                      @click="delClass(classData.id)" />
+                    </Col>
+                  </Row>
+                  </Col>
+                </Row>
+              </div>
+              <div class="card add-card" @click="addClass">
+                <Icon type="md-add-circle" :size="25" />
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <DialogBoxStudentScore :modalVisible="modalVisibleStudentScore" :className="className"
+      @closeModal="modalVisibleStudentScoreFun" :class_type="class_type" :classDataprop="classDataprop"
+      @updateItemScore="updateItemScore">
+    </DialogBoxStudentScore>
+    <Loading :top="100" v-show="dataLoading" type="1"></Loading>
+
+    <!-- <div :top="100" v-show="dataLoading" style="background: red; width: 300px;height: 300px;" ></div>  -->
+    <!-- <div :top="100"  style="background: red; width: 800px;height: 300px;display: none;" ></div>  -->
+  </div>
+</template>
+<script>
+import DialogBoxStudentScore from "./DialogBoxStudentScore.vue";
+import Loading from "@/common/Loading.vue";
+export default {
+  components: {
+    DialogBoxStudentScore,
+  },
+  props: {
+    //projectName: String, //課堂classRecord  作業homeWork 評量evaluate
+    tableInfo: Object, //
+    /*
+      tableInfo.tableName 表單名稱
+      tableInfo.tableId 表單ID
+      tableInfo.listId 表單項目ID
+    */
+    value: {
+      default: () => {
+        return [];
+      },
+    },
+  },
+  data() {
+    return {
+      isSave: true,
+      tempNum: 0,
+      filterExpire: false,
+      modalVisibleStudentScore: false,
+      class_type: "", //兩種型態:課堂紀錄 非課堂紀錄
+      thisClassData: { index: 0, projectName: "", percentage: 0 }, //當前顯示的資料
+      className: "", //課程名稱
+      projectDatas: [], // 左邊項目欄繫結用的資料
+      classDatas: [], // 右邊子項目欄繫結用的資料
+      calcData: {}, // 原始資料
+      selectIndex: 0, // 選中的項目索引
+      classData: [],
+      classDataprop: [],
+      inputValFromChild: "",
+      selectClassId: "",
+      selectClassIndex: "",
+      dataLoading: false,
+    };
+  },
+  computed: {
+    totalNum() {
+      let sum = 0;
+      this.projectDatas.forEach((element) => {
+        sum += parseInt(element.percentage, 10);
+      });
+      return sum;
+    },
+  },
+  mounted() {
+    //↓根據點進來的按鈕去撈資料庫,並改變顯示的資料。
+    //請改用tableInfo接資料
+    console.log("tableInfo=" + JSON.stringify(this.tableInfo));
+    this.getActList(this.tableInfo.listId);
+  },
+  methods: {
+    ProjectGoback(vule) {
+      if (vule == "save") {
+        if (this.totalNum > 100) {
+          this.$Message.warning(this.$t("scoreCalc.warringTotalRate"));
+        } else {
+          //#region 更新項目及子項目資料
+          let items = [];
+          let sort = 1;
+          this.classDatas.forEach((element) => {
+            let item = {
+              id: element.id,
+              name: element.className,
+              rate: element.proportion,
+              use: element.single,
+              sort: sort,
+            };
+            items.push(item);
+            sort = sort + 1;
+          });
+
+          let postData = {
+            scoreCalcActId: this.projectDatas[this.selectIndex].id,
+            teammodelId: this.$store.state.userInfo.TEAMModelId,
+            name: this.projectDatas[this.selectIndex].projectName,
+            rate: this.projectDatas[this.selectIndex].percentage,
+            items: items,
+          };
+          this.$api.learnActivity.updateScoreCalcAct(postData).then(
+            (res) => {
+              if (res) {
+                this.getActList(this.projectDatas[this.selectIndex].id);
+                this.$Message.info(this.$t("scoreCalc.dataIsSave"));
+              }
+            },
+            (err) => {
+              this.$Message.error(this.$t("cusMgt.gradeErr"));
+            }
+          );
+          this.isSave = true;
+          //#endregion
+        }
+      } else if (vule == "back") {
+        //直接返回
+        this.$emit("tableInfo", this.tableInfo);
+        this.$emit("changePage", "AllScore");
+      }
+    },
+    // 切換項目動作
+    changeItem(index) {
+      this.dataLoading = true;
+      // 要先判斷是否有修改
+      if (!this.isSave && index !== this.selectIndex) {
+        // 有修改的話要跳提示 會還原
+        this.$Modal.confirm({
+          title: this.$t("scoreCalc.remind"),
+          content: this.$t("scoreCalc.remindMessage1"),
+          onOk: async () => {
+            // 確定要不儲存切換
+            let listId = this.projectDatas[index].id;
+            this.projectDatas = [];
+            this.calcData.scoreCalcAct.forEach((element) => {
+              // 比對是否為選中的活動
+              if (listId === element.id) {
+                this.projectDatas.push({
+                  click: true,
+                  projectName: element.name,
+                  percentage: element.rate,
+                  id: element.id,
+                });
+
+                this.reloadProject(index);
+              } else {
+                this.projectDatas.push({
+                  click: false,
+                  projectName: element.name,
+                  percentage: element.rate,
+                  id: element.id,
+                });
+              }
+            });
+            this.isSave = true;
+          },
+          onCancel: () => {
+            // 不切換
+            //this.$Message.info('Clicked cancel');
+          },
+        });
+      } else {
+        this.reloadProject(index);
+      }
+      this.dataLoading = false;
+    },
+    // 重新整理選中的項目資料
+    reloadProject(index) {
+      this.selectIndex = index;
+      this.classDatas = [];
+      for (let i = 0; i < this.projectDatas.length; i++) {
+        this.projectDatas[i].click = false;
+        if (i === index) {
+          this.projectDatas[i].click = true;
+        }
+      }
+      // 設定右邊欄上方資料
+      this.thisClassData.index = index;
+      this.thisClassData.projectName = this.projectDatas[index].projectName;
+      this.thisClassData.percentage = this.projectDatas[index].percentage;
+
+      // 根據選中的項目刷新右邊欄資料
+      this.calcData.scoreCalcAct.forEach((element) => {
+        if (this.projectDatas[index].id === element.id) {
+          this.setSubListData(element);
+        }
+      });
+    },
+    // 增加一個自訂項目
+    addProject() {
+      // 要先判斷是否有修改
+      if (!this.isSave) {
+        // 有修改的話要跳提示 會還原
+        this.$Modal.confirm({
+          title: this.$t("scoreCalc.remind"),
+          content: this.$t("scoreCalc.remindMessage2"),
+          onOk: async () => {
+            // 確定要不儲存
+            this.dataLoading = true;
+            let postData = {
+              scorecalcId: this.tableInfo.tableId,
+              teammodelId: this.$store.state.userInfo.TEAMModelId,
+            };
+            this.$api.learnActivity.addScoreCalcAct(postData).then(
+              (res) => {
+                if (res) {
+                  this.calcData.scoreCalcAct.push(res);
+                  // 新增完成 清空左邊欄 重新塞資料
+                  this.projectDatas = [];
+                  this.calcData.scoreCalcAct.forEach((element) => {
+                    this.projectDatas.push({
+                      click: true,
+                      projectName: element.name,
+                      percentage: element.rate,
+                      id: element.id,
+                    });
+                  });
+                  this.reloadProject(this.projectDatas.length - 1);
+                }
+              },
+              (err) => {
+                this.$Message.error(this.$t("cusMgt.gradeErr"));
+              }
+            );
+            this.isSave = true;
+            this.dataLoading = false;
+          },
+          onCancel: () => {
+            // 不切換
+            //this.$Message.info('Clicked cancel');
+          },
+        });
+      } else {
+        this.dataLoading = true;
+        let postData = {
+          scorecalcId: this.tableInfo.tableId,
+          teammodelId: this.$store.state.userInfo.TEAMModelId,
+        };
+        this.$api.learnActivity.addScoreCalcAct(postData).then(
+          (res) => {
+            if (res) {
+              this.calcData.scoreCalcAct.push(res);
+              this.projectDatas.push({
+                click: true,
+                projectName: res.name,
+                percentage: res.rate,
+                id: res.id,
+              });
+              this.reloadProject(this.projectDatas.length - 1);
+            }
+          },
+          (err) => {
+            this.$Message.error(this.$t("cusMgt.gradeErr"));
+          }
+        );
+        this.dataLoading = false;
+      }
+    },
+    // 刪除一個自訂項目
+    delProject(index) {
+      this.dataLoading = true;
+      this.confirmDeleteAct(index + 3);
+      //this.projectDatas.splice(index + 3, 1);
+      //this.isSave = false;
+      this.dataLoading = false;
+    },
+    //拖曳相關--str---↓↓--
+    allowDrop(e) {
+      //取消默認行為
+      console.log("allowDrop");
+      e.preventDefault();
+    },
+    dragStart(e, index) {
+      console.log("dragStart");
+      let tar = e.target;
+      e.dataTransfer.setData("Text", index);
+      if (tar.tagName.toLowerCase() == "li") {
+      }
+    },
+    drop(e, index, whatData) {
+      //放置
+      console.log("drop");
+
+      this.allowDrop(e);
+      if (whatData == "classDatas") {
+        let arr = this.classDatas.concat([]),
+          dragIndex = e.dataTransfer.getData("Text");
+        let temp = arr.splice(dragIndex, 1);
+
+        arr.splice(index, 0, temp[0]);
+        this.classDatas = arr;
+
+        //#region 更新子項目順序
+        let sortItems = [];
+        for (let i = 0; i < this.classDatas.length; i++) {
+          let id = this.classDatas[i].id;
+          sortItems.push({
+            id: this.classDatas[i].id,
+            sort: i + 1,
+          });
+        }
+        let postData = {
+          scoreCalcActId: this.projectDatas[this.selectIndex].id,
+          teammodelId: this.$store.state.userInfo.TEAMModelId,
+          sortItems: sortItems,
+        };
+        this.dataLoading = true;
+
+        this.$api.learnActivity.updateScoreCalcActItemSort(postData).then(
+          (res) => {
+            if (res) {
+              // 重新排序原始資料
+              this.calcData.scoreCalcAct.forEach((element) => {
+                if (this.projectDatas[this.selectIndex].id === element.id) {
+                  // 先找到要排序的子項目資料
+                  for (let i = 0; i < element.items.length; i++) {
+                    for (let j = 0; j < this.classDatas.length; j++) {
+                      if (this.classDatas[j].id === element.items[i].id) {
+                        // 重新設定原始資料的排序
+                        element.items[i].sort = j + 1;
+                      }
+                    }
+                  }
+                  element.items = element.items.sort((a, b) => a.sort - b.sort); // 設定好排序後  進行升冪排序
+                }
+              });
+            }
+          },
+          (err) => {
+            this.$Message.error(this.$t("cusMgt.gradeErr"));
+          }
+        );
+        this.dataLoading = false;
+        //#endregion
+      } else if (whatData == "projectDatas") {
+        let arr = this.projectDatas.concat([]),
+          dragIndex = e.dataTransfer.getData("Text");
+        let temp = arr.splice(dragIndex, 1);
+
+        arr.splice(index, 0, temp[0]);
+        this.projectDatas = arr;
+        this.selectIndex = index;
+
+        //#region 更新活動項目順序
+        let sortItems = [];
+        for (let i = 0; i < this.projectDatas.length; i++) {
+          let id = this.projectDatas[i].id;
+          sortItems.push({
+            id: this.projectDatas[i].id,
+            sort: i + 1,
+          });
+        }
+        let postData = {
+          scoreCalcId: this.tableInfo.tableId,
+          teammodelId: this.$store.state.userInfo.TEAMModelId,
+          sortItems: sortItems,
+        };
+        this.dataLoading = true;
+        this.$api.learnActivity.updateScoreCalcActSort(postData).then(
+          (res) => {
+            if (res) {
+              // 重新排序原始資料
+              this.calcData.scoreCalcAct.forEach((element) => {
+                for (let i = 0; i < this.projectDatas.length; i++) {
+                  if (this.projectDatas[i].id === element.id) {
+                    element.sort = i + 1;
+                  }
+                }
+              });
+              this.calcData.scoreCalcAct = this.calcData.scoreCalcAct.sort(
+                (a, b) => a.sort - b.sort
+              );
+            }
+          },
+          (err) => {
+            this.$Message.error(this.$t("cusMgt.gradeErr"));
+          }
+        );
+        this.dataLoading = false;
+        //#endregion
+      }
+    },
+    dragEnd() {
+      console.log("dragEnd");
+      //this.isSave = false;
+    },
+    //拖曳相關--end---↑↑--
+    // 新增一個子項目
+    addClass() {
+      this.dataLoading = true;
+      let postData = {
+        scoreCalcActId: this.projectDatas[this.selectIndex].id,
+        teammodelId: this.$store.state.userInfo.TEAMModelId,
+      };
+      this.$api.learnActivity.addScoreCalcActItem(postData).then(
+        (res) => {
+          if (res) {
+            this.calcData.scoreCalcAct.forEach((element) => {
+              // 找到目前選中的項目 並更新其子項目資料
+              if (this.projectDatas[this.selectIndex].id === element.id) {
+                element.items.push(res);
+
+                let islessonrecord = false;
+                if (element.type === "lessonrecord") {
+                  islessonrecord = true;
+                }
+                this.classDatas.push({
+                  id: res.id,
+                  single: res.use,
+                  custom: true,
+                  className: res.name,
+                  proportion: res.rate,
+                  score: 0,
+                  islessonrecord: islessonrecord,
+                });
+              }
+            });
+          }
+        },
+        (err) => {
+          this.$Message.error(this.$t("cusMgt.gradeErr"));
+        }
+      );
+      this.dataLoading = false;
+    },
+    // 刪除一個子項目
+    delClass(id) {
+      this.$Modal.confirm({
+        title: this.$t("scoreCalc.deleteRemind1"),
+        content: this.$t("scoreCalc.remindMessage3"),
+        onOk: async () => {
+          this.dataLoading = true;
+          let postData = {
+            scoreCalcActId: this.projectDatas[this.selectIndex].id,
+            id: id,
+            teammodelId: this.$store.state.userInfo.TEAMModelId,
+          };
+          this.$api.learnActivity.deleteScoreCalcActItem(postData).then(
+            (res) => {
+              if (res) {
+                this.calcData.scoreCalcAct.forEach((element) => {
+                  // 找到刪除的項目 並移除其子項目資料
+                  if (this.projectDatas[this.selectIndex].id === element.id) {
+                    for (let i = 0; i < element.items.length; i++) {
+                      if (id === element.items[i].id) {
+                        element.items.splice(i, 1);
+                      }
+                    }
+                  }
+                });
+                // 找到刪除的項目 並移除其子項目資料
+                for (let i = 0; i < this.classDatas.length; i++) {
+                  if (id === this.classDatas[i].id) {
+                    this.classDatas.splice(i, 1);
+                  }
+                }
+              }
+            },
+            (err) => {
+              this.$Message.error(this.$t("cusMgt.gradeErr"));
+            }
+          );
+          this.dataLoading = false;
+        },
+        onCancel: () => {
+          //this.$Message.info('Clicked cancel');
+        },
+      });
+    },
+    // 登錄分數
+    keyScore(id, type, className) {
+      //(類型)
+      this.dataLoading = true;
+      this.classDataprop = [];
+      //debugger;
+      setTimeout(() => {
+        this.$nextTick(() => {
+          let dt = new Date();
+
+          this.classData = [];
+          this.selectClassId = id;
+          if (type) this.class_type = "lessonrecord";
+          else this.class_type = "activity";
+          this.className = className;
+          this.modalVisibleStudentScore = true;
+
+          this.calcData.scoreCalcAct.forEach((element) => {
+            if (element.id === this.projectDatas[this.selectIndex].id) {
+              // 先選中項目
+              element.items.forEach((item) => {
+                if (item.id === id) {
+                  // 再選中子項目
+                  if (element.type === "lessonrecord") {
+                    // 如果是課堂紀錄要登記三種分數
+                    for (let i = 0; i < item.stuActAttendScores.length; i++) {
+                      // for (let i = 0; i < 20; i++) {
+                      this.classData.push({
+                        name: this.calcData.members[i].name,
+                        id: this.calcData.members[i].id,
+                        attendance: item.stuActAttendScores[i],
+                        score: item.stuActPointScores[i],
+                        interactiveScore: item.stuActItactScores[i],
+                      });
+                    }
+                  } else {
+                    // 如果不是課堂紀錄登記一種分數
+                    for (let i = 0; i < item.scores.length; i++) {
+                      //  for (let i = 0; i < 20; i++) {
+                      this.classData.push({
+                        name: this.calcData.members[i].name,
+                        id: this.calcData.members[i].id,
+                        attendance: 0,
+                        score: item.scores[i],
+                        interactiveScore: 0,
+                      });
+                    }
+                  }
+                }
+              });
+            }
+          });
+          this.classDataprop = this.classData;
+        });
+      }, 1);
+      let that = this;
+      setTimeout(() => {
+        that.dataLoading = false;
+      }, 1000);
+      //this.dataLoading = false;
+    },
+    modalVisibleStudentScoreFun(value) {
+      this.modalVisibleStudentScore = value;
+      this.classDataprop = [];
+    },
+    updateInputprojectName(event) {
+      //debugger;
+      this.isSave = false;
+      const newProjectName = event.target.value;
+      this.projectDatas[this.thisClassData.index].projectName = newProjectName;
+    },
+    updateInputpercentage(event) {
+      this.isSave = false;
+      const newPercentage = event.target.value;
+      this.projectDatas[this.thisClassData.index].percentage = newPercentage;
+    },
+    isInput() {
+      this.isSave = false;
+    },
+    getProjectDatasClick(index) {
+      // 檢查選中項目click防呆
+      if (this.projectDatas[index] !== undefined) {
+        return this.projectDatas[index].click ? this.projectDatas[index].click : false;
+      } else {
+        return false;
+      }
+    },
+    getProjectName(index) {
+      // 檢查選中項目ProjectName防呆
+      if (this.projectDatas[index] !== undefined) {
+        // 轉換多語系
+        switch (this.projectDatas[index].projectName) {
+          case "課堂紀錄":
+            return this.$t("scoreCalc.lessonRecordTitle");
+          case "作業活動":
+            return this.$t("scoreCalc.homeworkTitle");
+          case "評量活動":
+            return this.$t("scoreCalc.examTitle");
+          default:
+            return "";
+        }
+      } else {
+        return "";
+      }
+    },
+    getPercentage(index) {
+      // 檢查選中項目Percentage防呆
+      if (this.projectDatas[index] !== undefined) {
+        return this.projectDatas[index].percentage
+          ? this.projectDatas[index].percentage
+          : "";
+      } else {
+        return "";
+      }
+    },
+    getActList(listId) {
+      //取項目資料
+      this.projectDatas = [];
+      let acts;
+      let postData = { id: this.tableInfo.tableId };
+      this.dataLoading = true;
+      this.$api.learnActivity.getScoreCalcAll(postData).then(
+        (res) => {
+          if (res) {
+            this.calcData = res;
+            if (res.scoreCalcAct) acts = res.scoreCalcAct.sort((a, b) => a.sort - b.sort); //title根據sort進行降冪排序
+
+            acts.forEach((element) => {
+              // 比對是否為選中的活動
+              if (listId === element.id) {
+                this.projectDatas.push({
+                  click: true,
+                  projectName: element.name,
+                  percentage: element.rate,
+                  id: element.id,
+                });
+
+                this.reloadProject(this.projectDatas.length - 1);
+              } else {
+                this.projectDatas.push({
+                  click: false,
+                  projectName: element.name,
+                  percentage: element.rate,
+                  id: element.id,
+                });
+              }
+            });
+          }
+        },
+        (err) => {
+          this.$Message.error(this.$t("cusMgt.gradeErr"));
+        }
+      );
+      this.dataLoading = false;
+    },
+    setSubListData(element) {
+      // 子項目資料填入
+      element.items.forEach((subelement) => {
+        if (element.type !== "lessonrecord") {
+          let sum = 0;
+          subelement.scores.forEach((scoreselement) => {
+            sum = sum + scoreselement;
+          });
+
+          this.classDatas.push({
+            id: subelement.id,
+            single: subelement.use,
+            custom: subelement.custom,
+            className: subelement.name,
+            proportion: subelement.rate,
+            score: Math.round((sum / subelement.scores.length) * 10) / 10,
+            islessonrecord: false,
+          });
+        } else {
+          this.classDatas.push({
+            id: subelement.id,
+            single: subelement.use,
+            custom: subelement.custom,
+            className: subelement.name,
+            proportion: subelement.rate,
+            score: 0,
+            islessonrecord: true,
+          });
+        }
+      });
+    },
+    confirmDeleteAct(index) {
+      // 刪除項目
+      this.$Modal.confirm({
+        title: this.$t("scoreCalc.deleteRemind2"),
+        content: this.$t("scoreCalc.remindMessage3"),
+        onOk: async () => {
+          if (index === this.selectIndex) {
+            // 如果要刪除的跟目前選中的活動向相同 焦點回到第一個項目
+            this.reloadProject(0);
+          }
+          let postData = {
+            id: this.projectDatas[index].id,
+            teammodelId: this.$store.state.userInfo.TEAMModelId,
+            scorecalcId: this.tableInfo.tableId,
+          };
+          this.dataLoading = true;
+          await this.$api.learnActivity.deleteScoreCalcAct(postData).then(
+            (res) => {
+              if (res) {
+                for (let i = 0; i < this.calcData.scoreCalcAct.length; i++) {
+                  // 移除已刪除項目
+                  // 比對是否為選中的活動
+                  if (this.projectDatas[index].id === this.calcData.scoreCalcAct[i].id) {
+                    this.calcData.scoreCalcAct.splice(i, 1);
+                  }
+                }
+                this.projectDatas.splice(index, 1); // 移除已刪除項目
+
+                if (this.projectDatas.length === 3) {
+                  this.reloadProject(0);
+                }
+
+                this.$Message.info(this.$t("scoreCalc.remindMessage4"));
+              }
+            },
+            (err) => {
+              this.$Message.error(this.$t("cusMgt.gradeErr"));
+            }
+          );
+          this.dataLoading = false;
+        },
+        onCancel: () => {
+          //this.$Message.info('Clicked cancel');
+        },
+      });
+    },
+    updateItemScore(val) {
+      // 接取子項目傳的值
+      this.inputValFromChild = val;
+
+      if (val) {
+        let postData = {};
+        let stuActAttendScores = [];
+        let stuActPointScores = [];
+        let stuActItactScores = [];
+        let scores = [];
+        // 根據目前選中的類別設定欄位更新分數
+        if (this.class_type === "lessonrecord") {
+          for (let i = 0; i < val.length; i++) {
+            stuActAttendScores.push(val[i].attendance);
+            stuActPointScores.push(val[i].score);
+            stuActItactScores.push(val[i].interactiveScore);
+          }
+
+          postData = {
+            scoreCalcActId: this.projectDatas[this.selectIndex].id,
+            teammodelId: this.$store.state.userInfo.TEAMModelId,
+            id: this.selectClassId,
+            stuActAttendScores: stuActAttendScores,
+            stuActPointScores: stuActPointScores,
+            stuActItactScores: stuActItactScores,
+          };
+        } else {
+          for (let i = 0; i < val.length; i++) {
+            scores.push(val[i].score);
+          }
+          postData = {
+            scoreCalcActId: this.projectDatas[this.selectIndex].id,
+            teammodelId: this.$store.state.userInfo.TEAMModelId,
+            id: this.selectClassId,
+            scores: scores,
+          };
+        }
+        this.dataLoading = true;
+        this.$api.learnActivity.updateItemScore(postData).then(
+          (res) => {
+            // 更新原始資料的那一個子項目的成績
+            this.calcData.scoreCalcAct.forEach((element) => {
+              if (element.id === this.projectDatas[this.selectIndex].id) {
+                // 先選中項目
+                element.items.forEach((item) => {
+                  if (item.id === this.selectClassId) {
+                    // 再選中子項目
+                    if (element.type === "lessonrecord") {
+                      // 如果是課堂紀錄要登記三種分數
+                      item.stuActAttendScores = stuActAttendScores;
+                      item.stuActPointScores = stuActPointScores;
+                      item.stuActItactScores = stuActItactScores;
+                    } else {
+                      // 如果不是課堂紀錄登記一種分數
+                      item.scores = scores;
+                    }
+                  }
+                });
+              }
+            });
+            // 登錄分數後平均分數要重算   先取得要修改的子項目索引
+            for (let i = 0; i < this.classDatas.length; i++) {
+              if (this.classDatas[i].id === this.selectClassId) {
+                this.selectClassIndex = i;
+              }
+            }
+            this.calcData.scoreCalcAct.forEach((element) => {
+              if (this.projectDatas[this.selectIndex].id === element.id) {
+                // 子項目資料填入
+                element.items.forEach((subelement) => {
+                  if (subelement.id === this.selectClassId) {
+                    if (element.type !== "lessonrecord") {
+                      let sum = 0;
+                      subelement.scores.forEach((scoreselement) => {
+                        sum = sum + scoreselement;
+                      });
+                      this.classDatas[this.selectClassIndex].score =
+                        Math.round((sum / subelement.scores.length) * 10) / 10;
+                    }
+                  }
+                });
+              }
+            });
+            this.$Message.info(this.$t("scoreCalc.remindMessage5"));
+          },
+          (err) => {
+            this.$Message.error(this.$t("cusMgt.gradeErr"));
+          }
+        );
+        this.dataLoading = false;
+      }
+      this.classDataprop = [];
+    },
+  },
+  watch: {},
+};
+</script>
+<style lang="less" scoped>
+@import "./AddProject.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+.score-container {
+  .right {
+    .content {
+      .body {
+        .card {
+          .ivu-input {
+            color: #2d8cf0;
+            text-align: center;
+            width: 100%;
+            resize: none;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

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

@@ -0,0 +1,126 @@
+.center {
+  display: flex;
+  justify-content: space-between;
+}
+
+.y-center {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.hr-color {
+  height: 1px;
+  border: none;
+  background-color: #dcdee2;
+}
+
+.save-info-ok {
+  text-align: right;
+  color: #808695;
+}
+.save-info-erro {
+  text-align: right;
+  color: #ed4014;
+}
+.marage-y {
+  margin: 0px 5px;
+}
+.dialog-box-div {
+  padding: 10px;
+
+  .div2 {
+    display: flex;
+    align-items: center;
+
+    .enter-box {
+      margin: 1px 5px;
+      border: 1px solid #dcdee2;
+    }
+    .txt-box {
+      text-align: left;
+      width: 400px;
+    }
+    .txt-box2 {
+      text-align: left;
+      width: 350px;
+    }
+  }
+  .div3 {
+    display: flex;
+    align-items: center;
+    .enter-box {
+      margin: 1px 0px;
+      border: 0px solid #dcdee2;
+    }
+  }
+  .info-icon{
+    cursor: pointer;
+    font-size: 16px;
+  }
+  .info-box{
+    padding: 5px;
+    //border: 1px solid #dcdee2;
+    background-color: #f8f8f9;
+    color: #808695;
+    top:0px;
+    .content{
+      font-size: 10px;
+      color: #808695;
+    }
+  }
+  .div-studentScore {
+    .enter-box {
+      margin: 1px 5px;
+      border: 1px solid #dcdee2;
+    }
+    .txt-box {
+      text-align: left;
+      width: 100%;
+      height: 400px;
+    }
+  }
+  .s-text {
+    font-size: 8px;
+    color: #808695;
+  }
+
+  .boxline {
+    border: 1px solid #dcdee2;
+    padding: 10px;
+  }
+  .enter-box {
+    width: 30px;
+    color: #2d8cf0 !important;
+    padding: 1px;
+    text-align: center;
+    border: 1px solid gray;
+  }
+  .column-input {
+    width: 30px;
+    height: 20px;
+    box-sizing: border-box;
+    color: #2d8cf0;
+    margin: 0px 5px;
+    border: none;
+    background: none;
+    text-align: center;
+  }
+}
+/*
+.attend-button{
+  background-color: #fff;
+  padding: 2px 15px;
+  border-color: #dcdee2;
+  border-radius: 4px;
+  color: #515a6e;
+  border: 1px solid transparent;
+  border-color: #dcdee2;
+  cursor: inherit;
+}*/
+.attend-button{
+  white-space:normal ;
+  height: auto;
+  margin: 0 2px;
+  padding: 2px 15px;
+}

+ 441 - 0
TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBoxAttend.vue

@@ -0,0 +1,441 @@
+<template>
+  <div class="score-dialog-box-attend">
+    <Modal :width="800" v-model="modalVisibleView" :title="`${titleName} `+$t('scoreCalc.scoreCalculation')" :class-name="class_name" @on-ok="ok_fun"
+      @on-cancel="cancel">
+      <div class="center">
+        <Button class="attend-button" :type="buttonType[0]" ref="simple_attend" 
+          @click="dialog_box_menu('simple_attend', 0)">{{ $t('scoreCalc.simpleAttendanceCalculation') }}</Button>
+        <Button class="attend-button" :type="buttonType[1]" ref="attend_calculate"
+          @click="dialog_box_menu('attend_calculate', 0)">{{ $t('scoreCalc.attendanceCalculationMethod') }}</Button>
+        <Button class="attend-button" :type="buttonType[2]" ref="custom_calculate1"
+          @click="dialog_box_menu('custom_calculate', 1)">{{ $t('scoreCalc.customCalculation') }}1</Button>
+        <Button class="attend-button" :type="buttonType[3]" ref="custom_calculate2"
+          @click="dialog_box_menu('custom_calculate', 2)">{{ $t('scoreCalc.customCalculation') }}2</Button>
+        <Button class="attend-button" :type="buttonType[4]" ref="custom_calculate3"
+          @click="dialog_box_menu('custom_calculate', 3)">{{ $t('scoreCalc.customCalculation') }}3</Button>
+      </div>
+      <div v-if="showContent === 'simple_attend'" class="dialog-box-div"><!--簡單出席法-->
+        <div>
+          <div>
+            <span>{{$t('scoreCalc.calculationDescription1')}}</span>
+          </div>
+          <br>
+          <Row>
+            <Col span="17">
+            <div class="div2">
+              <span>{{$t('scoreCalc.calculationDescription2')}}</span>
+              <input type="text" v-model="Count_attend_Temp.simple.score" class="enter-box" maxlength="2" />
+              <span>{{$t('scoreCalc.marks')}}</span>
+            </div>
+            <br>
+            <div>
+              <div>{{$t('scoreCalc.example')}}</div>
+              <div>{{$t('scoreCalc.attendance')}}: 100</div>
+              <div>{{$t('scoreCalc.absences')}}: 2</div>
+              <div> {{$t('scoreCalc.calculationDescription3')}} 5 {{$t('scoreCalc.marks')}}</div>
+              <div style="color:#808695;"> {{$t('scoreCalc.calculationFormula')}} 100 – ( 2 * <span style="color:#ed4014;">5</span> ) = 90 {{$t('scoreCalc.marks')}}({{$t('scoreCalc.attendance')}})</div>
+            </div>
+            </Col>
+            <Col span="7" class="y-center">
+            <div class="boxline">
+              <div>{{$t('scoreCalc.calculationDescription4')}}</div>
+              <CheckboxGroup v-model="Count_attend_Temp.simple.situation" class="">
+                <div>
+                  <Checkbox label="absent">{{$t('scoreCalc.absence2')}}</Checkbox>
+                </div>
+                <div>
+                  <Checkbox label="SL">{{$t('scoreCalc.sickLeave2')}}</Checkbox>
+                </div>
+                <div>
+                  <Checkbox label="PL">{{$t('scoreCalc.personalLeave2')}}</Checkbox>
+                </div>
+                <div>
+                  <Checkbox label="OL">{{$t('scoreCalc.publicLeave2')}}</Checkbox>
+                </div>
+              </CheckboxGroup>
+            </div>
+            </Col>
+          </Row>
+        </div>
+      </div>
+      <div v-if="showContent === 'attend_calculate'" class="dialog-box-div"><!--出席計算法-->
+        <div>
+          <div>
+            <span>{{$t('scoreCalc.calculationDescription5')}}</span>
+          </div>
+          <br>
+          <Row>
+            <Col span="17">
+            <div class="div2">
+              <span>{{$t('scoreCalc.calculationDescription6')}}</span>
+              <input type="text" v-model="Count_attend_Temp.attend.score" class="enter-box" maxlength="3" />
+              <span>{{$t('scoreCalc.marks')}}</span>
+            </div>
+            <div class="div2">
+              <span>{{$t('scoreCalc.attendanceOver')}}</span>
+              <input type="text" v-model="Count_attend_Temp.attend.percent" class="enter-box" maxlength="3" />
+              <span>{{$t('scoreCalc.isFullMark')}}</span>
+            </div>
+            <br>
+            <div>
+              <div>{{$t('scoreCalc.example')}}</div>
+              <div>{{$t('scoreCalc.classGrades')}}100</div>
+              <div>{{$t('scoreCalc.totalNumberClasses')}}:10</div>
+              <div>{{$t('scoreCalc.attendQwen')}}:8</div>
+              <div>{{$t('scoreCalc.calculationDescription6')}} <span style="color:#ed4014;">1</span> {{$t('scoreCalc.marks')}}</div>
+              <div>{{$t('scoreCalc.attendanceOver')}} <span style="color:#ed4014;">90</span> {{$t('scoreCalc.isFullMark')}}</div>              
+              <div style="color:#808695;">{{$t('scoreCalc.formula')}}
+              <div>8/ 10 * 100 = 80 / 100 - ( <span style="color:#ed4014;">90</span> – 80 ) * <span style="color:#ed4014;">1</span> = 90
+                {{$t('scoreCalc.marks')}}({{$t('scoreCalc.attendance')}})</div></div>
+            </div>
+            </Col>
+            <Col span="7" class="y-center">
+            <div class="boxline">
+              <div>{{$t('scoreCalc.calculationDescription4')}}</div>
+              <CheckboxGroup v-model="Count_attend_Temp.attend.situation">
+                <div>
+                  <Checkbox label="absent">{{$t('scoreCalc.absence2')}}</Checkbox>
+                </div>
+                <div>
+                  <Checkbox label="SL">{{$t('scoreCalc.sickLeave2')}}</Checkbox>
+                </div>
+                <div>
+                  <Checkbox label="PL">{{$t('scoreCalc.personalLeave2')}}</Checkbox>
+                </div>
+                <div>
+                  <Checkbox label="OL">{{$t('scoreCalc.publicLeave2')}}</Checkbox>
+                </div>
+              </CheckboxGroup>
+            </div>
+            </Col>
+          </Row>
+        </div>
+      </div>
+      <div v-if="showContent === 'custom_calculate'" class="dialog-box-div"><!--自訂計算-->
+        <div>
+          <div>
+            {{$t('scoreCalc.calculationDescription7')}}
+          </div>
+          <br>
+          <Row>
+            <Col span="6">
+            <div>X:{{$t('scoreCalc.totalNumberClasses')}}</div>
+            <div>Y:{{$t('scoreCalc.attendQwen')}}</div>
+            </Col>
+            <Col span="8">
+              <div>A:{{$t('scoreCalc.absences')}}</div>
+              <div>B:{{$t('scoreCalc.numberOfSick')}}</div>
+              <div>C:{{$t('scoreCalc.numberOfPerson')}}</div>
+              <div>D:{{$t('scoreCalc.numberOfPublic')}}</div>
+              <br>
+            </Col>
+            <Col v-if="infoShow" span="10" class="info-box">
+              <div style="text-decoration: underline;">{{$t('scoreCalc.formulaExample')}}ROUND(X)</div>
+              <div class="content">ROUND、MAX、MIN、SQRT、ABS、LN、EXP、POWER、INT、CEILING、FLOOR、LOG10、LOG2、RAND、SIGN、SIN、COS、TAN</div>
+            </Col>
+          </Row>          
+          <div>
+            <div><u>{{$t('scoreCalc.calculationFormula')}}</u>
+              <Icon type="md-alert" class="info-icon" @click="infoShow = !infoShow;"/>
+            </div>
+            <div class="div2">
+              <textarea type="text" rows="4" cols="30" datatype="*" class="enter-box txt-box"
+                :placeholder="custom_calculate1_data" required @change="textareafun" v-model="custom_data"></textarea>
+              <span>={{$t('scoreCalc.attendance')}}</span>
+            </div>
+            <!-- <div class="s-text"> {{$t('scoreCalc.calculationDescription9')}}</div> -->
+          </div>
+          <div style="  padding:5px;margin-top:10px;">
+            <div style=""><u>{{$t('scoreCalc.instantPreview')}}</u>: 
+            <span style="font-size:8px;"> ※<span style="color: #2d8cf0;">{{$t('scoreCalc.blueWord')}}</span>{{$t('scoreCalc.canModifyable')}}</span>
+            </div>
+            <div class="div3">
+              <span>{{$t('scoreCalc.totalNumberClasses')}}</span> <input type="text" v-model="checkNum.classTatol" class="enter-box" maxlength="3" @change="numberChanteFun"/>
+              <span> {{$t('scoreCalc.attendQwen')}}</span> <input type="text" v-model="checkNum.attend" class="enter-box" maxlength="3" @change="numberChanteFun"/>
+              <span> {{$t('scoreCalc.absence')}}</span> <input type="text" v-model="checkNum.absent" class="enter-box" maxlength="3" @change="numberChanteFun"/>
+              <span> {{$t('scoreCalc.sickLeave')}}</span> <input type="text" v-model="checkNum.SL" class="enter-box" maxlength="3" @change="numberChanteFun"/>
+              <span> {{$t('scoreCalc.personalLeave')}}</span> <input type="text" v-model="checkNum.PL" class="enter-box" maxlength="3" @change="numberChanteFun"/>
+              <span> {{$t('scoreCalc.publicLeave')}}</span> <input type="text" v-model="checkNum.OL" class="enter-box" maxlength="3" @change="numberChanteFun"/>
+            </div>
+            <div>{{$t('scoreCalc.score')}}:<span style="color: #ed4014;">{{ checkNum.Result }}</span></div>
+          </div>
+        </div>
+      </div>
+    </Modal>
+  </div>
+</template>
+<script>
+export default {
+  components: {
+
+  },
+  props: {
+    modalVisible: Boolean,
+    titleName: String,
+    class_name: String,
+    Count_attend: Object,
+    scoreCalcActId: String,
+    scoreCalcId: String,//成績表ID
+    evaluateExcelFormula: Function,//傳入轉換EXCEL的公式
+    evenlyShow:Function,//傳入//整除顯示的公式
+  },
+  data() {
+    return {
+      modalVisibleView: false,
+      showContent: 'simple_attend',
+      buttonType: ['primary', 'default', 'default', 'default', 'default'],
+      custom_calculate1_data: this.$t('scoreCalc.calculationDescription8')+'\nY / X*100',
+      custom_data: '',//顯示出席法的內容
+      Count_attend_Temp: {},
+      checkNum: { classTatol: 10, attend: 8, absent: 1, SL: 1, PL: 0, OL: 0, Result: 0 },
+      //modalVisible: false,
+      infoShow:false,
+    }
+  },
+  computed: {
+
+  },
+  methods: {
+    ok_fun() {
+      //this.$Message.info('Clicked ok');
+      //this.Count_attend = JSON.parse(JSON.stringify(this.Count_attend_Temp));
+      this.$api.learnActivity.getScoreCalcAll({ "id": this.scoreCalcId }).then(
+        res => {
+          if (res) {
+            let typeId = {
+              simple: { id: "", name: "", data: {}, use: false },
+              attend: { id: "", name: "", data: {}, use: false },
+              custom1: { id: "", name: "", data: {}, use: false },
+              custom2: { id: "", name: "", data: {}, use: false },
+              custom3: { id: "", name: "", data: {}, use: false }
+            };
+            if (this.Count_attend_Temp.way === 'simple') {
+              typeId.simple.use = true;
+            } else if (this.Count_attend_Temp.way === 'attend') {
+              typeId.attend.use = true;
+            } else if (this.Count_attend_Temp.way === 'custom1') {
+              typeId.custom1.use = true;
+            } else if (this.Count_attend_Temp.way === 'custom2') {
+              typeId.custom2.use = true;
+            } else if (this.Count_attend_Temp.way === 'custom3') {
+              typeId.custom3.use = true;
+            }
+
+            let filteredData = res.scoreCalcFunc.filter(item => item.method === "attend");//過濾標籤資料。
+            let customCount = 1;
+            for (let i = 0; i < filteredData.length; i++) {
+              if (filteredData[i].template === "simpleAttend") {
+                typeId.simple.data = filteredData[i];
+                typeId.simple.id = filteredData[i].id;
+                typeId.simple.name = filteredData[i].name;
+              } else if (filteredData[i].template === "attendRate") {
+                typeId.attend.data = filteredData[i];
+                typeId.attend.id = filteredData[i].id;
+                typeId.attend.name = filteredData[i].name;
+              } else if (filteredData[i].template === "custom") {
+                let typeName = "custom" + customCount;
+                typeId[typeName].data = filteredData[i];
+                typeId[typeName].id = filteredData[i].id;
+                typeId[typeName].name = filteredData[i].name;
+                customCount++;
+              }
+            }
+            this.giveData_API(typeId);
+          }
+        },
+        err => {
+          //this.$Message.error(this.$t('learnActivity.updateProjectListSort.Err'))
+        }
+      )
+      this.$emit('closeModal', { value1: false, value2: JSON.parse(JSON.stringify(this.Count_attend_Temp)) });
+    },
+    giveData_API(typeId) {
+      let giveData = {
+        "scoreCalcActId": this.scoreCalcActId,
+        "teammodelId": this.$store.state.userInfo.TEAMModelId,
+        "method": "attend",
+        "scoreCalcFunc": [
+          {
+            "id": typeId.simple.id,
+            "name": typeId.simple.name,
+            "use": typeId.simple.use,
+            "template": "simpleAttend",
+            "keyvals": [
+              {
+                "key": typeId.simple.data.keyvals.find(item => item.key === '一次扣幾分')?.key,
+                "val": this.Count_attend_Temp.simple.score
+              },
+              {
+                "key": typeId.simple.data.keyvals.find(item => item.key === 'Absent_Sick')?.key,
+                "val": this.Count_attend_Temp.simple.situation.includes('SL').toString()
+              },
+              {
+                "key": typeId.simple.data.keyvals.find(item => item.key === 'Absent')?.key,
+                "val": this.Count_attend_Temp.simple.situation.includes('absent').toString()
+              },
+              {
+                "key": typeId.simple.data.keyvals.find(item => item.key === 'Absent_Personal')?.key,
+                "val": this.Count_attend_Temp.simple.situation.includes('PL').toString()
+              },
+              {
+                "key": typeId.simple.data.keyvals.find(item => item.key === 'Absent_Official')?.key,
+                "val": this.Count_attend_Temp.simple.situation.includes('OL').toString()
+              }
+            ],
+            "content": typeId.simple.data.content
+          },
+          {
+            "id": typeId.attend.id,
+            "name": typeId.attend.name,
+            "use": typeId.attend.use,
+            /* simpleAttend:簡單出席計算法 | attendRate:出席率計算法 | custom:自訂 | standard:標準化評分 | percent:百分比評分  */
+            "template": "attendRate",
+            "keyvals": [
+              {
+                "key": typeId.attend.data.keyvals.find(item => item.key === '每缺席1%扣幾分')?.key,
+                "val": this.Count_attend_Temp.attend.score
+              },
+              {
+                "key": typeId.attend.data.keyvals.find(item => item.key === '出席率超過%為滿分')?.key,
+                "val": this.Count_attend_Temp.attend.percent
+              },
+              {
+                "key": "課堂總次數",
+                "val": "X"
+              },
+              {
+                "key": typeId.attend.data.keyvals.find(item => item.key === 'Absent_Sick')?.key,
+                "val": this.Count_attend_Temp.attend.situation.includes('SL').toString()
+              },
+              {
+                "key": typeId.attend.data.keyvals.find(item => item.key === 'Absent')?.key,
+                "val": this.Count_attend_Temp.attend.situation.includes('absent').toString()
+              },
+              {
+                "key": typeId.attend.data.keyvals.find(item => item.key === 'Absent_Personal')?.key,
+                "val": this.Count_attend_Temp.attend.situation.includes('PL').toString()
+              },
+              {
+                "key": typeId.attend.data.keyvals.find(item => item.key === 'Absent_Official')?.key,
+                "val": this.Count_attend_Temp.attend.situation.includes('OL').toString()
+              }
+            ],
+            /* (病假/缺席/事假/公假) 必須先判斷是否為true,才決定是否要帶入公式 */
+            "content": typeId.attend.data.content
+          },
+        ]
+      };
+      for (let i = 1; i <= 3; i++) {//還需判斷是否有ID
+        const customKey = `custom${i}`;
+        giveData.scoreCalcFunc.push({
+          "id": typeId[customKey].id,
+          "name": typeId[customKey].name,
+          "use": typeId[customKey].use,
+          "template": "custom",
+          "keyvals": typeId[customKey].data.keyvals,
+          "content": this.Count_attend_Temp[customKey].val
+        });
+      }
+      this.$api.learnActivity.updateScorecalc(giveData).then(
+        res => {
+          //console.log("res=" + JSON.stringify(res));
+          //this.$Message.success(this.$t('save Ok'))
+          setTimeout(() => {
+          })
+        },
+        err => {
+          //this.$Message.error(this.$t('Err'))
+        }
+      )
+    },
+    cancel() {
+      //this.$Message.info('Clicked cancel');
+      this.$emit('closeModal', { value1: false, value2: null });
+    },
+    dialog_box_menu(type, num) {
+      this.showContent = type;
+      if (type == 'simple_attend') {
+        this.buttonType = ['primary', 'default', 'default', 'default', 'default'];
+        this.Count_attend_Temp.way = 'simple';
+      } else if (type === 'attend_calculate') {
+        this.buttonType = ['default', 'primary', 'default', 'default', 'default'];
+        this.Count_attend_Temp.way = 'attend';
+      } else if (type === 'custom_calculate' && num === 1) {
+        this.Count_attend_Temp.way = 'custom1';
+        this.custom_data = this.Count_attend_Temp.custom1.val;
+        this.buttonType = ['default', 'default', 'primary', 'default', 'default'];
+      } else if (type === 'custom_calculate' && num === 2) {
+        this.custom_data = this.Count_attend_Temp.custom2.val;
+        this.Count_attend_Temp.way = 'custom2';
+        this.buttonType = ['default', 'default', 'default', 'primary', 'default'];
+      } else if (type === 'custom_calculate' && num === 3) {
+        this.Count_attend_Temp.way = 'custom3';
+        this.custom_data = this.Count_attend_Temp.custom3.val;
+        this.buttonType = ['default', 'default', 'default', 'default', 'primary'];
+      }
+      this.numberChanteFun();
+    },
+    textareafun() {
+      if (this.Count_attend_Temp.way == 'custom1') {
+        this.Count_attend_Temp.custom1.val = this.custom_data;
+      } else if (this.Count_attend_Temp.way == 'custom2') {
+        this.Count_attend_Temp.custom2.val = this.custom_data;
+      } else if (this.Count_attend_Temp.way == 'custom3') {
+        this.Count_attend_Temp.custom3.val = this.custom_data;
+      }
+      this.numberChanteFun();
+    },
+    numberChanteFun() {//輸入改變就執行此程式
+      const values = {
+        X: this.checkNum.classTatol,//課堂總次數
+        Y: this.checkNum.attend,//出席次數
+        A: this.checkNum.absent,//缺席
+        B: this.checkNum.SL,//病假
+        C: this.checkNum.PL,//事假
+        D: this.checkNum.OL,//公假
+      };
+      let formula = this.custom_data;
+      if (typeof formula === 'undefined' || formula === null || formula === '') {
+        this.checkNum.Result = 100;
+      } else {
+        let scoreCount = Number(this.evaluateExcelFormula(formula, values));
+        if (isNaN(scoreCount)) {
+          this.checkNum.Result = scoreCount;
+        } else {
+          this.checkNum.Result = this.evenlyShow(this.evaluateExcelFormula(formula, values), 1);
+        }
+      }
+    }
+  },
+  created() {
+
+  },
+  watch: {
+    modalVisible: {
+      immediate: true,
+      handler(newVal) {
+        this.modalVisibleView = newVal;
+        this.Count_attend_Temp = JSON.parse(JSON.stringify(this.Count_attend));
+        if (this.Count_attend_Temp.way == 'simple') {
+          this.dialog_box_menu('simple_attend', 0);
+        } else if (this.Count_attend_Temp.way == 'attend') {
+          this.dialog_box_menu('attend_calculate', 0);
+        } else if (this.Count_attend_Temp.way == 'custom1') {
+          this.dialog_box_menu('custom_calculate', 1);
+        } else if (this.Count_attend_Temp.way == 'custom2') {
+          this.dialog_box_menu('custom_calculate', 2);
+        } else if (this.Count_attend_Temp.way == 'custom3') {
+          this.dialog_box_menu('custom_calculate', 3);
+        }
+      }
+    }
+  }
+
+}
+</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>

+ 401 - 0
TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBoxScoreCont.vue

@@ -0,0 +1,401 @@
+<template>
+  <div class="score-dialog-box-score-cont">
+    <Modal v-model="modalVisibleView" :title="`${titleName} `+$t('scoreCalc.scoreCalculation')" :class-name="class_name" @on-ok="ok_fun"
+      @on-cancel="cancel">
+      <div class="center">
+        <Button class="attend-button" :type="buttonType[0]" ref="standard_score" @click="dialog_box_menu('standard_score')">{{ $t('scoreCalc.percentageScore') }}</Button>
+        <Button class="attend-button" :type="buttonType[1]" ref="percentage_score" @click="dialog_box_menu('percentage_score')">{{ $t('scoreCalc.standardizedsScoring') }}</Button>
+        <Button class="attend-button" :type="buttonType[2]" ref="custom_score1" @click="dialog_box_menu('custom_score', 1)">{{ $t('scoreCalc.customScoring') }}1</Button>
+        <Button class="attend-button" :type="buttonType[3]" ref="custom_score2" @click="dialog_box_menu('custom_score', 2)">{{ $t('scoreCalc.customScoring') }}2</Button>
+        <Button class="attend-button" :type="buttonType[4]" ref="custom_score3" @click="dialog_box_menu('custom_score', 3)">{{ $t('scoreCalc.customScoring') }}3</Button>
+      </div>
+      <div v-if="showContent === 'standard_score'" class="dialog-box-div">
+        <div>
+          <div class="div2">
+            {{ $t('scoreCalc.calculationDescription10') }}
+          </div>
+          <Row>
+            <Col span="14">
+            <br>
+            <div>
+              <div>x:{{ $t('scoreCalc.gravityCalculationScore') }}</div>
+              <div>y:{{ $t('scoreCalc.averageScore') }}</div>
+              <div> SD:{{ $t('scoreCalc.standardDeviation') }}</div>
+              <div> {{ $t('scoreCalc.standardScoreZFormula') }}
+                <math>
+                  <mfrac>
+                    <mrow>
+                      <mi>x</mi>
+                      <mo>-</mo>
+                      <mi>y</mi>
+                    </mrow>
+                    <mrow>
+                      <mi>S</mi>
+                      <mi>D</mi>
+                    </mrow>
+                  </mfrac>
+                </math>
+              </div>
+              <div class="div2">
+                <span>{{ $t('scoreCalc.derivedStandardScoreTFormula') }} T = 10Z+</span>
+                <input type="text" v-model="Count_Temp.standard.score" class="enter-box" maxlength="2" />
+              </div>
+              <div>{{ $t('scoreCalc.calculationDescription11') }}</div>
+            </div>
+            </Col>
+            <Col span="10" class="y-center">
+            <div class="boxline">
+              <div>{{ $t('scoreCalc.example') }}</div>
+              <div>{{ $t('scoreCalc.gravityCalculationScore') }}:18 </div>
+              <div>{{ $t('scoreCalc.indicatesAverageScore') }}:14</div>
+              <div>{{ $t('scoreCalc.standardDeviation') }}:3</div>
+              <div style="color:#808695; margin:5px 0px;">
+                <math>
+                  <mfrac>
+                    <mrow>
+                      <mn>18</mn>
+                      <mo>-</mo>
+                      <mn>14</mn>
+                    </mrow>
+                    <mn>3</mn>
+                  </mfrac>
+                </math>
+                = 1.33
+              </div>
+              <div style="color:#808695;"> 10× 1.33+ <span style="color:#ed4014;">50</span>= 63.3{{ $t('scoreCalc.marks') }}</div>
+            </div>
+            </Col>
+          </Row>
+        </div>
+      </div>
+      <div v-if="showContent === 'percentage_score'" class="dialog-box-div">
+        <div>
+          <div>
+            <span>{{ $t('scoreCalc.calculationDescription12') }}</span>
+          </div>
+          <br>
+          <div style="color:#808695; ">
+            <div>{{ $t('scoreCalc.example') }}</div>
+            <div>{{ $t('scoreCalc.gravityCalculationScore') }}:12</div>
+            <div>{{ $t('scoreCalc.highestScore') }}:20</div>
+            <div style="margin-top: 5px;">
+              {{ $t('scoreCalc.formulaExample') }}100 x
+              <math>
+                <mfrac>
+                  <mn>12</mn>
+                  <mn>20</mn>
+                </mfrac>
+              </math>
+              = 60 {{ $t('scoreCalc.marks') }}
+            </div>
+          </div>
+        </div>
+      </div>
+      <div v-if="showContent === 'custom_score'" class="dialog-box-div">
+        <div>
+          <div>
+            {{ $t('scoreCalc.calculationDescription13') }}
+          </div>          
+          <Row>
+            <Col span="12">
+              <div>A:{{ $t('scoreCalc.gravityCalculationScore') }}</div>
+              <div>B:{{ $t('scoreCalc.classQwen') }}</div>
+              <div>C:{{ $t('scoreCalc.totalScoreClass') }}</div>
+              <div>D:{{ $t('scoreCalc.totalNumberStudents') }}</div>              
+              <br>
+            </Col>
+            <Col v-if="infoShow" span="10" class="info-box">
+              <div style="text-decoration: underline;">{{$t('scoreCalc.formulaExample')}}ROUND(X)</div>
+              <div class="content">ROUND、MAX、MIN、SQRT、ABS、LN、EXP、POWER、INT、CEILING、FLOOR、LOG10、LOG2、RAND、SIGN、SIN、COS、TAN</div>
+            </Col>
+          </Row>
+          <div>
+            <div><u>{{ $t('scoreCalc.calculationFormula') }}</u>
+              <Icon type="md-alert" class="info-icon" @click="infoShow = !infoShow;"/>
+            </div>
+            <div class="div2">
+              <textarea type="text" rows="4" cols="30" datatype="*" class="enter-box txt-box2"
+                :placeholder="custom_score1_data" required v-model="custom_data" @change="textareafun"></textarea>
+              <span>={{ titleName }} {{ $t('scoreCalc.score') }}</span>
+            </div>
+            <!-- <div class="s-text"> {{ $t('scoreCalc.calculationDescription9') }}</div> -->
+          </div>
+          <div>
+            <div style="margin-top:20px;"><u>{{ $t('scoreCalc.instantPreview') }}</u>:
+              <span style="font-size:8px;"> ※<span style="color: #2d8cf0;">{{ $t('scoreCalc.blueWord') }}</span>{{ $t('scoreCalc.canModifyable') }}</span>
+            </div>
+            <div class="div3">
+              <span>{{ $t('scoreCalc.gravityCalculationScore') }}<input type="text" v-model="checkNum.Gravityscore" class="enter-box" maxlength="3" @change="numberChanteFun"/></span> 
+              <span> {{ $t('scoreCalc.totalNumberClasses') }}<input type="text" v-model="checkNum.classTatol" class="enter-box" maxlength="3" @change="numberChanteFun"/></span> 
+              <span> {{ $t('scoreCalc.totalScoreClass') }}<input type="text" v-model="checkNum.allScore" class="enter-box" maxlength="3" @change="numberChanteFun"/></span> 
+              <span> {{ $t('scoreCalc.totalNumberStudents') }}<input type="text" v-model="checkNum.studentNum" class="enter-box" maxlength="3" @change="numberChanteFun"/></span> 
+            </div>            
+            <div>{{ $t('scoreCalc.score') }}:<span style="color: #ed4014;">{{ checkNum.Result }}</span></div>
+          </div>
+        </div>
+      </div>
+    </Modal>
+</div>
+</template>
+<script>
+export default {
+  components: {
+
+  },
+  props: {
+    modalVisible: Boolean,
+    titleName: String,
+    class_name: String,
+    Count_point: Object,
+    Count_interact: Object,
+    scoreCalcActId: String,
+    scoreCalcId: String,//成績表ID
+    evaluateExcelFormula:  Function,//傳入轉換EXCEL的公式
+    evenlyShow:Function,//傳入//整除顯示的公式
+  },
+  data() {
+    return {
+      infoShow:false,
+      modalVisibleView: false,
+      showContent: 'standard_score',
+      buttonType: ['primary', 'default', 'default', 'default', 'default'],
+      custom_score1_data: this.$t('scoreCalc.formulaExample')+'10×√A  '+this.$t('scoreCalc.writtenas')+'\n10*SQRT(A) ',
+      custom_data: '',//顯示出席法的內容
+      Count_Temp: {},
+      checkNum : {Gravityscore:80,classTatol:10,allScore:10,studentNum:50,Result:0}
+    }
+  },
+  computed: {
+
+  },
+  methods: {
+    ok_fun() {
+      //this.$Message.info('Clicked ok');  
+      this.$api.learnActivity.getScoreCalcAll({ "id": this.scoreCalcId }).then(
+        res => {
+          if (res) {
+            let typeId = {
+              method : "",
+              standard: { id: "", name: "", data: {}, use: false },
+              percent: { id: "", name: "", data: {}, use: false },
+              custom1: { id: "", name: "", data: {}, use: false },
+              custom2: { id: "", name: "", data: {}, use: false },
+              custom3: { id: "", name: "", data: {}, use: false }
+            };
+            if (this.Count_Temp.way === 'standard') {
+              typeId.standard.use = true;
+            } else if (this.Count_Temp.way === 'percent') {
+              typeId.percent.use = true;
+            } else if (this.Count_Temp.way === 'custom1') {
+              typeId.custom1.use = true;
+            } else if (this.Count_Temp.way === 'custom2') {
+              typeId.custom2.use = true;
+            } else if (this.Count_Temp.way === 'custom3') {
+              typeId.custom3.use = true;
+            }
+
+            let filteredData = {};
+            if (this.titleName == this.$t('scoreCalc.point')) {//記分板
+              typeId.method = "point";
+              filteredData = res.scoreCalcFunc.filter(item => item.method === "point");//過濾標籤資料。
+              this.$emit('closeModal', { value1: false, value2: '記分板', value3: JSON.parse(JSON.stringify(this.Count_Temp)) });
+            } else if (this.titleName == this.$t('scoreCalc.interactiveScore')) {//互動分
+              typeId.method = "interaction";
+              filteredData = res.scoreCalcFunc.filter(item => item.method === "interaction");//過濾標籤資料。
+              this.$emit('closeModal', { value1: false, value2: '互動分', value3: JSON.parse(JSON.stringify(this.Count_Temp)) });
+            }
+
+            let customCount = 1;
+            for (let i = 0; i < filteredData.length; i++) {
+              if (filteredData[i].template === "standard") {
+                typeId.standard.data = filteredData[i];
+                typeId.standard.id = filteredData[i].id;
+                typeId.standard.name = filteredData[i].name;
+              } else if (filteredData[i].template === "percent") {
+                typeId.percent.data = filteredData[i];
+                typeId.percent.id = filteredData[i].id;
+                typeId.percent.name = filteredData[i].name;
+              } else if (filteredData[i].template === "custom") {
+                let typeName = "custom" + customCount;
+                typeId[typeName].data = filteredData[i];
+                typeId[typeName].id = filteredData[i].id;
+                typeId[typeName].name = filteredData[i].name;
+                customCount++;
+              }
+            }
+            this.giveData_API(typeId);
+          }
+        },
+        err => {
+          //this.$Message.error(this.$t('learnActivity.updateProjectListSort.Err'))
+        }
+      )
+    },
+    giveData_API(typeId) {
+      let giveData = {
+        "scoreCalcActId": this.scoreCalcActId,
+        "teammodelId": this.$store.state.userInfo.TEAMModelId,
+        "method": typeId.method,//point / interaction
+        "scoreCalcFunc": [
+          {
+            "id": typeId.standard.id,
+            "name": typeId.standard.name,
+            "use": typeId.standard.use,
+            "template": "standard",
+            "keyvals": [
+              {
+                "key": "原始分數",
+                "val": "X"
+              },
+              {
+                "key": "平均分數",
+                "val": "Y"
+              },
+              {
+                "key": typeId.standard.data.keyvals.find(item => item.key === '平均數')?.key,
+                "val": this.Count_Temp.standard.score
+              },
+              {
+                "key": "標準差",
+                "val": "50"
+              },
+            ],
+            "content": typeId.standard.data.content
+          },
+          {
+            "id": typeId.percent.id,
+            "name": typeId.percent.name,
+            "use": typeId.percent.use,
+            /* simpleAttend:簡單出席計算法 | attendRate:出席率計算法 | custom:自訂 | standard:標準化評分 | percent:百分比評分  */
+            "template": "percent",
+            "keyvals": [
+              {
+                "key": "原始分數",
+                "val": "X"
+              },
+              {
+                "key": "最高分數",
+                "val": "Y"
+              }
+            ],
+            /* (病假/缺席/事假/公假) 必須先判斷是否為true,才決定是否要帶入公式 */
+            "content": typeId.percent.data.content
+          },
+        ]
+      };
+      for (let i = 1; i <= 3; i++) {//還需判斷是否有ID
+        const customKey = `custom${i}`;
+        giveData.scoreCalcFunc.push({
+          "id": typeId[customKey].id,
+          "name": typeId[customKey].name,
+          "use": typeId[customKey].use,
+          "template": "custom",
+          "keyvals": typeId[customKey].data.keyvals,
+          "content": this.Count_Temp[customKey].val
+        });
+      }
+      this.$api.learnActivity.updateScorecalc(giveData).then(
+        res => {
+          //console.log("res=" + JSON.stringify(res));
+          //this.$Message.success(this.$t('save Ok'))
+          setTimeout(() => {
+          })
+        },
+        err => {
+          //this.$Message.error(this.$t('Err'))
+        }
+      )
+    },
+    cancel() {
+      //this.$Message.info('Clicked cancel');
+      this.$emit('closeModal', { value1: false, value2: null, value3: null });
+    },
+    dialog_box_menu(showContent, num) {
+      this.showContent = showContent;
+      if (showContent == 'standard_score') {
+        this.buttonType = ['primary', 'default', 'default', 'default', 'default'];
+        this.Count_Temp.way = 'standard';
+      } else if (showContent == 'percentage_score') {
+        this.buttonType = ['default', 'primary', 'default', 'default', 'default'];
+        this.Count_Temp.way = 'percent';
+      } else if (showContent == 'custom_score' && num == 1) {
+        this.buttonType = ['default', 'default', 'primary', 'default', 'default'];
+        this.custom_data = this.Count_Temp.custom1.val;
+        this.Count_Temp.way = 'custom1';
+      } else if (showContent == 'custom_score' && num == 2) {
+        this.buttonType = ['default', 'default', 'default', 'primary', 'default'];
+        this.custom_data = this.Count_Temp.custom2.val;
+        this.Count_Temp.way = 'custom2';
+      } else if (showContent == 'custom_score' && num == 3) {
+        this.buttonType = ['default', 'default', 'default', 'default', 'primary'];
+        this.custom_data = this.Count_Temp.custom3.val;
+        this.Count_Temp.way = 'custom3';
+      }
+      this.numberChanteFun();
+    },
+    textareafun() {
+      if (this.Count_Temp.way == 'custom1') {
+        this.Count_Temp.custom1.val = this.custom_data;
+      } else if (this.Count_Temp.way == 'custom2') {
+        this.Count_Temp.custom2.val = this.custom_data;
+      } else if (this.Count_Temp.way == 'custom3') {
+        this.Count_Temp.custom3.val = this.custom_data;
+      }
+      this.numberChanteFun();
+    },
+    numberChanteFun() {//輸入改變就執行此程式
+      const values = {
+        A: this.checkNum.Gravityscore,//比重計算分數
+        B: this.checkNum.classTatol,//課堂總數
+        C: this.checkNum.allScore,//全班總分
+        D: this.checkNum.studentNum,//學生總數
+      };
+      let formula = this.custom_data;
+      if (typeof formula === 'undefined' || formula === null || formula === '') {
+        this.checkNum.Result = 100;
+      } else {
+        let scoreCount = Number(this.evaluateExcelFormula(formula, values));
+        if (isNaN(scoreCount)) {
+          this.checkNum.Result = scoreCount;
+        } else {
+          this.checkNum.Result = this.evenlyShow(this.evaluateExcelFormula(formula, values), 1);
+        }
+      }
+    }
+  },
+  watch: {
+    modalVisible: {
+      immediate: true,
+      handler(newVal) {
+        this.modalVisibleView = newVal;        
+      if (this.titleName == this.$t('scoreCalc.point')) {//記分板
+        this.Count_Temp = JSON.parse(JSON.stringify(this.Count_point));
+      } else if (this.titleName == this.$t('scoreCalc.interactiveScore')) {//互動分
+        this.Count_Temp = JSON.parse(JSON.stringify(this.Count_interact));
+      }
+      //確認按鈕位置
+      if (this.Count_Temp.way == 'standard') {
+        this.dialog_box_menu('standard_score', 0);
+      } else if (this.Count_Temp.way == 'percent') {
+        this.dialog_box_menu('percentage_score', 0);
+      } else if (this.Count_Temp.way == 'custom1') {
+        this.dialog_box_menu('custom_score', 1);
+      } else if (this.Count_Temp.way == 'custom2') {
+        this.dialog_box_menu('custom_score', 2);
+      } else if (this.Count_Temp.way == 'custom3') {
+        this.dialog_box_menu('custom_score', 3);
+      }
+      }
+    }
+  }
+}
+</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>

+ 285 - 0
TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBoxStudentScore.vue

@@ -0,0 +1,285 @@
+<template>
+  <div class="score-dialog-box-student-score">
+
+    <Modal v-model="modalVisibleView" :title="className + $t('scoreCalc.scoreCalc')" class-name="titleClassStyle" :class_type="class_type"
+      @on-ok="ok" @on-cancel="cancel" :width="modalWidth">
+      <div class="dialog-box-div center" style="padding: 0px;">
+        <div class="left">
+          <div>
+            <span class="s-text"> ※<span style="color: #2d8cf0;">{{$t('scoreCalc.blueWord')}}</span>{{$t('scoreCalc.modifyContent')}}</span>
+            <span v-if="class_type == 'lessonrecord'" class="s-text">{{$t('scoreCalc.attendState')}}</span>
+          </div>
+          <div>
+            <DataTable :value="classData" showGridlines v-if="class_type == 'lessonrecord'" :scrollable="true"
+              scrollHeight="400px" editMode="cell" class="editable-cells-table" responsiveLayout="scroll" >
+              <Column field="name" :header="$t('scoreCalc.name')" :styles="{ 'min-width': '120px', 'text-align': 'center', 'display': 'block' }" >
+                <template #body="rowData">                  
+                    <div >
+                    {{ rowData.data.name }}
+                  </div>
+                </template>
+              </Column>
+              <Column field="id" :header="$t('scoreCalc.id')"
+                :styles="{ 'min-width': '120px', 'text-align': 'center', 'display': 'block' }">
+                <template #body="rowData">
+                  <div>
+                    {{ rowData.data.id }}
+                  </div>
+                </template>
+              </Column>
+              <Column field="attendance" :header="$t('scoreCalc.attend')"        
+              :styles="{ 'min-width': '120px', 'color': 'rgb(45, 140, 240)', 'text-align': 'center', 'display': 'block' }"
+              :headerStyle="{ 'color': '#515a6e' }">
+                <template #body="rowData">
+                  <div >
+                    <input type="text" v-model.number="rowData.data[rowData.column.field]" @input="falseIsSave()"
+                      maxlength="1" class="column-input" />
+                  </div>
+                </template>
+              </Column>
+              <Column field="score" :header="$t('scoreCalc.point')"       
+                :styles="{ 'min-width': '120px', 'color': 'rgb(45, 140, 240)', 'text-align': 'center', 'display': 'block' }"
+                :headerStyle="{ 'color': '#515a6e' }">
+                <template #body="rowData">
+                  <div >
+                    <input type="text" v-model.number="rowData.data[rowData.column.field]" @input="falseIsSave()"
+                      maxlength="3" class="column-input" />
+                  </div>
+                </template>
+              </Column>
+              <Column field="interactiveScore" :header="$t('scoreCalc.interactiveScore')"
+                :styles="{ 'min-width': '120px', 'color': 'rgb(45, 140, 240)', 'text-align': 'center', 'display': 'block' }"
+                :headerStyle="{ 'color': '#515a6e' }">
+                <template #body="rowData">
+                  <div >
+                    <input type="text" v-model.number="rowData.data[rowData.column.field]" @input="falseIsSave()"
+                      maxlength="3" class="column-input" />
+                  </div>
+                </template>
+              </Column>
+            </DataTable>
+
+            <DataTable :value="classData" showGridlines v-if="class_type == 'activity'" :scrollable="true"
+              scrollHeight="400px" editMode="cell" class="editable-cells-table" responsiveLayout="scroll">
+              <Column field="name" :header="$t('scoreCalc.name')"
+                :styles="{ 'min-width': '120px', 'text-align': 'center', 'display': 'block' }">
+                <template #body="rowData">
+                  <div style="text-align: center;">
+                    {{ rowData.data.name }}
+                  </div>
+                </template>
+              </Column>
+              <Column field="id" :header="$t('scoreCalc.id')"
+                :styles="{ 'min-width': '120px', 'text-align': 'center', 'display': 'block' }">
+                <template #body="rowData">
+                  <div>
+                    {{ rowData.data.id }}
+                  </div>
+                </template>
+              </Column>
+              <Column field="score" :header="$t('scoreCalc.score')"
+                :styles="{ 'min-width': '120px', 'color': 'rgb(45, 140, 240)', 'text-align': 'center', 'display': 'block' }"
+                :headerStyle="{ 'color': '#515a6e' }">
+                <template #body="rowData">
+                  <div style="width: 100%">
+                    <input type="text" v-model.number="rowData.data[rowData.column.field]" @input="falseIsSave()"
+                      maxlength="3" class="column-input" />
+                  </div>
+                </template>
+              </Column>
+            </DataTable>
+
+
+
+          </div>
+        </div>
+        <div class="right">
+          <div>
+            <span style="font-weight: bold;">{{$t('scoreCalc.pasteMultiple')}}</span>
+            <span class="s-text">{{$t('scoreCalc.pasteEXCEL')}}</span>
+          </div>
+
+          <div class="div-studentScore">
+            <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
+              @input="isTextareaInput = true, TextareaInput_system"></textarea>
+            <textarea v-if="class_type == 'activity'" v-model="textareaValue_system" type="text" rows="4" cols="30"
+              datatype="*" class="enter-box txt-box" :placeholder="custom_score_data2" required
+              @input="isTextareaInput = true, TextareaInput_custom"></textarea>
+          </div>
+          <div v-if="isSave" class="save-info-ok">
+            <Icon type="md-checkmark-circle" />{{$t('scoreCalc.isSave')}}
+          </div>
+          <div v-if="!isSave" class="save-info-erro">
+            <Icon type="md-alert" />{{$t('scoreCalc.notSave')}}
+          </div>
+        </div>
+      </div>
+      <Loading :top="100" v-show="dataLoading" type="1"></Loading>
+    </Modal>
+  </div>
+</template>
+<script>
+import DataTable from 'primevue/datatable';
+import Column from 'primevue/column';
+import Loading from '@/common/Loading.vue';
+import InputText from 'primevue/inputtext';
+
+
+export default {
+  components: {
+    DataTable,
+    Column,
+    InputText
+  },
+  props: {
+    modalVisible: Boolean,
+    className: String,
+    class_type: String,
+    classDataprop: Array
+  },
+  data() {
+    return {
+      isSave: true,
+      modalVisibleView: false,
+      textareaValue_system: '',
+      isTextareaInput: false,
+      // custom_score_data: '1\t3\t2\n57\t86\t75\n62\t81\t93\n75\t77\t63\n75\t68\t83\n92\t93\t89',
+      // custom_score_data2: '76\n82\n86\n65\n77\n68',
+      custom_score_data: '',
+      custom_score_data2: '',
+      classData: [],
+      dataLoading: false,      
+    }
+  },
+  computed: {
+    TextareaInput_system() {
+      this.isSave = false;
+      if (this.isTextareaInput && this.textareaValue_system.trim() !== '') {
+        const data = this.textareaValue_system.split('\n').map((line) => line.split('\t'));
+        const lastLine = data[data.length - 1];
+        const isLastLineEmpty = lastLine.length === 1 && lastLine[0].trim() === '';
+
+        for (let i = 0; i < data.length - 1; i++) { // 迭代到倒數第二行
+          if (this.classData[i]) {
+            const [attendance, score, interactiveScore] = data[i];
+            this.classData[i].attendance = parseInt(attendance, 10) || 0;
+            this.classData[i].score = parseInt(score, 10) || 0;
+            this.classData[i].interactiveScore = parseInt(interactiveScore, 10) || 0;
+          }
+        }
+        // 更新最後一行的值,除非只包含換行符
+        if (!isLastLineEmpty && this.classData[data.length - 1]) {
+          const [attendance, score, interactiveScore] = data[data.length - 1];
+          this.classData[data.length - 1].attendance = parseInt(attendance, 10) || 0;
+          this.classData[data.length - 1].score = parseInt(score, 10) || 0;
+          this.classData[data.length - 1].interactiveScore = parseInt(interactiveScore, 10) || 0;
+        }
+        this.isTextareaInput = false;
+      }
+    },
+    TextareaInput_custom() {
+      this.isSave = false;
+      if (this.isTextareaInput && this.textareaValue_system.trim() !== '') {
+        const data = this.textareaValue_system.split('\n').map((line) => line.split('\t'));
+        const lastLine = data[data.length - 1];
+        const isLastLineEmpty = lastLine.length === 1 && lastLine[0].trim() === '';
+
+        for (let i = 0; i < data.length - 1; i++) { // 迭代到倒數第二行
+          if (this.classData[i]) {
+            const [score] = data[i];
+            this.classData[i].score = parseInt(score, 10) || 0;
+          }
+        }
+        // 更新最後一行的值,除非只包含換行符
+        if (!isLastLineEmpty && this.classData[data.length - 1]) {
+          const [score] = data[data.length - 1];
+          this.classData[data.length - 1].score = parseInt(score, 10) || 0;
+        }
+        this.isTextareaInput = false;
+      }
+    },
+    modalWidth() {
+      if (this.class_type === 'lessonrecord') {
+        return '900px';
+      } else if (this.class_type === 'activity') {
+        return '700px';
+      } else {
+        return '900px'; // 預設的 modal 寬度
+      }
+    },
+  },
+  mounted() {
+  },
+  methods: {
+    ok() {
+      if (!this.isSave) {
+        this.isSave = true;
+        //this.$Message.info('Clicked ok');      
+        this.textareaValue_system = '';
+        this.$emit("updateItemScore", this.classData);
+        this.$emit('closeModal');
+      } else {
+        this.$emit('closeModal');
+      }
+    },
+    cancel() {
+      this.dataLoading = true;
+
+      this.$emit('closeModal');
+      this.textareaValue_system = '';
+      this.isSave = true;
+     
+      this.dataLoading = false;
+    },
+    falseIsSave() {
+      this.isSave = false;
+    },
+    modelclick() {
+      //debugger;
+      console.log('modelclick');
+      this.modalVisibleView = true;
+    }
+  },
+  watch: {
+    modalVisible(newVal) {
+      //debugger;
+      this.modalVisibleView = newVal;
+    },
+    classDataprop(newVal) {
+      // const time = new Date();
+      // console.log("子視窗---classDataprop----S" + time);      
+      this.classData = JSON.parse(JSON.stringify(this.classDataprop));
+      this.custom_score_data = this.classData.map(item => `${item.attendance}\t${item.score}\t${item.interactiveScore}`).join('\n');
+      this.custom_score_data2 = this.classData.map(item => `${item.score}`).join('\n');
+
+      //console.log("子視窗---classDataprop----E" + time);         
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./DialogBox.less";
+</style>
+<style lang="less">
+.titleClassStyle {
+
+  .ivu-modal-header-inner {
+    font-size: 18px;
+    font-weight: bold;
+  }
+}
+
+thead tr th div {  
+  display: block !important;  
+}
+
+.tbthcolor{
+  color: #515a6e;
+  min-width: 120px;
+  color: rgb(45, 140, 240);
+  text-align: center; 
+  display: block;
+}
+
+</style>

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


+ 89 - 0
TEAMModelOS/ClientApp/src/view/mycourse/score/Score.vue

@@ -0,0 +1,89 @@
+<template>
+  <div class="score-container">
+    <div v-if="changePage == 'AllScore'">
+      <ScoreBody @changePage="changePagefun" @projectName="projectNamefun" :enter_tableInfo="tableInfo"
+        :paramsInfo="gradeParams" @tableInfo="tableInfofun" :grouplistId="grouplistId" :listType="listType"></ScoreBody>
+    </div>
+    <div v-else-if="changePage == 'AddProject'">
+      <AddProject  @changePage="changePagefun" :tableInfo="tableInfo"></AddProject>
+    </div>
+  </div>
+</template>
+<script>
+import ScoreBody from "./ScoreBody.vue"
+import AddProject from "./AddProject.vue"
+export default {
+  components: {
+    ScoreBody, AddProject
+  },
+  props: {
+    //收藏id,双向绑定
+    value: {
+      default: () => {
+        return []
+      },
+    },
+    gradeParams: {
+      type: Object,
+      default: () => {
+        return []
+      }
+    },
+    grouplistId: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    listType: {
+      type: String,
+      default: () => {
+        return {}
+      }
+    },
+  },
+  data() {
+    return {
+      filterExpire: false,
+      fIds: [],
+      changePage: "AllScore",
+      projectName: "",
+      tableInfo:{},
+    }
+  },
+  computed: {
+
+  },
+  created() {
+
+  },
+  methods: {
+    changePagefun(newValue) {
+      this.changePage = newValue;
+    },
+    projectNamefun(newValue) {
+      this.projectName = newValue;
+    },
+    tableInfofun(newValue) {
+      this.tableInfo = newValue;
+    }
+  },
+  watch: {
+    grouplistId: {
+      deep: true,
+      immediate: true,
+      handler(n, o) {
+        this.tableInfo ={};
+        this.changePage = "AllScore";//若在第二頁去,只要重新點選課程,一律跳回第一頁
+      }
+    }
+
+  }
+}
+</script>
+<style lang="less" scoped>
+@import "./Score.less";
+</style>
+<style lang="less">
+//.ivu-table.ivu-table-stripe .ivu-table-cell.demo-table-info-column
+</style>

+ 180 - 0
TEAMModelOS/ClientApp/src/view/mycourse/score/ScoreBody.less

@@ -0,0 +1,180 @@
+.record-container {
+    width: 100%;
+    height: ~"calc(100% - 50px)";
+}
+
+.text-size20{
+    font-size: 20px; 
+}
+
+// .custom-datatable::before{//奇數行的背景顏色f6f6f6
+//     background-color: #f6f6f6!important; 
+// }
+// .custom-datatable{//偶數行的背景顏色ffffff
+//     background-color: #c87878;
+// }
+
+.div-center{//水平置中
+    display: flex; 
+    justify-content: center; 
+    text-align:center;
+    width:100%;
+}
+.div-centerY{//垂直置中
+    display: flex; 
+    align-items: center;  
+    justify-content: center;
+}
+
+.table-none-background{    
+    background-color: 'white';
+    color: 'white';
+    border: '1px solid white';
+}
+.menu-list {
+    padding: 10px;
+    display: flex;
+    overflow-x: auto;
+    align-items: center;
+
+    .ivu-icon {
+        margin: 10px;
+    }
+
+    .ivu-card-body {
+        width: 160px !important;
+    }
+
+    .ivu-card {
+        background: #eee;
+        text-align: center;
+        overflow-wrap: break-word;
+        margin-right: 10px;
+        width: 160px;
+        flex: 0 0 160px;
+    }
+    .ivu-card:hover {
+        background: #ffffff;
+    }
+
+    .ivu-card.active{
+        background: #ffffff;
+        border-color:#dcdee2;
+        border-style:solid;
+    }
+}
+
+
+.rcd-item {
+    cursor: pointer;
+    display: flex;
+    border-bottom: 1px solid #e8eaec;
+    padding: 20px 30px 20px 15px;
+
+    &:hover .common-item-icon {
+        display: inline-block;
+    }
+
+    &:hover {
+        background: var(--active-item-start);
+    }
+}
+
+.body-list {
+    height: 100vh;
+    display: flex;
+    flex-direction: column;
+}
+
+.custom-table .ivu-table-cell {
+    padding-top: 0px;
+    /* 自定义上内边距 */
+    padding-bottom: 0px;
+    /* 自定义下内边距 */
+}
+
+
+
+.body-content {
+    padding: 15px;
+    flex-grow: 1;
+
+    .head {
+        display: flex;
+        align-items: center;
+        margin-bottom: 5px;
+
+        .list-name {
+            width: 250px;
+            color: #2d8cf0;
+            padding: 2px 5px;
+            border: 1px solid #e8eaec;
+        }       
+        .switch-location {
+            margin-left: auto; /* 使靠右方 */
+            margin-top: auto; /* 使自動靠下 */
+            display: flex;
+            align-items: center; //垂直置中
+        }
+
+        p {
+            margin: 0px 5px;
+            font-size: 6pt;
+        }
+    }
+
+    .body {
+
+        //height: 500px;
+        //overflow-y: auto;
+        .body-center {
+            align-items: center;
+            display: flex;
+
+            .table-container {
+                width: 100%;
+            }
+
+        }
+
+        .body-showIcon {
+            display: flex;
+            flex-direction: column;
+            margin-top: 40px;
+
+            .ivu-icon {
+                margin: 30px 10px;
+            }
+        }
+
+        .ivu-icon {
+            margin: 10px;
+        }
+    }
+    .save-info-ok{
+        text-align:right;
+        display: flex;
+        align-items: flex-end;
+        color: #808695;
+    }
+    .save-info-erro{
+        text-align:right;
+        display: flex;
+        align-items: flex-end;
+        color: #ed4014;
+    }
+    .foot {
+        display: flex;
+        justify-content: space-between;
+        padding: 5px 0px;
+        
+        .button-group {
+            margin-left: auto;
+            display: flex;
+        }
+
+        .button-space {
+            margin-left: 5px;
+        }
+    }
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2171 - 0
TEAMModelOS/ClientApp/src/view/mycourse/score/ScoreBody.vue


+ 23 - 0
TEAMModelOS/ClientApp/src/view/mycourse/score/ScoreIndex.less

@@ -0,0 +1,23 @@
+.menu-list {
+    padding: 10px;
+    display: flex;
+    overflow-x: auto;
+    align-items: center;
+
+    .ivu-icon {
+        margin: 10px;
+    }
+
+    .ivu-card-body {
+        width: 160px !important;
+    }
+
+    .ivu-card {
+        background: #eee;
+        text-align: center;
+        overflow-wrap: break-word;
+        margin-right: 10px;
+        width: 160px;
+        flex: 0 0 160px;
+    }
+}

+ 44 - 0
TEAMModelOS/ClientApp/src/view/mycourse/score/ScoreIndex.vue

@@ -0,0 +1,44 @@
+<template>
+  <div class="score-container">
+    <div class="menu-list">
+      <Icon type="md-add-circle" :size="25" @click="addNewScoreFile" />
+      <Card :bordered="false" v-for="n in 5">
+        <p><b>2023年上學期期中成績</b></p>
+        <!-- <p>Mid-term results of last semester</p> -->
+      </Card>
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  components: {
+  },
+  props: {
+    //收藏id,双向绑定
+    value: {
+      default: () => {
+        return []
+      },
+    },
+  },
+  data() {
+    return {
+      filterExpire: false,
+      fIds: [],
+      list: {
+        name: '2023年上學期期中成績2',
+      },     
+    };
+  },
+  methods: {
+    addNewScoreFile() {
+      // 在這裡處理點擊事件的邏輯
+      console.log("Icon 被點擊了!");
+    },
+  },
+}
+</script>
+<style lang="less" scoped>
+@import "./ScoreIndex.less";
+</style>
+<style lang="less"></style>