Bläddra i källkod

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

liqk 4 år sedan
förälder
incheckning
12263b81ed

+ 28 - 0
TEAMModelOS.SDK/DI/AzureStorage/AzureStorageBlobExtensions.cs

@@ -11,6 +11,7 @@ using System.IO;
 using Azure.Storage.Blobs.Specialized;
 using System.Collections.Generic;
 using System.Linq;
+using System.Text;
 
 namespace TEAMModelOS.SDK.DI
 {
@@ -37,6 +38,33 @@ namespace TEAMModelOS.SDK.DI
                 return size;
             }
         }
+        /// <summary>
+        /// 取得指定前置詞的 Blob 名稱的總大小(Bytes),例如指定目錄名稱為前置詞
+        /// </summary>      
+        /// <param name="prefix">篩選開頭名稱,Null代表容器總大小</param>
+        /// <returns>總大小(Bytes),如果為Null代表查無前置詞或者發生錯誤</returns>
+        public static async Task<long?> GetBlobsSize(this BlobContainerClient client, List<string>urls)
+        {
+            long? size = 0;
+            try
+            {
+                foreach (var url in urls) {
+                   var eurl = "/" + System.Web.HttpUtility.UrlDecode(url.ToString(), Encoding.UTF8);
+                    client.GetBlobClient(eurl);
+                    if (client.Exists()) {
+                        await foreach (var item in client.GetBlobsAsync(BlobTraits.None, BlobStates.None))
+                        {
+                            size += item.Properties.ContentLength;
+                        }
+                    }
+                }
+                return size;
+            }
+            catch
+            {
+                return size;
+            }
+        }
         /// <summary>        
         /// 批量刪除Blobs
         /// </summary>      

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 8 - 7
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.css


+ 103 - 56
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue

@@ -5,8 +5,8 @@
                 <svg-icon icon-class="handonHint" class="warm-icon" />
                 <span class="warm-hint">{{ $t("studentWeb.exam.timeoutHint") }}</span>
             </div>
-            <span v-show="$store.getters.getItemTitle.progress != 'finish' && testState == 1" @click="showTest" style="color: #03966a;width: 100%;cursor: pointer;font-size:18px;font-weight: 800;text-align: center">前往作答</span>
-            <h4 v-show='testState == 2'>成绩尚未结算</h4>
+            <span v-show="$store.getters.getItemTitle.progress != 'finish' && testState == 1" @click="showTest" style="color: #03966a;width: 100%;cursor: pointer;font-size:18px;font-weight: 800;text-align: center">{{$t("studentWeb.exam.report.anwser")}}</span>
+            <h4 v-show='testState == 2'>{{$t("studentWeb.exam.report.noRes")}}</h4>
             <Row :gutter="20" v-if='testState == 3'>
                 <i-col :xs="24" :sm="24" :md="24" :lg="12">
                     <Row :gutter="20">
@@ -39,7 +39,7 @@
                         </i-col>
                         <i-col :xs="24" :sm="24" :md="12" :lg="12">
                             <Card class="score-card">
-                                <p class="card-title">得分题目数</p>
+                                <p class="card-title">{{$t("studentWeb.exam.report.getScore")}}</p>
                                 <div class="card-content">
                                     <span class="myscore">{{rightAns.right}}</span> / {{rightAns.all}}
                                 </div>
@@ -70,22 +70,22 @@
         <div class="QAsheet" v-if='testState != 1'>
             <div class='title-rect-group '>
                 <div class="title-rect" />
-                <h2 class="title-rect-name"  @click="checkedAnsFilter">评测作答回顾</h2>
+                <h2 class="title-rect-name" @click="checkedAnsFilter">{{$t("studentWeb.exam.report.answerBack")}}</h2>
             </div>
             <div class="filterBtn">
                 <label class="checkAns">
                     <input type="checkbox" value="right" v-model="checkedAns" />
-                    <span>答对: {{rightAns.right}}</span>
+                    <span>{{$t("studentWeb.exam.report.right")}}: {{rightAns.right}}</span>
                     <div class="rightBtn"></div>
                 </label>
                 <label class="checkAns">
                     <input type="checkbox" value="wrong" v-model="checkedAns" />
-                    <span>答错: {{ examInfo.stuScore.length - rightAns.right - rightAns.noAns}}</span>
+                    <span>{{$t("studentWeb.exam.report.wrong")}}: {{ examInfo.stuScore.length - rightAns.right - rightAns.noAns}}</span>
                     <div class="wrongBtn"></div>
                 </label>
                 <label class="checkAns" v-show=" rightAns.noAns != 0 ">
                     <input type="checkbox" value="noAns" v-model="checkedAns" />
-                    <span>未评分: {{ rightAns.noAns}}</span>
+                    <span>{{$t("studentWeb.exam.report.noScore")}}: {{ rightAns.noAns}}</span>
                     <div class="noAnsBtn"></div>
                 </label>
             </div>
@@ -136,7 +136,7 @@
                             <i-col :xs="2" :sm="2" :md="1" :lg="1">
                                 <div class="qScore">
                                     <span v-if="examInfo.stuScore[index] != -1">{{examInfo.stuScore[index]}}/{{question.score}}</span>
