فهرست منبع

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

liqk 4 سال پیش
والد
کامیت
8715f38833

+ 41 - 9
TEAMModelOS.SDK/DI/AzureStorage/AzureStorageBlobExtensions.cs

@@ -8,6 +8,8 @@ using TEAMModelOS.SDK.Context.Constant;
 using TEAMModelOS.SDK.Helper.Security.ShaHash;
 using System;
 using System.IO;
+using Azure.Storage.Blobs.Specialized;
+using System.Collections.Generic;
 
 namespace TEAMModelOS.SDK.DI
 {
@@ -22,19 +24,49 @@ namespace TEAMModelOS.SDK.DI
         {
             long? size = 0;
             try
-            {                
+            {
                 await foreach (var item in client.GetBlobsAsync(BlobTraits.None, BlobStates.None, prefix))
                 {
                     size += item.Properties.ContentLength;
                 };
                 return size;
             }
-            catch 
+            catch
             {
                 return size;
             }
         }
 
+        /// <summary>
+        /// 批量刪除Blobs
+        /// 注意單個批次最多支持256個子請求。批處理請求的正文大小不能超過4MB,超過返回False
+        /// </summary>      
+        /// <param name="prefix">篩選開頭名稱,Null代表容器</param>        
+        public static async Task<bool> DelectBlobs(this BlobServiceClient client, string blobContainerName, string prefix = null)
+        {
+            if (string.IsNullOrWhiteSpace(prefix)) return false;
+
+            try
+            {
+                BlobContainerClient bcc = client.GetBlobContainerClient(blobContainerName);
+                BlobBatchClient bbc = client.GetBlobBatchClient();
+                List<Uri> blobs = new List<Uri>();
+                await foreach (var item in bcc.GetBlobsAsync(BlobTraits.None, BlobStates.None, prefix))
+                {
+                    var urib = new UriBuilder(bcc.Uri);
+                    urib.Path += "/" + item.Name;
+                    blobs.Add(urib.Uri);
+                };
+
+                await bbc.DeleteBlobsAsync(blobs);
+                return true;
+            }
+            catch
+            {
+                return false;
+            }
+        }
+
         /// <summary>
         /// 系统管理员 资源,题目关联,htex关联,学习活动学生上传文件关联,基本信息关联,教室平面图关联,评测冷数据关联
         /// "system": [ "res", "item", "htex", "task", "info", "room", "exam" ],
@@ -56,7 +88,7 @@ namespace TEAMModelOS.SDK.DI
 
             // string groupName =folder;
 
-            BlobContainerClient blobContainer =  azureStorage.GetBlobContainerClient(name.ToLower().Replace("#", "")); //blobClient.GetContainerReference(groupName); 
+            BlobContainerClient blobContainer = azureStorage.GetBlobContainerClient(name.ToLower().Replace("#", "")); //blobClient.GetContainerReference(groupName); 
             Uri url = blobContainer.Uri;
 
             var blockBlob = blobContainer.GetBlobClient(folder + "/" + fileName);
@@ -68,23 +100,23 @@ namespace TEAMModelOS.SDK.DI
                 if (!string.IsNullOrEmpty(contenttype))
                 {
                     content_type = contenttype;
-                    
-                    
+
+
                 }
                 else
                 {
-                   
+
                     //blockBlob.Properties.ContentType = content_type;
                 }
             }
             else
             {
-               
+
                 //blockBlob.Properties.ContentType = content_type;
             }
             byte[] bytes = System.Text.Encoding.Default.GetBytes(text);
-            Stream streamBlob= new MemoryStream(bytes);
-            await blockBlob.UploadAsync(streamBlob,true);
+            Stream streamBlob = new MemoryStream(bytes);
+            await blockBlob.UploadAsync(streamBlob, true);
             blockBlob.SetHttpHeaders(new BlobHttpHeaders { ContentType = content_type });
             AzureBlobModel model = new AzureBlobModel(fileName, name, folder, fileName, folder, content_type, bytes.Length)
             {

+ 29 - 6
TEAMModelOS/ClientApp/src/components/learnactivity/ClassList.less

@@ -8,17 +8,17 @@
 .content {
     width: 100%;
     height: 100%;
-    display: flex;
+    /*display: flex;*/
 
     .class-list {
         width: calc(100% - 10px);
         height: 100%;
-        margin-left: 5px;
+        /*margin-left: 5px;*/
     }
 
     .class-info {
-        /*width: 80%;*/
-        height: 95%;
+        width: 100%;
+        height: 100%;
         /*overflow:hidden;*/
         /*min-height: 98%;*/
         /*padding-left: 10px;*/
@@ -27,6 +27,7 @@
 
     .learn-progress-main{
         height:100%;
+        width:100%;
     }
     .subject-item {
         display: inline-block;
@@ -82,10 +83,32 @@
 .table-show{
     margin-top:15px;
     margin-bottom:10px;
+    width:100%;
+    height:100%;
+    overflow:auto;
+}
+.table-show /deep/ .ivu-table-fixed  {
+    background-color: #2B2B2E;
+}
+.table-show /deep/ .ivu-table-fixed-right {
+    background-color: #2B2B2E;
 }
-.ivu-table th {
-    background-color:none !important;
+
+.table-show /deep/ .ivu-table-fixed-right::before {
+    height: 0px;
+}
+.table-show /deep/ .ivu-table-fixed::before {
+    height: 0px;
+}
+.table-show /deep/ .ivu-table-fixed-header thead tr th {
+    border-bottom: 1px solid #e8eaec6e;
+    border-right: 1px solid #e8eaec6e;
+    background-color: #2B2B2E;
+    color:#ffffff;
 }
+/*.ivu-table th {
+    background-color: none !important;
+}*/
 .scoreShow {
     color: #1CC0F3;
     cursor:pointer;

+ 49 - 49
TEAMModelOS/ClientApp/src/components/learnactivity/ClassList.vue

@@ -9,46 +9,52 @@
                 <Button v-show="showTest" style=" float: right; margin-top: 5px; margin-right: 25px;" @click="getBack" icon="md-arrow-back" type="info">返回</Button>
             </div>
             <div class="class-info">
-                <div class="learn-progress-main " v-show="!showTest">
-                    <vuescroll>
-                        <!--<p style="color:#EEEEEE;font-size:16px;margin-top:5px;">测验成绩分析</p>-->
-                        <div class="class-filter dark-iview-select">
-                            <span class="filter-label">测验年级:</span>
-                            <Select filterable v-model="chooseGrade" style="display: inline-block;width: 100px;" @on-change="getPeriod" size="small">
-                                <Option v-for="(item,index) in paperData.grade" :value="item.id" :key="index">{{ item.name }}</Option>
-                            </Select>
-                            <span style="margin-left:5px">班级:</span>
-                            <Select filterable v-model="chooseClass" style="display: inline-block;width: 150px;" @on-change="getClassInfo" size="small">
-                                <Option v-for="(item,index) in classData" :value="item.id" :key="index">{{ item.name }}</Option>
-                            </Select>
-                        </div>
-                        <!--<div class="chart-show">
-                            <div v-if="!testStatus" class="chart" style="margin:auto">
-                                <Grade v-if="studentList.length !== 0" :studentData="studentList"></Grade>
-                            </div>
-                            <div v-if="testStatus" class="chart">
-                                <Analyse></Analyse>
-                            </div>
+                <div class="learn-progress-main" v-show="!showTest">
+                    <!--<p style="color:#EEEEEE;font-size:16px;margin-top:5px;">测验成绩分析</p>-->
+                    <div class="class-filter dark-iview-select">
+                        <span class="filter-label">测验年级:</span>
+                        <Select filterable v-model="chooseGrade" style="display: inline-block;width: 100px;" @on-change="getPeriod" size="small">
+                            <Option v-for="(item,index) in paperData.grade" :value="item.id" :key="index">{{ item.name }}</Option>
+                        </Select>
+                        <span style="margin-left:5px">班级:</span>
+                        <Select filterable v-model="chooseClass" style="display: inline-block;width: 150px;" @on-change="getClassInfo" size="small">
+                            <Option v-for="(item,index) in classData" :value="item.id" :key="index">{{ item.name }}</Option>
+                        </Select>
+                    </div>
+                    <!--<div class="chart-show">
+                        <div v-if="!testStatus" class="chart" style="margin:auto">
+                            <Grade v-if="studentList.length !== 0" :studentData="studentList"></Grade>
                         </div>
-                        <p style="color:#EEEEEE;padding-left:15px;font-size:16px;margin-top:10%;margin-bottom:10px;">学生成绩数据</p>-->
-                        <div class="table-show dark-iview-table" >
-                            <Loading :top="200" type="1" style="text-align:center" v-if="dataLoading"></Loading>
-                            <Table v-if="!dataLoading" border :columns="scoreLists" :data="studentScore">
-                                <template slot-scope="{ row,index }" slot="total">
-                                    <strong>{{getcount(studentScore[row._index].data)}}</strong>
-                                </template>
-                                <template slot-scope="{ row,index }" :slot="'que'+qIndex" v-for="(item,qIndex) in quLen">
-                                    <div  @click="getStuScore(row,qIndex)" :class="[studentScore[row._index].data[qIndex] == -1 ?'scoreShow':'scoreShows']">
-                                        <span >{{studentScore[row._index].data[qIndex] == -1 ? '-': studentScore[row._index].data[qIndex]}}</span>
-                                    </div>
-                                </template>
-                            </Table>
-                            <!--<Table v-if="studentList.length !== 0" @fixScore="getScore" :studentData="studentList"></Table>-->
+                        <div v-if="testStatus" class="chart">
+                            <Analyse></Analyse>
                         </div>
-                    </vuescroll>
+                    </div>
+                    <p style="color:#EEEEEE;padding-left:15px;font-size:16px;margin-top:10%;margin-bottom:10px;">学生成绩数据</p>-->
+                    <div class="table-show dark-iview-table">
+                        
+                        <Table  border :columns="scoreLists" :loading="dataLoading" height="750" :data="studentScore">
+                            <div class="show-loading" slot="loading">
+                                <Loading :top="-200" type="1"></Loading>
+                            </div>
+                            <template slot-scope="{ row,index }" :slot="'que'+qIndex" v-for="(item,qIndex) in quLen">
+                                <div @click="getStuScore(row,qIndex)">
+                                    <Poptip trigger="hover" content="点击前往评分页面">
+                                        <Icon class="scoreShow" size="26" type="ios-create-outline" v-show="studentScore[row._index].data[qIndex] == -1" />
+                                    </Poptip>      
+                                    <Poptip trigger="hover" content="点击查看试题详情">
+                                        <span class="scoreShows" v-show="studentScore[row._index].data[qIndex] != -1">{{studentScore[row._index].data[qIndex]}}</span>
+                                    </Poptip>
+                                </div>
+                            </template>
+                            <template slot-scope="{ row,index }" slot="total">
+                                <strong>{{getcount(studentScore[row._index].data)}}</strong>
+                            </template>
+                        </Table>
+                        <!--<Table v-if="studentList.length !== 0" @fixScore="getScore" :studentData="studentList"></Table>-->
+                    </div>
                 </div>
                 <div class="dark-iview-table" v-show="showTest">
-                    <!--<p style="color:#EEEEEE;font-size:16px;margin-top:5px;">测验成绩评分</p>-->
+                    <p style="color:#EEEEEE;font-size:16px;margin-top:5px;">测验成绩评分</p>
                     <div style="margin-top:5px;overflow:hidden">
                         <grade-list v-on:closeTest="getBack" :studentInfo="selectStudent" :paperInfo="paperData"></grade-list>
                     </div>
@@ -98,11 +104,14 @@ import { data } from 'autoprefixer'
                         key: 'name',
                         fixed:'left',
                         align: 'center',
+                        minWidth:150
                     },
                     {
                         title: '总分',
                         slot: 'total',
-                        align: 'center'
+                        align: 'center',
+                        fixed: 'right',
+                        width:100
                     }
                 ],
                 scoreLists: [],
@@ -114,7 +123,6 @@ import { data } from 'autoprefixer'
         },
         methods: {
             getBack(data) {
-                console.log(data)
                 if (data == '1') {
                     this.initClassData()
                 }
@@ -124,14 +132,12 @@ import { data } from 'autoprefixer'
                 this.showTest = false
                 this.selectStudent = {}
                 if (data.id) {
-                    console.log('4121561561')
                     data.classId = this.chooseClass
                     data.className = this.getClassName(this.chooseClass)
                     data.queNo = index
                     this.showTest = true
                 }
                 this.selectStudent = { ...data }
-                console.log(this.selectStudent)
             },
             getClassName(data) {
                 if (this.classData.length) {
@@ -144,7 +150,6 @@ import { data } from 'autoprefixer'
             },
             //初始化获取班级数据
             getClassData(data) {
-                console.log('2')
                 this.classData.length = 0
                 if (data !== undefined) {
                     for (let item of this.classList) {
@@ -153,11 +158,9 @@ import { data } from 'autoprefixer'
                         }
                     }
                 }
-                console.log(this.classData)
             },
             //年级数据获取
             getPeriod(data) {
-                console.log('1')
                 this.chooseGrade = ''
                 if (data) {
                     this.chooseGrade = data
@@ -176,7 +179,6 @@ import { data } from 'autoprefixer'
                 }, 0)
             },
             getScores(data) {
-                console.log(data)
                 return data.id
             },
             //获取班级测评数据
@@ -257,7 +259,9 @@ import { data } from 'autoprefixer'
                     let data = {
                         title: "No" + (i + 1),
                         slot: "que" + i,
-                        align:'center'
+                        align: 'center',
+                        minWidth:150
+
                     }
                     this.scoreLists.push(data)
                 }
@@ -266,7 +270,6 @@ import { data } from 'autoprefixer'
                     for (let k = 0; k < this.studentData.students.length; k++) {
                         let score = {}
                         if (this.studentAns.studentIds[i] == this.studentData.students[k].id) {
-                            console.log(i)
                             score.name = this.studentData.students[k].name
                             score.id = this.studentAns.studentIds[i]
                             score.data = this.studentAns.studentScores[i]
@@ -303,7 +306,6 @@ import { data } from 'autoprefixer'
             },
             getAllStudentData() {
                 this.dataLoading = true
-                console.log(this.paperData)
                 let requestData = {
                     id: this.paperData.id,
                     school: this.$store.state.user.schoolCode,
@@ -314,9 +316,7 @@ import { data } from 'autoprefixer'
                     this.$api.learnActivity.FindAllStudent(requestData).then(
                         res => {
                             this.studentAns = {}
-                            console.log(res)
                             if (res.examClassResults.length > 0) {
-                                console.log(res.examClassResults[0])
                                 this.studentAns = res.examClassResults[0]
                                 this.setTableData()
                                 setTimeout(() => {

+ 110 - 83
TEAMModelOS/ClientApp/src/components/learnactivity/GradeList.less

@@ -15,98 +15,125 @@
     border-right: 1px solid @borderColor;
 }
 
-.grade-box {
+.show-loading /deep/ .loading-container {
     width: 100%;
-    margin: 10px;
-    float: right;
-}
-
-.search-box {
-    height: 5%;
-    margin-top:5px;
-    /*margin-left:5px;*/
-    border-bottom: 1px solid @borderColor;
-}
-.student-box {
-    height:98%;
-    li :hover{
-        cursor:pointer;
+    height: 100%;
+    right: 0px;
+    top: 0;
+    left: 0;
+    display: flex;
+    /* flex-direction: row; */
+    text-align: center;
+    justify-content: center;
+    /* background: rgba(103, 103, 103, 0.27); */
+    z-index: 1000;
     }
-    .student-list{
-        height:96%;
+
+    .grade-box {
+        width: 100%;
+        margin: 10px;
+        float: right;
     }
-    .student-show {
-        width:95%;
-        height: 40px;
-        padding-top:10px;
+
+    .search-box {
+        height: 5%;
+        margin-top: 5px;
+        /*margin-left:5px;*/
         border-bottom: 1px solid @borderColor;
-        display: block;
-        span {
-            font-size: 15px;
-            color: @primary-textColor;
-            margin-left: 10px;
+    }
+
+    .student-box {
+        height: 98%;
+
+        li :hover {
+            cursor: pointer;
+        }
+
+        .student-list {
+            height: 96%;
+        }
+
+        .student-show {
+            width: 95%;
+            height: 40px;
+            padding-top: 10px;
+            border-bottom: 1px solid @borderColor;
+            display: block;
+
+            span {
+                font-size: 15px;
+                color: @primary-textColor;
+                margin-left: 10px;
+            }
         }
     }
-}
-.awnser-box {
-    margin-top: 10px;
-    width: 95%;
-    border: 1px solid @borderColor;
 
-    .question-box {
-        margin-top: 20px;
+    .awnser-box {
+        margin-top: 10px;
+        width: 95%;
+        border: 1px solid @borderColor;
+
+        .question-box {
+            margin-top: 20px;
+            display: flex;
+            width: 100%;
+            /* background-color: #fff; */
+            /*margin-bottom: 10px;*/
+            margin-left: 5px;
+        }
+    }
+
+    .content {
         display: flex;
         width: 100%;
-        /* background-color: #fff; */
-        /*margin-bottom: 10px;*/
+        margin: auto;
+        height: 730px;
+        border: 1px solid @borderColor;
+        position: relative;
+    }
+
+    .top-bar {
+        height: 40px;
+        border: 1px solid #424242;
+        display: inline-flex;
+        width: 100%;
+    }
+
+    .type-list {
+        width: 100%;
+        padding-top: 5px;
         margin-left: 5px;
     }
-}
-.content {
-    display: flex;
-    width: 100%;
-    margin: auto;
-    height:730px;
-    border: 1px solid @borderColor;
-    position:relative;
-}
 
-.top-bar {
-    height: 40px;
-    border: 1px solid #424242;
-    display: inline-flex;
-    width: 100%;
-}
-.type-list{
-    width:100%;
-    padding-top:5px;
-    margin-left:5px;
-}
-.button-list {
-    width: 50%;
-    padding-top: 3px;
-    text-align: right;
-}
-.base-info-btn{
-    margin-left:5px;
-    margin-right:10px;
-}
-.base-info-item {
-    font-size: 16px;
-    color: #a5a5a5;
-    margin-left:15px;
-}
-.analysis-info {
-    font-size: 16px;
-    color: #0f9272;
-}
-.activity-status {
-    font-size: 10px !important;
-    background: #19be6b;
-    float: right;
-    padding: 0 5px;
-    color: @primary-textColor;
-    display: inline-block;
-    margin-right: 10px;
-    border-radius: 5px;
-}
+    .button-list {
+        width: 50%;
+        padding-top: 3px;
+        text-align: right;
+    }
+
+    .base-info-btn {
+        margin-left: 5px;
+        margin-right: 10px;
+    }
+
+    .base-info-item {
+        font-size: 16px;
+        color: #a5a5a5;
+        margin-left: 15px;
+    }
+
+    .analysis-info {
+        font-size: 16px;
+        color: #0f9272;
+    }
+
+    .activity-status {
+        font-size: 10px !important;
+        background: #19be6b;
+        float: right;
+        padding: 0 5px;
+        color: @primary-textColor;
+        display: inline-block;
+        margin-right: 10px;
+        border-radius: 5px;
+    }

+ 10 - 1
TEAMModelOS/ClientApp/src/components/learnactivity/GradeList.vue

@@ -269,7 +269,16 @@
             },
         },
         mounted() {
-            this.getClassData(1)
+            this.$store.dispatch('user/getSchoolProfile').then(
+                (res) => {
+                    if (res) {
+                        this.getClassData(1)
+                    }
+                },
+                (err) => {
+                    this.$Message.error('API error!')
+                }
+            )
         },
         watch: {
             paperInfo: {

+ 4 - 3
TEAMModelOS/ClientApp/src/components/student-web/EventBasicInfo.vue

@@ -18,11 +18,11 @@
     <i-col :xs="24" :sm="24" :md="24" :lg="getCurrentLang()=='tw'?12:24" class="info-part">
       <ul class="base-info" :class="{'base-infoEn':getCurrentLang()=='en'}">
         <li
-          v-if="this.$store.getters.getItemTitle.eventType == 'exam' "
+          v-if="this.$store.getters.getItemTitle.eventType == 'exam' && paper.length !== 0 "
         >
           <svg-icon icon-class="subject" class="base-info-icon" />{{ $t('studentWeb.baseInfo.subject')}}
-          <span class="base-info-text">综合科目</span>
-           <span class="base-info-text" v-if="getCurrentLang()=='en'">{{ transSubjecttoEn(this.$store.getters.getItemTitle.eventSubject) }}</span>
+          <span class="base-info-text">{{paper.length > 1? '综合科目':paper[0].subject.name }}</span>
+          <span class="base-info-text" v-if="getCurrentLang()=='en'">{{ transSubjecttoEn(this.$store.getters.getItemTitle.eventSubject) }}</span>
         </li>
 
         <!--<li>
@@ -104,6 +104,7 @@ export default {
     },
         },
         mounted() {
+            console.log('54534135123123')
             console.log(this.paper)
         },
         methods: {

+ 1 - 1
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContent.vue

@@ -59,7 +59,7 @@ export default {
     }
   },
         mounted() {
-            console.log(this.$store.getters.getItemTitle.eventType)
+            //console.log(this.$store.getters.getItemTitle.eventType)
     //this.theFirstActiveEvent(); // <!-- 如果沒選的時候預設顯示列表第一個-->
   },
   data() {

+ 2 - 2
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTest.vue

@@ -118,12 +118,12 @@
             </div>-->
             <!----->
             <!--多學科試卷-->
-            <div v-if="paperData.length >1 ">
+            <div v-if="paperData.length > 0 ">
                 <ul v-for="(item, index) in paperData"
                     :key="index"
                     class="tasks"
                     @click="opentestWithSubject(item)">
-                    <li class="title" v-if="getCurrentLang() == 'tw'">
+                    <li class="title">
                         <span style="position: relative; top: 1px">
                             <svg-icon icon-class="test" class="title-icon" />
                         </span>

+ 1 - 0
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestPop.vue

@@ -462,6 +462,7 @@
             openWarmMessage: function (showMessageNum) {
                 this.WarmMessageisOpen = true;
                 if (showMessageNum == 1) {
+                    //if()
                     this.showMessageNum = showMessageNum;
                 } else if (showMessageNum == 2) {
                     for (var i = 0; i <= this.$store.getters.getPaperInfo.item.length; i++) {

+ 0 - 14
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventView.vue

@@ -51,22 +51,8 @@
             this.$emit("onNavName", this.MyName);
             this.$store.commit("ToggleSidebar", true);
             this.$store.commit("SaveNowPage", '活動');
-            //this.setPaperData()
         },
         methods: {
-
-
-            setPaperData() {
-                let data = {
-                    scope: "school",
-                    blob: "/paper/主观题测试"
-                }
-                let info = this.$evTools.getFullPaper(data)
-                console.log('学生端试卷信息')
-                console.log(info)
-            },
-
-
             scrollList() {
                 //當從通知操作進行捲動時,將篩選條件清空
                 this.selectedEventStatusNow = "所有活動狀態";

+ 2 - 2
TEAMModelOS/ClientApp/src/css/common-style.less

@@ -1,4 +1,4 @@
-@first-bgColor: #141414;
+@first-bgColor: #141414;
 @second-bgColor: #1b1b1b;
 @third-bgColor: #222222;
 @borderColor: #424242;
@@ -23,7 +23,7 @@
 .custom-scroll-bar {
     div::-webkit-scrollbar { /*滚动条整体样式*/
         width: 5px; /*高宽分别对应横竖滚动条的尺寸*/
-        height: 1px;
+        height: 10px;
     }
 
     div::-webkit-scrollbar-thumb { /*滚动条里面小方块*/

+ 8 - 2
TEAMModelOS/ClientApp/src/view/learnactivity/CreateEvaluation.vue

@@ -806,12 +806,18 @@
                     scope: this.mode,
                     createDate: Math.round(new Date())
                 }
+
                 this.$api.learnActivity.SaveExamInfo(data).then(
                     res => {
                         if (res.error == null) {
                             this.$Message.success('评测发布成功!')
-                            this.evaluationInfo.papers = res.exam
-                            this.isLoading = false
+                            setTimeout(() => {
+                                this.isLoading = false
+                                let datas = this.mode + 'Evaluation'
+                                this.$router.push({
+                                    name: datas
+                                })
+                                this.evaluationInfo.papers = res.exam},500)
                         } else {
                             this.$Message.error('API ERROR!')
                             this.isLoading = false

+ 1 - 1
TEAMModelOS/ClientApp/src/view/learnactivity/ManageEvaluation.less

@@ -13,7 +13,7 @@
     flex-direction: row;
 
     .evaluation-list-wrap {
-        width: 30%;
+        width: 20%;
         height: 100%;
         border-right: 1px solid @borderColor;
         padding-left: 15px;

+ 3 - 1
TEAMModelOS/ClientApp/src/view/learnactivity/ManageEvaluation.vue

@@ -95,7 +95,9 @@
             </div>
             <!-- 试卷评测打分 -->
             <div :class="currentBraIndex == 0 ? 'animated fadeIn evaluation-base-info':'evaluation-base-info animated fadeOutRight'" v-if="currentBraIndex == 0">
-                <ClassList :paper="examPaperList"></ClassList>
+                <div style="width:100%;height:100%">
+                    <ClassList :paper="examPaperList"></ClassList>
+                </div>
             </div>
         </div>
         <Modal v-model="editEvaluationStatus"

+ 134 - 76
TEAMModelOS/Controllers/Exam/ImportExerciseController.cs

@@ -86,11 +86,11 @@ namespace TEAMModelOS.Controllers
         [RequestSizeLimit(102_400_000_00)] //最大10000m左右
         public async Task<IActionResult> AnalysisPPTX(JsonElement request)
         {
-            string id_token = HttpContext.GetXAuth("IdToken");
-            if (string.IsNullOrEmpty(id_token)) return BadRequest();
-            var jwt = new JwtSecurityToken(id_token);
-            if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
-            var id = jwt.Payload.Sub;
+            //string id_token = HttpContext.GetXAuth("IdToken");
+            //if (string.IsNullOrEmpty(id_token)) return BadRequest();
+            //var jwt = new JwtSecurityToken(id_token);
+            //if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
+            //var id = jwt.Payload.Sub;
 
             request.TryGetProperty("code", out JsonElement code);
             string azureBlobSAS = System.Web.HttpUtility.UrlDecode(code.ToString(), Encoding.UTF8);
@@ -107,8 +107,8 @@ namespace TEAMModelOS.Controllers
                 var response = await _clientFactory.CreateClient().GetAsync(new Uri(blobAuth.url + blobAuth.sas));
                 response.EnsureSuccessStatusCode();
                 Stream stream=  await response.Content.ReadAsStreamAsync();
-                HTEXLib.Htex htex = await PPTXTranslator(id, FileName, stream);
-                return Ok(JsonSerializer.Deserialize<JsonElement>(json: JsonHelper.ToJson(htex, ignoreNullValue: true)));
+                string  index = await PPTXTranslator(ContainerName, FileName, stream);
+                return Ok(new { index=index });
             }
             else { return BadRequest("不是正确的Blob链接!"); }
         }
@@ -142,80 +142,20 @@ namespace TEAMModelOS.Controllers
             var jwt = new JwtSecurityToken(id_token);
             if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
             var id = jwt.Payload.Sub;
-            if (!FileType.GetExtention(file.FileName).ToLower().Equals("pptx"))
+            if (FileType.GetExtention(file.FileName).ToLower().Equals("pptx") || FileType.GetExtention(file.FileName).ToLower().Equals("xml"))
             {
-                return BadRequest("type is not pptx!");
+                string FileName = file.FileName;
+                Stream streamFile = file.OpenReadStream();
+                string index = await PPTXTranslator(id, FileName, streamFile);
+                return Ok(new { index = index });
             }
-            string FileName = file.FileName;
-            Stream streamFile = file.OpenReadStream();
-
-            HTEXLib.Htex htex = await PPTXTranslator(id, FileName, streamFile);
-            return Ok(JsonSerializer.Deserialize<JsonElement>(json: JsonHelper.ToJson(htex, ignoreNullValue: true)));
-        }
-
-        private async Task<HTEXLib.Htex> PPTXTranslator(string id, string FileName, Stream streamFile)
-        {
-            var day = new DateTimeOffset(DateTime.UtcNow).ToString("yyyyMMdd", DateTimeFormatInfo.InvariantInfo);
-            string shaCode = ShaHashHelper.GetSHA1(streamFile);
-            HTEXLib.Htex htex = htexGenerator.Generator(streamFile);
-            htex.name = FileName;
-            var slides = htex.slides;
-            int index = 1;
-            List<Task> tasks = new List<Task>();
-            foreach (var slide in slides)
-            {
-                string text = JsonHelper.ToJson(slide, ignoreNullValue: false);
-                tasks.Add(_azureStorage.UploadFileByContainer(id, text, "pptx", day + "/" + shaCode + "/" + index + ".json", false)
-                    .ContinueWith((Task<AzureBlobModel> blob) =>
-                    {
-                        htex.urls.Add(blob.Result.BlobUrl);
-                    })
-                    );
-                // var blob=  await _azureStorage.UploadFileByContainer(id, text, "pptx", day+"/"+ shaCode +"/"+ index + ".json", false);
-                // htex.urls.Add(blob.BlobUrl);
-                index++;
+            else {
+                return BadRequest("type is not pptx or xml !");
             }
-            await Task.WhenAll(tasks);
-            htex.slides = null;
-            Dictionary<string, Store> dict = new Dictionary<string, Store>();
-            List<Task> tasksFiles = new List<Task>();
-            foreach (var key in htex.stores.Keys)
-            {
-                if (key.EndsWith(".wdp") || key.EndsWith(".xlsx"))
-                {
-                    htex.stores.Remove(key);
-                    continue;
-                }
-                var store = htex.stores[key];
-                Store str = new Store() { path = key, contentType = store.contentType, isLazy = store.isLazy };
-                if (!store.isLazy && store.contentType != null && ContentTypeDict.extdict.TryGetValue(store.contentType, out string ext) && store.url.Contains(";base64,"))
-                {
-                    string[] strs = store.url.Split(',');
-                    Stream stream = new MemoryStream(Convert.FromBase64String(strs[1]));
-                    var urlstrs = key.Split("/");
-                    var name = urlstrs[urlstrs.Length - 1];
-                    tasksFiles.Add(_azureStorage.UploadFileByContainer(id, stream, "pptx", day + "/" + shaCode + "/" + name, false)
-                        .ContinueWith((Task<AzureBlobModel> blob) =>
-                        {
-                            str.url = blob.Result.BlobUrl;
-                        })
-                        );
-                    // var blob = await _azureStorage.UploadFileByContainer(id, stream, "pptx", day + "/" + shaCode + "/" + name, false);
-                    //  str.url = blob.BlobUrl;
-
-                }
-                else
-                {
-                    str.url = store.url;
-                }
-                dict.TryAdd(key, str);
-            }
-            await Task.WhenAll(tasksFiles);
-            htex.stores = dict;
-            return htex;
+            
+           
         }
 
-
         /// <summary>
         /// docUrl
         /// folder
@@ -294,5 +234,123 @@ namespace TEAMModelOS.Controllers
                 return builder.Data(null).build();
             }
         }
+
+        private async Task<string> PPTXTranslator(string id, string FileName, Stream streamFile)
+        {
+            //var day = new DateTimeOffset(DateTime.UtcNow).ToString("yyyyMMdd", DateTimeFormatInfo.InvariantInfo);
+            string shaCode = ShaHashHelper.GetSHA1(streamFile);
+            HTEXLib.Htex htex = htexGenerator.Generator(streamFile);
+            htex.name = FileName;
+            var slides = htex.slides;
+            List<Task> tasks = new List<Task>();
+            HTEX hTEX = new HTEX() { name = FileName, size = htex.size, thumbnail = htex.thumbnail, id = shaCode };
+
+            Dictionary<string, string> texts = new Dictionary<string, string>();
+            List<string> shas = new List<string>();
+            foreach (var slide in slides)
+            {
+                string text = JsonHelper.ToJson(slide, ignoreNullValue: false);
+                string sha = ShaHashHelper.GetSHA1(text);
+                texts.Add(sha, text);
+                shas.Add(sha);
+            }
+            Dictionary<string, string> bloburls = new Dictionary<string, string>();
+            foreach (var key in texts.Keys)
+            {
+                tasks.Add(_azureStorage.UploadFileByContainer(id, texts[key], "res", FileName + "/" + key + ".json", false)
+                    .ContinueWith((Task<AzureBlobModel> blob) =>
+                    {
+                        bloburls.Add(key, blob.Result.BlobUrl);
+                    })
+                    );
+            }
+            await Task.WhenAll(tasks);
+            List<Sld> slds = new List<Sld>();
+            foreach (string sha in shas)
+            {
+                slds.Add(new Sld { type = "normal", url = bloburls[sha], scoring = null }); ;
+            }
+            Dictionary<string, Store> dict = new Dictionary<string, Store>();
+            List<Task> tasksFiles = new List<Task>();
+            foreach (var key in htex.stores.Keys)
+            {
+                if (key.EndsWith(".wdp") || key.EndsWith(".xlsx"))
+                {
+                    htex.stores.Remove(key);
+                    continue;
+                }
+                var store = htex.stores[key];
+                Store str = new Store() { path = key, contentType = store.contentType, isLazy = store.isLazy };
+                if (!store.isLazy && store.contentType != null && ContentTypeDict.extdict.TryGetValue(store.contentType, out string ext) && store.url.Contains(";base64,"))
+                {
+                    string[] strs = store.url.Split(',');
+                    Stream stream = new MemoryStream(Convert.FromBase64String(strs[1]));
+                    var urlstrs = key.Split("/");
+                    var name = urlstrs[urlstrs.Length - 1];
+                    tasksFiles.Add(_azureStorage.UploadFileByContainer(id, stream, "res", FileName + "/" + name, false)
+                        .ContinueWith((Task<AzureBlobModel> blob) =>
+                        {
+                            str.url = blob.Result.BlobUrl;
+                        })
+                        );
+                }
+                else
+                {
+                    str.url = store.url;
+                }
+                dict.TryAdd(key, str);
+            }
+            await Task.WhenAll(tasksFiles);
+            hTEX.stores = dict;
+            hTEX.slides = slds;
+            var blob=  await _azureStorage.UploadFileByContainer(id, JsonHelper.ToJson(hTEX, ignoreNullValue: false), "res", FileName + "/" + "index.json", false);
+            return blob.BlobUrl;
+        }
+
+
+    }
+
+    public class HTEX {
+        public string id { get; set; }
+        public string version { get; set; } = "1.0.20201210";
+        public string name { get; set; }
+        public HTEXLib.HtexSize size { get; set; }
+        public List<Sld> slides { get; set; }
+        //缩略图
+        public string thumbnail { get; set; }
+        //  public int page { get; set; }
+        public Dictionary<string, Store> stores { get; set; }
+        public List<string> points { get; set; }
+        public string periodId { get; set; }
+        public List<string> gradeIds { get; set; }
+        public string subjectId { get; set; }
+        public string subjectName { get; set; }
+        public string score { get; set; }
+        public string code { get; set; }
+        public string scope { get; set; }
+        public int? multipleRule { get; set; }
+    }
+    public class Sld {
+        /// <summary>
+        /// normal,普通的hte页面 single 单选题 multiple 多选题 judge 判断题 complete 填空题 subjective 问答题 compose 综合题 
+        /// </summary>
+        public string type { get; set; }
+        /// <summary>
+        /// 单页PPTx htex 的解析链接或一个题目的链接
+        /// </summary>
+        public string url { get; set; }
+        /// <summary>
+        /// 题目的配分,如果为type为normal 及compose ,则 scoring=null
+        /// </summary>
+        public Scoring scoring { get; set; }
+        /// <summary>
+        /// 单页PPTx htex 的缩略图
+        /// </summary>
+        public string thumbnail { get; set; }
+    }
+
+    public class Scoring { 
+        public double score { get; set; }
+        public List<string> ans { get; set; } = new List<string>();
     }
 }

+ 2 - 2
TEAMModelOS/TEAMModelOS.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
+<Project Sdk="Microsoft.NET.Sdk.Web">
 
   <PropertyGroup>
     <TargetFramework>netcoreapp3.1</TargetFramework>
@@ -6,7 +6,7 @@
   <ItemGroup>
     <PackageReference Include="Caching.CSRedis" Version="3.6.50" />
     <PackageReference Include="CSRedisCore" Version="3.6.5" />
-    <PackageReference Include="HTEXLib" Version="1.0.9" />
+    <PackageReference Include="HTEXLib" Version="1.1.1" />
     <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" />
       <PackageReference Include="VueCliMiddleware" Version="3.1.2" />  </ItemGroup>
   <PropertyGroup>