-                                    <span v-if="examInfo.stuScore[index] == -1">未评分</span>
+                                    <span v-if="examInfo.stuScore[index] == -1">{{$t("studentWeb.exam.report.noScore")}}</span>
                                 </div>
                             </i-col>
                         </Row>
@@ -146,24 +146,68 @@
                                     <div v-for="(item,index) in question.option" style="display:flex;margin-top:5px;">
                                         ({{item.code}})<div style="margin-left:10px" v-html="item.value"></div>
                                     </div>
-                                    <div class="TitleRec1"><span style="margin:5px;color:#1472c7">作答结果:</span></div>
+                                    <div class="TitleRec1"><span style="margin:5px;color:#1472c7">{{$t("studentWeb.exam.report.ansRes")}}:</span></div>
                                     <br />
-                                    <div v-if="ansData[index]" style="margin-left:10px" v-html="ansData[index].length > 0 ? ansData[index][0] : '未作答'">32131{{ansData[index][0]}}</div>
+                                    <div v-if="ansData[index]" style="margin-left:10px" v-html="ansData[index].length > 0 ? ansData[index][0] : $t('studentWeb.exam.report.noScore')"></div>
                                 </div>
                             </div>
                             <!--<br />-->
                             <div class="rightAnalys">
-                                <div class="TitleRec2"><span style="margin-left:5px">参考答案:</span></div>
+                                <div class="TitleRec2"><span style="margin-left:5px">{{$t("studentWeb.exam.report.testAns")}}:</span></div>
                                 <br />
                                 <div style="display:flex">
                                     <div v-for="(item,iundex) in question.answer" v-html="item" style="margin-left:10px;"></div>
                                 </div>
-                                <div class="TitleRec2"><span style="margin-left:5px">解析:</span></div>
+                                <div class="TitleRec2"><span style="margin-left:5px">{{$t("studentWeb.exam.report.testAnalyse")}}:</span></div>
                                 <br />
-                                <div style="margin-left:10px;" v-html="question.explain != '' ?  question.explain : '暂无解析' "></div>  
-                                <div class="TitleRec2"><span style="margin-left:5px">补救资源:</span></div>
+                                <div style="margin-left:10px;" v-html="question.explain != '' ?  question.explain : $t('studentWeb.exam.report.noAnslyse') "></div>  
+                                <div v-show="examInfo.stuScore[index] != -1 && examInfo.stuScore[index] != question.score" class="TitleRec2"><span style="margin-left:5px">{{$t("studentWeb.exam.report.repairSource")}}:</span></div>
                                 <br />
-                                <div style="margin-left:10px;" v-html="question.explain != '' ?  question.explain : '暂无解析' "></div>
+                                <div  style="margin-left:10px;display:flex" v-show="examInfo.stuScore[index] != -1 && examInfo.stuScore[index] != question.score">
+                                    <div v-if="question.repair" class="repair-box">
+                                        <!--<Collapse style="width:85%" accordion @on-change="getSource(question.repair,question)">
+                                            <Panel name="1">
+                                                链接资源
+                                                <p slot="content">
+                                                    <List border size="small">
+                                                        <ListItem v-for="(item,normalIndex) in repairSource.normal" :key="normalIndex">
+                                                            <span style="margin-right:10px;" v-show="item.blobUrl">
+                                                                <Icon color="#0066FF" custom="iconfont icon-share_link" size="20" />
+                                                            </span><a>{{item.blobUrl}}</a>
+                                                            <span v-show="item.blobUrl == undefined">暂无资源</span>
+                                                        </ListItem>
+                                                        <ListItem v-show="repairSource.normal.length == 0">
+                                                            <span>暂无资源</span>
+                                                        </ListItem>
+                                                    </List>
+                                        
+                                                </p>
+                                            </Panel>
+                                            <Panel name="2">
+                                                文件资源
+                                                <p slot="content">
+                                                    <List border size="small">
+                                                        <ListItem v-for="(item,fileIndex) in repairSource.file" :key="fileIndex">
+                                                                <span style="margin-right:10px;">
+                                                                    <Icon v-if="item.fileType == 'zip'" custom="iconfont icon-zip" size="20" /> 
+                                                                    <Icon v-else-if="item.fileType == 'zip'" color="#8199AF" custom="iconfont icon-zip" size="20" /> 
+                                                                    <Icon v-else-if="item.fileType == 'pdf'" color="#FF6464" custom="iconfont icon-pdf" size="20" /> 
+                                                                    <Icon v-else-if="item.fileType == 'ppt'|| item.fileType == 'pptx'" color="#FF8976" custom="iconfont icon-ppt" size="20" /> 
+                                                                    <Icon v-else-if="item.fileType == 'mp3'" color="#FF5562" custom="iconfont icon-mp3" size="20" /> 
+                                                                    <Icon v-else-if="item.fileType == 'mp4'" color="#8E4C9E" custom="iconfont icon-video1" size="20" /> 
+                                                                    <Icon v-else-if="item.fileType == 'zip'" custom="iconfont icon-video1" size="20" /> 
+                                                                    <Icon v-else-if="item.fileType == 'doc'||item.fileType =='docx'" color="#6CCBFF" custom="iconfont icon-word" size="20" /> 
+                                                                    <Icon v-else-if="item.fileType == 'csv'||item.fileType =='xlsx'||item.fileType =='xls'" color="#25C273" custom="iconfont icon-xlsx" size="20" /> 
+                                                                    <Icon v-else-if="item.fileType == 'jpg'||item.fileType =='png'||item.fileType =='jpeg'" color="#30D1CA" custom="iconfont icon-jpg" size="20" /> 
+                                                                    <Icon v-else custom="iconfont icon-V" size="20" /> 
+                                                                </span><a>{{item.name}}</a>
+                                                        </ListItem>
+                                                    </List>
+                                                </p>
+                                            </Panel>
+                                        </Collapse>-->
+                                    </div>
+                                </div>
                             </div>
                         </div>
                     </div>
@@ -204,7 +248,6 @@
                 isLoading: true,
                 opacity: 0.6,
                 //loading畫面
-                currentReportSubject: "國文",
                 closeAnsDetail: false,
                 RandomComment: Random.paragraph(1, 2),
                 RandomKeypoint: Random.paragraph(1, 3),
@@ -246,7 +289,12 @@
                     },
                 ],
                 paperData: [],
-                ansData:[]
+                ansData: [],
+                repairSource: {
+                    normal: [],
+                    file: []
+                },
+                repairData:[]
             };
         },
         mounted() {
@@ -254,6 +302,35 @@
             this.testJudge()
         },
         methods: {
+            getSource(data, info) {
+                console.log(info)
+                this.repairSource = {
+                    normal: [],
+                    file: []
+                }
+                let source = {
+                    normal: [],
+                    file: []
+                }
+                for (let item of data) {
+                    if (item.type == 'normal') {
+                        source.normal.push(item)
+                    } else if (item.blobUrl) {
+                        let code = item.blobUrl.split('/')
+                        let data = code[code.length - 1].split('.')
+                        item.name = code[code.length-1]
+                        item.file = code[code.length - 2]
+                        item.fileType = data[data.length -1]
+                        console.log(code)
+                        source.file.push(item)
+                    }
+                }
+                console.log(source)
+                console.log(source.normal.dfd)
+                this.repairSource = source
+                //let code = data.blobUrl.split('/')
+                //console.log(code)
+            },
             showTest() {
                 if (this.examInfo.subject !== undefined) {
                     this.$store.commit("ToggleLessonTestPopWithSubject", this.examInfo)
@@ -345,13 +422,6 @@
             getCurrentLang() {
                 return localStorage.getItem('lang');
             },
-
-            transSubjecttoEn(type) {
-                if (type == "國文") return "Chinese";
-                else if (type == "英文") return "English";
-                else if (type == "數學") return "Math";
-                else if (type == "綜合學科") return "Comprehensive";
-            },
             RandomNum() {
                 return Random.integer(70, 96)
             },
@@ -368,10 +438,6 @@
             closeDetail() {
                 this.closeAnsDetail = !this.closeAnsDetail;
             },
-            changeListSubject(subject) {
-                this.currentReportSubject = subject;
-                this.doAjax();
-            },
             ansRightSum: function () {
                 var ansRightSum = [0, 0, 0];
                 for (var i = 0; i < 10; i++) {
@@ -402,32 +468,6 @@
                 else return false;
 
             },
-            transQtypetoEn(Qtype) {
-                if (localStorage.getItem('lang') == 'en') {
-                    if (Qtype == "單選") {
-                        return "Single"
-                    } else if (Qtype == "多選") {
-                        return "Multi";
-                    }
-                    else if (Qtype == "判斷") {
-                        return "True/False"
-                    }
-                    else if (Qtype == "填充") {
-                        return "Fill in the blank"
-                    }
-                    else return
-                }
-                else return Qtype
-            },
-            doAjax() {
-                this.isLoading = true;
-
-                // simulate AJAX
-                setTimeout(() => {
-                    this.forceRerender();
-                    this.isLoading = false;
-                }, 3000);
-            },
         },
         computed: {
             testScore() {
@@ -784,11 +824,18 @@
         top: -70%;
         right: -40%;
         font-size: 20px;
-        color: rgba(0, 0, 0, 0.5)
+        color: rgba(0, 0, 0, 0.5);
     }
 
     .vld-overlay {
         outline: none;
-        border: none
+        border: none;
     }
+    .repair-box{
+        width:100%;
+    }
+        .repair-box /deep/ .ivu-list-container{
+            max-height:300px;
+            overflow:scroll;
+        }
 </style>

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

@@ -263,6 +263,20 @@ export default {
             "queNo": "Title:",
             "myAns": "My answer:"
         },
+        "report": {
+            "anwser": "Go to answer",
+            "noRes": "The results have not yet been settled",
+            "getScore": "Number of score questions",
+            "answerBack": "Review of the review and answer",
+            "right": "Right",
+            "wrong": "Wrong ",
+            "noScore": "Not Review",
+            "ansRes": "Response result",
+            "testAns": "Reference Answer",
+            "testAnalyse": "Analyze",
+            "repairSource": "Repair Source",
+            "noAnalyse": "No analysis"
+        },
         "timeoutHint": "The evaluation activity time has ended. Overtime will be calculated as 0 points, or wait for the teacher to open the make-up exam.",
         "contentPage": "Review Content",
         "scorePage": "Score Report",

+ 38 - 2
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/settings.js

@@ -1,5 +1,41 @@
 export default {
     setting_title1: '学校管理',
-	setting_title2: '一般设置'
-
+	setting_title2: '一般设置',
+	schoolList:'已添加或申请学校',
+	langSetting:'网站语言设定',
+	langTips:'请选择网站要用来显示选单、互动页面以及通知信息的语言',
+	langCheck:'使用浏览器语系展示',
+	themeSetting:'网站色彩模式',
+	themeTips:'请选择网站显示的色彩模式,以便提供最佳的用户体验',
+	menuSetting:'菜单显示设置',
+	menuTips:'选择左侧Menu在网站载入时的预设显示模式',
+	menuOpen:'预设展开显示',
+	menuClose:'预设关闭显示',
+	defaultSchool:'默认学校',
+	curSchool:'当前学校',
+	courseNum:'课程数',
+	activityNum:'活动数',
+	joinStatus:'提出加入请求',
+	requestStatus:'送出添加邀请',
+	goSchool:'前往学校',
+	agreeJoin:'同意加入',
+	cancelAdd:'取消添加',
+	requestJoin:'申请加入',
+	inputSearch:'输入要搜索的学校名称',
+	modalTip1:'注意',
+	modalTip2:'此举动将使您离开当前学校的 IES5 站台,并前往',
+	modalTip3:'当前页面未保存的资料将会丢失,是否同意此操作?',
+	columnName:'学校名称',
+	columnArea:'地区',
+	columnId:'校代码',
+	columnTool:'操作',
+	modalTip4:'温馨提示',
+	modalTip5:'确认申请加入',
+	submitSucTips:'提交成功',
+	submitFailTips:'操作失败',
+	joinSucTips:'加入成功!',
+	status1:'已加入',
+	status2:'收到邀请',
+	status3:'申请中',
+	
 }

+ 14 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/studentWeb.js

@@ -265,6 +265,20 @@ export default {
             "queNo": "题目:",
             "myAns":"我的作答:"
         },
+        "report": {
+            "anwser": "前往作答",
+            "noRes": "成绩尚未结算",
+            "getScore": "得分题目数",
+            "answerBack": "评测作答回顾",
+            "right": "答对",
+            "wrong": "答错",
+            "noScore": "未评分",
+            "ansRes": "作答结果",
+            "testAns": "参考答案",
+            "testAnalyse": "解析",
+            "repairSource": "补救资源",
+            "noAnalyse":"暂无解析"
+        },
         "timeoutHint": "评量活动时间已结束,逾时将以0分计算,或等待教师开放补考。",
         "contentPage": "评量内容",
         "scorePage": "成绩报告",

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

@@ -1,5 +1,40 @@
 export default {
-    setting_title1: '學校管理',
-	setting_title2: '一般設置'
-
+	setting_title1: '學校管理',
+	setting_title2: '一般設定',
+	schoolList: '已添加或申請學校',
+	langSetting: '網站語言設定',
+	langTips: '請選擇網站要用來顯示選單、互動頁面以及通知資訊的語言',
+	langCheck: '使用瀏覽器語系展示',
+	themeSetting: '網站色彩模式',
+	themeTips: '請選擇網站顯示的色彩模式,以便提供最佳的用戶體驗',
+	menuSetting: '選單顯示設定',
+	menuTips: '選擇左側Menu在網站載入時的預設顯示模式',
+	menuOpen: '預設展開顯示',
+	menuClose: '預設關閉顯示',
+	defaultSchool: '默認學校',
+	curSchool: '當前學校',
+	courseNum: '課程數',
+	activityNum: '活動數',
+	joinStatus: '提出加入請求',
+	requestStatus: '送出添加邀請',
+	goSchool: '前往學校',
+	agreeJoin: '同意加入',
+	cancelAdd: '取消添加',
+	requestJoin: '申請加入',
+	inputSearch: '輸入要蒐索的學校名稱',
+	modalTip1: '注意',
+	modalTip2: '此舉動將使您離開當前學校的IES5站臺,並前往',
+	modalTip3: '當前頁面未保存的資料將會遺失,是否同意此操作?',
+	columnName: '學校名稱',
+	columnArea: '地區',
+	columnId: '校程式碼',
+	columnTool: '操作',
+	modalTip4: '溫馨提示',
+	modalTip5: '確認申請加入',
+	submitSucTips: '提交成功',
+	submitFailTips: '操作失敗',
+	joinSucTips: '加入成功!',
+	status1: '已加入',
+	status2: '收到邀請',
+	status3: '申請中',
 }

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

@@ -263,6 +263,20 @@ export default {
             "queNo": "題目:",
             "myAns": "我的作答:"
         },
+        "report": {
+            "anwser": "前往作答",
+            "noRes": "成績尚未結算",
+            "getScore": "得分題目數",
+            "answerBack": "評測作答回顧",
+            "right": "答對",
+            "wrong": "答錯",
+            "noScore": "未評分",
+            "ansRes": "作答結果",
+            "testAns": "參考答案",
+            "testAnalyse": "解析",
+            "repairSource": "補救資源",
+            "noAnalyse": "暫無解析"
+        },
         "timeoutHint": "評量活動時間已結束,逾時將以0分計算,或等待教師開放補考。",
         "contentPage": "評量內容",
         "scorePage": "成績報告",

+ 5 - 8
TEAMModelOS/ClientApp/src/view/evaluation/components/BasePointPie.vue

@@ -78,15 +78,12 @@
 					tempArr.push(i)
 				}
 			})
-			let typeList = this._.groupBy(tempArr, 'points')
-			console.log(typeList)
+			let typeList = this._.groupBy(tempArr, 'knowledge')
 			for (let key in typeList) {
-				if (key !== ''){
-					arr.push({
-						value: typeList[key].length,
-						name: key
-					})
-				}
+				arr.push({
+					value: typeList[key].length,
+					name: key === 'undefined' || !key ?  '未绑定知识点' : key
+				})
 			}
 			this.drawLine(arr)
 		},

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

@@ -274,7 +274,7 @@
 							})
 						}
 						// 如果导入的是客观题 则需要检测答案与选项是否为空
-						if (objectiveTypes.includes(i.type) && (!i.question.replace(/\s*/g, "") || !i.option.length || !i.answer.length)) {
+						if (objectiveTypes.includes(i.type) && (!i.question.replace(/\s*/g, "") || !i.option.length || !i.answer.length || !i.option || !i.answer)) {
 							this.errorList.push(i)
 						}
 					}

+ 9 - 11
TEAMModelOS/ClientApp/src/view/settings/Index.vue

@@ -8,32 +8,32 @@
         <div class="settings-body">
             <div class="normal-settings" v-if="activeTab === '0'">
                 <div class="normal-settings-item">
-                    <span class="item-title">网站语言设定</span>
-                    <span class="item-description">请选择网站要用来显示选单、互动页面以及通知信息的语言</span>
+                    <span class="item-title">{{ $t('settings.langSetting')}}</span>
+                    <span class="item-description">{{ $t('settings.langTips')}}</span>
                     <span class="item-content">
                         <Select v-model="cloudSetting.curLang" style="width:200px" @on-change="onSelectLang">
                             <Option value="zh-cn">中文(简体)</Option>
                             <Option value="zh-tw">中文(繁体)</Option>
                             <Option value="en-us">English</Option>
                         </Select>
-                        <Checkbox v-model="cloudSetting.isSystemLang" @on-change="onMenuStatusChange">使用您作业系统的语系来展示</Checkbox>
+                        <Checkbox v-model="cloudSetting.isSystemLang" @on-change="onMenuStatusChange">{{ $t('settings.langCheck')}}</Checkbox>
                     </span>
                 </div>
                 <div class="normal-settings-item">
-                    <span class="item-title">网站色彩模式</span>
-                    <span class="item-description">请选择网站显示的色彩模式,以便提供最佳的用户体验</span>
+                    <span class="item-title">{{ $t('settings.themeSetting')}}</span>
+                    <span class="item-description">{{ $t('settings.themeTips')}}</span>
                     <span class="item-content">
                         <span :class="['color-item',cloudSetting.curTheme === 'dark' ?  'color-item-active' : '']" @click="onTips('dark')"></span>
                         <span :class="['color-item',cloudSetting.curTheme === 'light' ?  'color-item-active' : '']" @click="onTips('light')"></span>
                     </span>
                 </div>
                 <div class="normal-settings-item">
-                    <span class="item-title">菜单显示设置</span>
-                    <span class="item-description">选择左侧Menu在网站载入时的预设显示模式</span>
+                    <span class="item-title">{{ $t('settings.menuSetting')}}</span>
+                    <span class="item-description">{{ $t('settings.menuTips')}}</span>
                     <span class="item-content">
                         <RadioGroup v-model="cloudSetting.menuStatus" @on-change="onMenuStatusChange">
-                            <Radio label="open">预设展开显示</Radio>
-                            <Radio label="close">预设关闭显示</Radio>
+                            <Radio label="open">{{ $t('settings.menuOpen')}}</Radio>
+                            <Radio label="close">{{ $t('settings.menuClose')}}</Radio>
                         </RadioGroup>
                     </span>
                 </div>
@@ -139,8 +139,6 @@
                 this.$Modal.confirm({
                     title: '提示',
                     content: '设置保存成功,刷新后即可生效,是否前往?',
-                    okText: '确认',
-                    cancelText: '取消',
                     onOk: () => {
                         localStorage.setItem('cloudSetting', JSON.stringify(this.cloudSetting))
                         location.reload()

+ 31 - 35
TEAMModelOS/ClientApp/src/view/settings/SchoolMgmt.vue

@@ -3,7 +3,7 @@
 		<Loading v-show="isLoading"></Loading>
 		<div class="school-container-left">
 			<div class="school-container-header">
-				<span>已添加或申请学校</span>
+				<span>{{ $t('settings.schoolList')}}</span>
 			</div>
 			<vuescroll>
 				<div class="school-list-wrap">
@@ -16,33 +16,33 @@
 							<span class="school-item-name">
 								<span>{{ item.name }}</span>
 								<span class="school-item-status" :style='{ background:bgFilter(item.status) }'>{{ statusFilter(item.status) }}</span>
-								<span class="school-item-status" style="background-color: #008352;" v-show="item.schoolId === teacherInfo.defaultschool">默认学校</span>
-								<span class="school-item-status" style="background-color: #f59a2a;" v-show="item.schoolId === curSchool">当前学校</span>
+								<span class="school-item-status" style="background-color: #008352;" v-show="item.schoolId === teacherInfo.defaultschool">{{ $t('settings.defaultSchool')}}</span>
+								<span class="school-item-status" style="background-color: #f59a2a;" v-show="item.schoolId === curSchool">{{ $t('settings.curSchool')}}</span>
 							</span>
 							<span class="school-item-code">{{ item.schoolId  }}</span>
 							<span class="school-item-nums" v-if="item.status === 'join'">
 								<span>
 									<Icon type="md-bookmarks" />
-									<span>课程数</span>
+									<span>{{ $t('settings.courseNum')}}</span>
 									<span style="margin-left: 10px;">{{ item.course }}</span>
 								</span>
 								<span style="margin-left: 20px;">
 									<Icon type="md-star" />
-									<span>活动数</span>
+									<span>{{ $t('settings.activityNum')}}</span>
 									<span style="margin-left: 10px;">{{ item.activity }}</span>
 								</span>
 							</span>
 							<span class="school-item-nums" v-if="item.status === 'request'">
-								于 2020-08-02 提出加入请求
+								于 2020-08-02 {{ $t('settings.joinStatus')}}
 							</span>
 							<span class="school-item-nums" v-if="item.status === 'invite'">
-								于 2020-08-02 送出添加邀请
+								于 2020-08-02 {{ $t('settings.requestStatus')}}
 							</span>
 							<span class="school-item-role">{{ item.role }}</span>
 							<span class="school-item-btn" v-if="item.status === 'join' && item.schoolId !== curSchool" @click="onGoSchool(item)">
 								<span>
 									<Icon type="md-swap" style="transform: rotate(90deg);" />
-									<span>前往学校</span>
+									<span>{{ $t('settings.goSchool')}}</span>
 								</span>
 							</span>
 <!-- 							<span class="school-item-btn" style="background: rgb(202,54,54);" v-if="item.status === 'request'">
@@ -54,13 +54,13 @@
 							<span class="school-item-btn" style="background: #1CC0F3;right: 140px;" v-if="item.status === 'invite'" @click="onConfirmJoin(item)">
 								<span>
 									<Icon type="md-checkmark" />
-									<span>同意加入</span>
+									<span>{{ $t('settings.agreeJoin')}}</span>
 								</span>
 							</span>
 							<span class="school-item-btn" style="background: rgb(202,54,54);" v-if="item.status === 'invite'">
 								<span>
 									<Icon type="md-close" />
-									<span>取消添加</span>
+									<span>{{ $t('settings.cancelAdd')}}</span>
 								</span>
 							</span>
 						</div>
@@ -70,9 +70,9 @@
 		</div>
 		<div class="school-container-right">
 			<div class="school-container-header">
-				<span>申请加入学校</span>
+				<span>{{ $t('settings.requestJoin')}}</span>
 				<div>
-					<Input placeholder="输入要搜索的学校名称" @on-change="onSearchList" v-model="schoolListSearch">
+					<Input :placeholder="$t('settings.inputSearch')" @on-change="onSearchList" v-model="schoolListSearch">
 					<Icon type="ios-search" slot="prefix" />
 					</Input>
 				</div>
@@ -83,11 +83,11 @@
 			</div>
 		</div>
 		<Modal v-model="goSchoolModal" class-name="go-school-modal" footer-hide>
-			<p>注意</p>
-			<p>此举动将使您离开当前学校的 IES5 站台,并前往</p>
+			<p>{{ $t('settings.modalTip1')}}</p>
+			<p>{{ $t('settings.modalTip2')}}</p>
 			<p>{{ curSchoolItem ? curSchoolItem.name : '' }}</p>
-			<p>当前页面未保存的资料将会丢失,是否同意此操作?</p>
-			<Button @click="onChangeSchool">确定</Button>
+			<p>{{ $t('settings.modalTip3')}}</p>
+			<Button @click="onChangeSchool">{{ $t('evaluation.confirm')}}</Button>
 		</Modal>
 
 	</div>
@@ -117,24 +117,24 @@
 				schoolList: [],
 				originSchoolList:[],
 				schoolColumns: [{
-						title: '学校名称',
+						title: this.$t('settings.columnName'),
 						key: 'name',
 						width: 500,
 					},
 					{
-						title: '地区',
+						title: this.$t('settings.columnArea'),
 						render: (h, params) => {
 							return h('span', params.row.region + '-' +  params.row.province+ '-' + params.row.city);
 						}
 					},
 					{
-						title: '校代码',
+						title: this.$t('settings.columnId'),
 						key: 'id'
 					},
 					{
-						title: '操作',
+						title: this.$t('settings.columnTool'),
 						render: (h, params) => {
-							return this.tbStatusFilter(params.row.id) === '申请加入' ? 
+							return this.tbStatusFilter(params.row.id) === this.$t('settings.requestJoin') ? 
 							h('div', [
 								h('Button', {
 									props: {
@@ -243,10 +243,8 @@
 			/* 申请加入学校 */
 			onJoinSchool(item){
 				this.$Modal.confirm({
-				    title: '温馨提示',
-				    content: '<p>确认申请加入' + item.name + ' ?</p>',
-				    okText: '确认',
-				    cancelText: '取消',
+				    title: this.$t('settings.modalTip4'),
+				    content: this.$t('settings.modalTip5') + item.name + ' ?',
 				    onOk: () => {
 						this.$api.schoolSetting.joinSchool({
 							grant_type:'request',
@@ -256,13 +254,13 @@
 							(res) => {
 								console.log(res)
 								if (!res.error) {
-									this.$Message.success("提交成功!")
+									this.$Message.success(this.$t('settings.submitSucTips'))
 									this.initTeacherInfo()
 									this.getAllShoolList()
 								}
 							},
 							(err) => {
-								this.$Message.error("操作失败!")
+								this.$Message.error(this.$t('settings.submitFailTips'))
 							}
 						)
 				    },
@@ -275,10 +273,8 @@
 			onConfirmJoin(item){
 				console.log(item)
 				this.$Modal.confirm({
-				    title: '温馨提示',
-				    content: '<p>确认加入' + item.name + ' ?</p>',
-				    okText: '确认',
-				    cancelText: '取消',
+				    title: this.$t('settings.modalTip4'),
+				    content: this.$t('settings.modalTip5') + item.name + ' ?',
 				    onOk: () => {
 						this.$api.schoolSetting.joinSchool({
 							grant_type:'join',
@@ -288,7 +284,7 @@
 							async (res) => {
 								console.log(res)
 								if (!res.error) {
-									this.$Message.success("加入成功!")
+									this.$Message.success(this.$t('settings.joinSucTips'))
 									// 如果之前用户没有加入任何学校
 									if(this.mySchoolList.length && this.mySchoolList.filter(i => i.status === 'join').length === 0){
 										let teacherInfo = await this.getTeacherInfo()
@@ -306,7 +302,7 @@
 								}
 							},
 							(err) => {
-								this.$Message.error("操作失败!")
+								this.$Message.error(this.$t('settings.submitFailTips'))
 							}
 						)
 				    },
@@ -340,7 +336,7 @@
 		computed: {
 			statusFilter() { 
 				return status => {
-					return status === 'join' ? '已加入' : status === 'invite' ? '受邀' : '申请中'
+					return status === 'join' ? this.$t('settings.status1') : status === 'invite' ? this.$t('settings.status2') : this.$t('settings.status3')
 				}
 			},
 			bgFilter() {
@@ -354,7 +350,7 @@
 					let isJoin =  this.mySchoolList.filter(i => i.status === 'join').map(j => j.schoolId).indexOf(id)  > -1 
 					let isInvite =  this.mySchoolList.filter(i => i.status === 'invite').map(j => j.schoolId).indexOf(id)  > -1 
 					let isRequest =  this.mySchoolList.filter(i => i.status === 'request').map(j => j.schoolId).indexOf(id)  > -1 
-					return isJoin ? '已加入' : isInvite ? '收到邀请' : isRequest ? '申请中' : '申请加入'
+					return isJoin ? this.$t('settings.status1') : isInvite ? this.$t('settings.status2') : isRequest ? this.$t('settings.status3') : this.$t('settings.requestJoin')
 				}
 			},
 			curSchool(){

+ 71 - 5
TEAMModelOS/Controllers/Analysis/AnalysisController.cs

@@ -1709,6 +1709,7 @@ namespace TEAMModelOS.Controllers.Analysis
             {
                 List<Dictionary<string, object>> averageMap = new List<Dictionary<string, object>>();
                 List<Dictionary<string, object>> averageTotal = new List<Dictionary<string, object>>();
+                List<List<double>> classAllAverage = new List<List<double>>();
                 var client = _azureCosmos.GetCosmosClient();
                 ExamInfo info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"Exam-{code}"));
                 List<ExamResult> examResults = new List<ExamResult>();
@@ -1717,28 +1718,93 @@ namespace TEAMModelOS.Controllers.Analysis
                 {
                     examResults.Add(item);
                 }
+                int indexClass = 0;
+                HashSet<string> cla = new HashSet<string>();
+                HashSet<string> stu = new HashSet<string>();
+                double totalScore = 0;
+                List<List<double>> allList = new List<List<double>>();
                 foreach (ExamResult result in examResults)
                 {
+                    
                     List<double> ClassAverage = new List<double>();
-                    List<string> ClassName = new List<string>();
+                    List<string> ClassId = new List<string>();
                     Dictionary<string, object> mapClass = new Dictionary<string, object>();
                     int index = result.studentIds.IndexOf(sId.ToString());
-
+                    //个人总分
+                    totalScore += result.studentScores[index].Sum();
                     mapClass.Add("subjectId", result.subjectId);
+                    double totalGrade = 0;
+                    List<double> gradeScores = new List<double>();
+                    List<List<double>> classScores = new List<List<double>>();
+                    //此处声明集合存储原本的成绩序列
+                    List<List<double>> cScores = new List<List<double>>();
                     foreach (ClassRange range in result.classes)
                     {
+                        List<double> scores = new List<double>();
+                        List<double> finalScores = new List<double>();
+                        if (range.gradeId.Equals(gId.ToString(), StringComparison.OrdinalIgnoreCase))
+                        {
+                            ClassId.Add(range.id);
+                            cla.Add(range.id);
                             double totalClass = 0;
                             for (int i = range.range[0]; i <= range.range[1]; i++)
                             {
                                 totalClass += result.studentScores[i].Sum();
+                                scores.Add(result.studentScores[i].Sum());
+                                finalScores.Add(result.studentScores[i].Sum());
+                                gradeScores.Add(result.studentScores[i].Sum());
+                                totalGrade += result.studentScores[i].Sum();
+                                stu.Add(result.studentIds[i]);
                             }
-                            ClassAverage.Add(range.range[1] - range.range[0] + 1 > 0 ? totalClass * 1.0 / (range.range[1] - range.range[0] + 1) : 0);                   
+                            classScores.Add(scores);
+                            cScores.Add(finalScores);
+                            ClassAverage.Add(range.range[1] - range.range[0] + 1 > 0 ? Math.Round(totalClass * 1.0 / (range.range[1] - range.range[0] + 1),2) : 0);
+                        }                                
                     }
+                    classAllAverage.Add(ClassAverage);
+                    gradeScores.Sort((s1, s2) => { return s2.CompareTo(s1); });
+                    indexClass = ClassId.IndexOf(cId.ToString());
+                    //单科成绩
+                    allList.Add(cScores[indexClass]);
+                    classScores[indexClass].Sort((s1, s2) => { return s2.CompareTo(s1); });
                     mapClass.Add("Score",result.studentScores[index].Sum());
-                    mapClass.Add("ClassAverage", ClassAverage);                
+                    mapClass.Add("ClassAverage", ClassAverage[indexClass]);
+                    mapClass.Add("ClassRank", classScores[indexClass].IndexOf(result.studentScores[index].Sum()));
+                    mapClass.Add("GradeAverage", Math.Round(totalGrade*1.0 / result.studentIds.Count,2));
+                    mapClass.Add("GradeRank", gradeScores.IndexOf(result.studentScores[index].Sum()));
                     averageMap.Add(mapClass);
                 }
-                return Ok(new { averageMap});
+                //处理班级/年级全科均分
+                List<double> AllAverage = new List<double>();
+                double a = 0;
+                for (int k = 0;k< cla.Count;k++) {
+                    for (int i = 0; i < classAllAverage.Count; i++)
+                    {
+                        a += classAllAverage[i][k];
+                    }
+                    AllAverage.Add(a);
+                }
+                List<double> classScore = new List<double>();
+                for (int i =0; i<allList[0].Count;i++) {
+                    double b = 0;
+                    for (int m = 0; m< allList.Count; m++) {
+                        b += allList[m][i];
+                    }
+                    classScore.Add(b);
+                }
+                classScore.Sort((s1, s2) => { return s2.CompareTo(s1); });
+                //处理年级总分以及排名
+                List<double> GradeScore = new List<double>();
+                foreach (string ss in stu) {
+                    double score = 0;
+                    foreach (ExamResult result in examResults) {
+                        int index = result.studentIds.IndexOf(ss);
+                        score += result.studentScores[index].Sum();
+                    }
+                    GradeScore.Add(score);
+                }
+                GradeScore.Sort((s1, s2) => { return s2.CompareTo(s1); });
+                return Ok(new { rankc = classScore.IndexOf(totalScore),rankg = GradeScore.IndexOf(totalScore), classAverage = Math.Round(AllAverage[indexClass],2), gradeAverage = Math.Round(AllAverage.Sum() * 1.0 / cla.Count,2), averageMap }); ;
             }
             catch (Exception e)
             {

+ 18 - 0
TEAMModelOS/Controllers/Core/BlobController.cs

@@ -254,6 +254,7 @@ namespace TEAMModelOS.Controllers.Core
         }
         /// <summary>
         /// 测试单个文本内容的上传
+        /// {"containerName":"hbcn","updateSize":5000,"deleteurl":[]}
         /// </summary>
         /// <param name="azureBlobSASDto"></param>
         /// <returns></returns>
@@ -266,6 +267,23 @@ namespace TEAMModelOS.Controllers.Core
             var size = await client.GetBlobsSize();
             return Ok(new { size });
         }
+        /// <summary>
+        /// 测试单个文本内容的上传
+        /// {"containerName":"hbcn","updateSize":5000,"deleteurl":[]}
+        /// </summary>
+        /// <param name="azureBlobSASDto"></param>
+        /// <returns></returns>
+        [HttpPost("get-blobUrlsize")]
+        public async Task<ActionResult> getBlobUrlsize(JsonElement request)
+        {
+            request.TryGetProperty("containerName", out JsonElement containerName);
+            request.TryGetProperty("deleteUrl", out JsonElement deleteUrl);
+            var name = containerName.GetString();
+            var urls = deleteUrl.ToObject<List<string>>();
+            var client = _azureStorage.GetBlobContainerClient(name);
+            var size = await client.GetBlobsSize(urls);
+            return Ok(new { size });
+        }
 
         private static (string, string) BlobUrlString(string sasUrl)
         {