소스 검색

Merge branch 'develop' into cmy/develop-bi

chenmy 2 년 전
부모
커밋
c75863a25a
24개의 변경된 파일827개의 추가작업 그리고 156개의 파일을 삭제
  1. 86 9
      TEAMModelBI/Controllers/BISchool/SchoolController.cs
  2. 28 1
      TEAMModelOS.SDK/DI/CoreAPI/CoreAPIHttpService.cs
  3. 1 0
      TEAMModelOS.SDK/Models/Cosmos/Common/ArtEvaluation.cs
  4. 2 0
      TEAMModelOS.SDK/Models/Cosmos/Common/ArtRecord.cs
  5. 5 1
      TEAMModelOS.SDK/Models/Cosmos/Student/StudentArtResult.cs
  6. 10 0
      TEAMModelOS/ClientApp/src/access/login.js
  7. 2 2
      TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/RecordView.vue
  8. 114 4
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperViewBox/ArtView.vue
  9. 20 2
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperViewBox/PaperView.vue
  10. 22 1
      TEAMModelOS/ClientApp/src/view/Home.vue
  11. 129 85
      TEAMModelOS/ClientApp/src/view/artexam/AcQuos.vue
  12. 4 3
      TEAMModelOS/ClientApp/src/view/artexam/Create.vue
  13. 80 0
      TEAMModelOS/ClientApp/src/view/artexam/ExamData.vue
  14. 13 6
      TEAMModelOS/ClientApp/src/view/artexam/ExamSubject.vue
  15. 33 4
      TEAMModelOS/ClientApp/src/view/artexam/Mgt.vue
  16. 80 0
      TEAMModelOS/ClientApp/src/view/artexam/WorkData.vue
  17. 13 6
      TEAMModelOS/ClientApp/src/view/artexam/WorkSubject.vue
  18. 6 1
      TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue
  19. 3 2
      TEAMModelOS/ClientApp/src/view/jyzx/index.vue
  20. 1 1
      TEAMModelOS/ClientApp/src/view/settings/Index.vue
  21. 94 22
      TEAMModelOS/Controllers/Common/ExamController.cs
  22. 62 1
      TEAMModelOS/Controllers/School/ArtReviewController.cs
  23. 16 2
      TEAMModelOS/Controllers/Teacher/InitController.cs
  24. 3 3
      TEAMModelOS/TEAMModelOS.csproj

+ 86 - 9
TEAMModelBI/Controllers/BISchool/SchoolController.cs

@@ -1419,7 +1419,9 @@ namespace TEAMModelBI.Controllers.BISchool
         [HttpPost("get-assisscbase")]
         public async Task<IActionResult> GetAssistSchoolCnt(JsonElement jsonElement)
         {
-            if (!jsonElement.TryGetProperty("tmdId", out JsonElement tmdId)) return BadRequest();
+            jsonElement.TryGetProperty("tmdId", out JsonElement tmdId);
+            jsonElement.TryGetProperty("role", out JsonElement role);
+
             //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
             var cosmosClient = _azureCosmos.GetCosmosClient();
             ////分开部署,就不需要,一站多用时,取消注释
@@ -1436,7 +1438,22 @@ namespace TEAMModelBI.Controllers.BISchool
             List<ScRankCnt> scRankCnts = new();   //学校开课、上传, 课例排名
             var (start, end) = TimeHelper.GetStartOrEnd(dateTime, "month");
 
-            List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
+            List<string> schoolIds = new();
+            if (!string.IsNullOrEmpty($"{tmdId}")) 
+            {
+                switch ($"{role}")
+                {
+                    case "admin":
+                        schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}","admin");
+                        break;
+                    default:
+                        schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
+                        break;
+                }
+            }
+            else
+                schoolIds = await CommonFind.GetValueSingle(cosmosClient,"School","select value(c.id) from c","Base");
+
             if (schoolIds.Count > 0)
             {
                 string scIdSql = BICommonWay.ManyScSql("c.schoolId", schoolIds);
@@ -1497,9 +1514,11 @@ namespace TEAMModelBI.Controllers.BISchool
         public async Task<IActionResult> GetAssisSc(JsonElement jsonElement)
         {
             jsonElement.TryGetProperty("tmdId", out JsonElement tmdId);
+            jsonElement.TryGetProperty("role", out JsonElement role);
             jsonElement.TryGetProperty("schoolId", out JsonElement schooId);
             //jsonElement.TryGetProperty("site", out JsonElement site); //分开部署,就不需要,一站多用时,取消注释
             var cosmosClient = _azureCosmos.GetCosmosClient();
+
             //if ($"{site}".Equals(BIConst.Global))
             //    cosmosClient = _azureCosmos.GetCosmosClient(name: BIConst.Global);
 
@@ -1509,7 +1528,23 @@ namespace TEAMModelBI.Controllers.BISchool
             string scSql = null;
             if (!string.IsNullOrEmpty($"{tmdId}") && string.IsNullOrEmpty($"{schooId}"))
             {
-                List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
+                //List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
+                List<string> schoolIds = new();
+                if (!string.IsNullOrEmpty($"{tmdId}"))
+                {
+                    switch ($"{role}")
+                    {
+                        case "admin":
+                            schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}", "admin");
+                            break;
+                        default:
+                            schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
+                            break;
+                    }
+                }
+                else
+                    schoolIds = await CommonFind.GetValueSingle(cosmosClient, "School", "select value(c.id) from c", "Base");
+
                 if (schoolIds.Count == 0) return Ok(new { state = RespondCode.Ok, yearCnts, });
                 scSql = BICommonWay.ManyScSql("c.school", schoolIds);
             }
@@ -1551,7 +1586,8 @@ namespace TEAMModelBI.Controllers.BISchool
         [HttpPost("get-assissccnt")]
         public async Task<IActionResult> GetAssisScCnt(JsonElement jsonElement)
         {
-            if (!jsonElement.TryGetProperty("tmdId", out JsonElement tmdId)) return BadRequest();
+            jsonElement.TryGetProperty("tmdId", out JsonElement tmdId);
+            jsonElement.TryGetProperty("role", out JsonElement role);
             //jsonElement.TryGetProperty("site", out JsonElement site); //分开部署,就不需要,一站多用时,取消注释
             var cosmosClient = _azureCosmos.GetCosmosClient();
             //if ($"{site}".Equals(BIConst.Global))
@@ -1562,6 +1598,7 @@ namespace TEAMModelBI.Controllers.BISchool
             var (years, yeare) = TimeHelper.GetStartOrEnd(dateTime, "year");
             var (lastYears, lastYeare) = TimeHelper.GetStartOrEnd(dateTime, "lastYear");
 
+
             int lessAll = 0;  //所以课例
             int lessLastdayCnt = 0;  //昨天的课例
             int lessDayCnt = 0;    //今天的课例
@@ -1580,7 +1617,22 @@ namespace TEAMModelBI.Controllers.BISchool
             int lastYearActCnt = 0;       //去年活动
             int yearActCnt = 0;       //今年活动
 
-            List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
+            List<string> schoolIds = new();
+            if (!string.IsNullOrEmpty($"{tmdId}"))
+            {
+                switch ($"{role}")
+                {
+                    case "admin":
+                        schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}", "admin");
+                        break;
+                    default:
+                        schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
+                        break;
+                }
+            }
+            else
+                schoolIds = await CommonFind.GetValueSingle(cosmosClient, "School", "select value(c.id) from c", "Base");
+
             if (schoolIds.Count > 0)
             {
 
@@ -1706,7 +1758,8 @@ namespace TEAMModelBI.Controllers.BISchool
         [HttpPost("get-proded")]
         public async Task<IActionResult> GetProdEd(JsonElement jsonElement)
         {
-            if (!jsonElement.TryGetProperty("tmdId", out JsonElement tmdId)) return Ok(new { state = RespondCode.ParamsError, nsg = "参数错误" });
+            jsonElement.TryGetProperty("tmdId", out JsonElement tmdId);
+            jsonElement.TryGetProperty("role", out JsonElement role);
             //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
             var cosmosClient = _azureCosmos.GetCosmosClient();
             ////分开部署,就不需要,一站多用时,取消注释
@@ -1717,7 +1770,22 @@ namespace TEAMModelBI.Controllers.BISchool
             int allCnt = 0;
             List<ScProdEd> scInfos = new();
             List<string> products = new();
-            List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
+            //List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
+            List<string> schoolIds = new();
+            if (!string.IsNullOrEmpty($"{tmdId}"))
+            {
+                switch ($"{role}")
+                {
+                    case "admin":
+                        schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}", "admin");
+                        break;
+                    default:
+                        schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
+                        break;
+                }
+            }
+            else
+                schoolIds = await CommonFind.GetValueSingle(cosmosClient, "School", "select value(c.id) from c", "Base");
 
             if (schoolIds.Count > 0)
             {
@@ -2054,7 +2122,6 @@ namespace TEAMModelBI.Controllers.BISchool
             else { return Ok(new { status = 201, msg = $"{_tmdName}【{_tmdId}】账号不是顾问" }); }
         }
 
-
         /// <summary>
         /// 管理员所管理的学校信息
         /// </summary>
@@ -2069,6 +2136,7 @@ namespace TEAMModelBI.Controllers.BISchool
 
             var cosmosClient = _azureCosmos.GetCosmosClient();
             List<ManageScInfo> mScInfos = new();
+            List<ManageScInfo> noScInfos = new();
             List<string> scIds = new();
 
             string mScSql = $"SELECT value(REPLACE(c.code, 'Teacher-', '')) FROM c where array_contains(c.roles,'admin',true) and c.pk='Teacher' and c.id='{tmdId}'";
@@ -2090,7 +2158,16 @@ namespace TEAMModelBI.Controllers.BISchool
                 mScInfos = await CommonFind.GetObject<ManageScInfo>(cosmosClient, "School", scSql, "Base");
             }
 
-            return Ok(new { state = RespondCode.Ok, mScInfos });
+            if (!string.IsNullOrEmpty($"{areaId}")) 
+            {
+                string noScInfoSql = $"select c.id,c.name,c.code,c.picture,c.region,c.province,c.city,c.dist,c.areaId from c where c.areaId='{areaId}'";
+                List<ManageScInfo> areaAllScInfos = await CommonFind.GetObject<ManageScInfo>(cosmosClient, "School", noScInfoSql, "Base");
+
+                noScInfos = areaAllScInfos.Where(w => !mScInfos.Any(a => a.id == w.id)).ToList();
+                //noScInfos = areaAllScInfos.Except(mScInfos).ToList();
+            }
+
+            return Ok(new { state = RespondCode.Ok, mScInfos, noScInfos });
         }
         
         /// <summary>

+ 28 - 1
TEAMModelOS.SDK/DI/CoreAPI/CoreAPIHttpService.cs

@@ -126,8 +126,30 @@ namespace TEAMModelOS.SDK
                 "eventName":"",
                 "data":""action":{"type":"click\link","tokenbindtype":1,"url":"http://xxxx"}"
             }
+
+            {
+                "action":[ //陣列, 可以包含多個按鈕
+                    {
+                        "type":"click", //按鈕
+                        "label":"Ok", //按鈕的字
+                        "url":"https://www.teammodel.net?code=", // POST API
+                        "tokenbindtype":1 //附掛 code token到 utl 後面
+                    }
+                ]
+            }
+            {
+                "action": [
+                    {
+                        "type": "click",
+                        "label": "\\u67e5\\u770b",
+                        "url": "https:\\/\\/sokrates.teammodel.org\\/exhibition\\/tbavideo\\/check-with-habook\\/?to=aHR0cHM6Ly9zb2tyYXRlcy50ZWFtbW9kZWwub3JnL2V4aGliaXRpb24vdGJhdmlkZW8jL2NvbnRlbnQvMTM5MzU\\/Z3JvdXBJZHM9MTQxJmNoYW5uZWxJZD0xMzA=&ticket=",
+                        "tokenbindtype": 1
+                    }
+                ]
+            }
             */
-            try {
+            try
+            {
                 string lang = location.Contains("China") ? "zh-cn" : "en-us";
                 toTeachers.FindAll(x => string.IsNullOrWhiteSpace(x.code) || (!x.code.Equals("zh-cn") && !x.code.Equals("zh-tw") && !x.code.Equals("en-us"))).ForEach(x => { x.code = lang; });
                 var groups = toTeachers.GroupBy(x => x.code).Select(x => new { x.Key, list = x.ToList() });
@@ -163,6 +185,11 @@ namespace TEAMModelOS.SDK
                         
                         if (msgs.IsNotEmpty())
                         {
+                          //  ExpandoObject()
+                            //处理action
+                            if (notifyCode.Equals("request_school") || notifyCode.Equals("invite_school")) { 
+                                
+                            }
                             var tags = group.list.Select(x => $"{x.id}_{notifyType}");
                             NotifyData notifyData = new NotifyData
                             {

+ 1 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/ArtEvaluation.cs

@@ -75,6 +75,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
     }
     public class Acs {
         public string acId { get; set; }
+        public string name { get; set; }
         public string subject { get; set; }
         public int? isOrder { get; set; } = 0;
         public int? type { get; set; } = 0;

+ 2 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/ArtRecord.cs

@@ -12,6 +12,8 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
         {
             pk = "ArtRecord";
         }
+        public string artId { get; set; }
+        public string quotaId { get; set; }
         public string acId { get; set; }
         public string subject { get; set; }
         public string stuId { get; set; }

+ 5 - 1
TEAMModelOS.SDK/Models/Cosmos/Student/StudentArtResult.cs

@@ -47,9 +47,13 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public string quotaName { get; set; }
         /// <summary>
+        /// 指标类型-1未设定 0评分,1评测,2作业
+        /// </summary>
+        public int quotaType { get; set; }
+        /// <summary>
         /// 分数
         /// </summary>
-        public double score { get; set; }
+        public double score { get; set; } = -1;
         /// <summary>
         /// 上传的文件
         /// </summary>

+ 10 - 0
TEAMModelOS/ClientApp/src/access/login.js

@@ -17,6 +17,16 @@ export default {
 				let teacherInfo = await $api.login.getTeacherInfo({ id_token: id_token })
 				localStorage.setItem("auth_token", teacherInfo.auth_token)
 				localStorage.setItem("location", teacherInfo.location)
+				console.error(teacherInfo.lang)
+				if (teacherInfo.lang) {
+					app.$tools.changeLang(teacherInfo.lang)
+					$store.commit("setLanguage", teacherInfo.lang);
+					if (localStorage.getItem("cloudSetting")) {
+						let setting = JSON.parse(localStorage.getItem("cloudSetting"));
+						setting.curLang = teacherInfo.lang
+						localStorage.setItem('cloudSetting', JSON.stringify(setting))
+					}
+				}
 				$store.dispatch('user/setUserProfile', teacherInfo)
 				// 检查老师是否加入了学校 再去设定需要去获取哪个学校的基础信息
 				let hasJoinSchool = teacherInfo.schools && teacherInfo.schools.length && teacherInfo.schools.find(i => i.status === 'join')

+ 2 - 2
TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/RecordView.vue

@@ -42,10 +42,10 @@
                         <Icon custom="iconfont icon-zuopin" size="16" />
                         {{ $t('studentWeb.courseContent.myWorks') }}
                     </Button> -->
-                    <!-- <Button type="primary" @click="showNote = true" v-if="recordInfo.myNote.length">
+                    <Button type="primary" @click="showNote = true" v-if="recordInfo.myNote.length">
                         <Icon custom="iconfont icon-myNote" size="17" />
                         {{ $t('studentWeb.courseContent.mynotes') }}
-                    </Button> -->
+                    </Button>
                     <Button type="primary" @click="viewENote">
                         <Icon custom="iconfont icon-activityT" />
                         {{ $t('studentWeb.courseContent.notes') }}

+ 114 - 4
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperViewBox/ArtView.vue

@@ -13,8 +13,23 @@
                     <p>{{ $t('jyzx.offline.submitFile') }}:
                         <!-- <span style="float: right; margin-right: 10px; color: #4e77b1; cursor: pointer;" @click="deleteFile">{{ $t("cusMgt.delBatch") }}</span> -->
                     </p>
-                    <div>
-                        <Table :ref="{'selection': true}" :columns="fileCol" :data="hwInfo.answer.attachments" @on-selection-change="selectionChange">
+                        <div class="file-show">
+                            <div v-for="(item, index) in hwInfo.answer.attachments" :key="index" class="one-show">
+                                <div class="repair-link-wrap-item-box">
+                                    <div class="file-icon">
+                                        <img :src="$tools.getFileThum(item.type, item.name)"/>
+                                    </div>
+                                    <div class="file-info">
+                                        <p class="file-name">{{ item.name }}</p>
+                                        <div>
+                                            <span @click="onPreview(item)" v-if="item.type !== 'other'">{{ $t('ability.review.preview')}}</span>
+                                            <span @click="onDownload(item)" v-if="item.type !== 'link'">{{ $t('ability.review.download')}}</span>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                        <!-- <Table :ref="{'selection': true}" :columns="fileCol" :data="hwInfo.answer.attachments" @on-selection-change="selectionChange">
                             <template slot-scope="{row}" slot="name">
                                 <span v-show="row.prime" class="school-gade" style="display: inline-block; background: #a2b02e;">{{ $t("jyzx.offline.mainFile") }}</span>
                                 {{ row.name }}
@@ -22,8 +37,7 @@
                             <template slot-scope="{row}" slot="action">
                                 <Icon type="md-download" size="20" @click="loadAttach(row)" :title="$t('jyzx.offline.upload')" />
                             </template> 
-                        </Table>
-                    </div>
+                        </Table> -->
                 </div>
                 <Upload
                     multiple
@@ -130,6 +144,11 @@ export default {
         ...mapState({
             userInfo: state => state.userInfo
         }),
+        getSuffix() {
+            return name => {
+                return name.substr(name.lastIndexOf(".") + 1)
+            }
+        }
     },
     watch: {
         hwInfo: {
@@ -235,6 +254,8 @@ export default {
                     let params = {
                         acId: this.hwInfo.id,
                         subject: this.hwInfo.subject,
+                        artId: this.getItemTitle.id,
+                        quotaId: this.hwInfo.quotaId,
                         attachments: content,
                     }
                     // 如果是重新上传,要再传一个works里面的id
@@ -313,6 +334,30 @@ export default {
                 }
             })
         },
+        /* 预览 */
+        async onPreview(item){
+            console.log(item);
+            let url = item.url
+            if (this.getSuffix(item.name) === 'pdf') {
+                window.open('/web/viewer.html?file=' + encodeURIComponent(url));
+            } else if(item.type === 'doc') {
+                window.open('https://view.officeapps.live.com/op/view.aspx?src=' + escape(url));
+            } else if(item.type === 'image') {
+                this.$hevueImgPreview(url)
+            } else if(item.type === 'link') {
+				window.open(/^(http:|https:)/i.test(url) ? url : "http://" + url)
+            } else {
+                console.log(1111111111111);
+                this.previewFile = item
+                this.previewStatus = true
+                console.log(this.previewFile.type);
+            }
+        },
+
+        /* 下载 */
+        async onDownload(item){
+            this.$tools.doDownloadByUrl(item.url, item.name)
+        },
     }
 }
 </script>
@@ -322,4 +367,69 @@ export default {
     margin-bottom: 10px;
     font-size: 16px;
 }
+
+.file-show {
+    background-color: #f1f1f1;
+    border-radius: 5px;
+    padding: 20px 25px;
+    margin-top: 10px;
+
+    .answer-show img {
+        max-width: 50% !important;
+    }
+
+    &>p {
+        font-size: 18px;
+        font-weight: bold;
+        margin-bottom: 10px;
+    }
+
+    /* .one-show{
+        display: flex;
+        justify-content: space-between;
+        padding: 0 5px 5px;
+        // padding-bottom: 5px;
+        margin-bottom: 10px;
+        // padding-left: 5px;
+        border-bottom: 1px solid #ccc;
+
+        .ivu-icon{
+            cursor: pointer;
+        }
+    } */
+
+    .repair-link-wrap-item-box {
+        display: flex;
+        position: relative;
+        // background-color: #e3e3e3;
+        border-radius: 5px;
+        padding: 10px 0;
+        font-size: 14px;
+
+        &:hover {
+            background-color: #ebe9e9;
+        }
+
+        .file-icon {
+            img {
+                width: 45px;
+            }
+        }
+
+        .file-info {
+            margin-left: 10px;
+
+            .file-name {
+                font-weight: bold;
+                margin-bottom: 5px;
+            }
+
+            span {
+                color: #16a3b5;
+                margin-right: 15px;
+                cursor: pointer;
+            }
+        }
+    }
+}
 </style>

+ 20 - 2
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperViewBox/PaperView.vue

@@ -177,12 +177,14 @@
                 hwLists: [],
                 showPaper: null,
                 nowPaperId: null, //当前科目下选择的试卷id
+                sasInfo: undefined,
             };
         },
         methods: {
-            getArtInfo() {
+            async getArtInfo() {
                 // this.artInfo = undefined
                 // this.artExam = []
+                this.sasInfo = await this.getSas()
                 let params = {
                     id: this.getItemTitle.id,
                     code: this.getItemTitle.school
@@ -208,6 +210,12 @@
                                         files = res.works.find(work => {
                                             return work.acId === task.acId
                                         })
+                                        if(files) {
+                                            files.attachments = files.attachments.map(item => {
+                                                item.url = item.url + '?' + this.sasInfo.sas
+                                                return item
+                                            })
+                                        }
                                     }
                                     // 按照科目来区分试卷
                                     let subIndex = subList.findIndex(sub => {
@@ -556,10 +564,20 @@
                 return Y + M + D + H + Min;
             },
             changeHwAnswer(answer, index) {
-                console.log(11111111111111);
+                answer.attachments = answer.attachments.map(item => {
+                    item.url = item.url + '?' + this.sasInfo.sas
+                    return item
+                })
                 this.hwLists[index].answer = answer
                 this.$forceUpdate()
             },
+            getSas() {
+                return new Promise(async (r, j) => {
+                    let code = this.getItemTitle.school
+                    let sasInfo = await this.$tools.getBlobSas(code)
+                    r(sasInfo)
+                })
+            },
             /* =====未调用===== */
             hidehint() {
                 this.ishideHint = !this.ishideHint;

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

@@ -257,7 +257,24 @@ export default {
       localStorage.setItem('msgs', JSON.stringify(this.msgs))
       console.log('端外通知', this.msgs)
     },
+    isJSON(str) {
+      if (typeof str == 'string') {
+        try {
+          var obj = JSON.parse(str);
+          if (typeof obj == 'object' && obj) {
+            return true;
+          } else {
+            return false;
+          }
+        } catch (e) {
+          return false;
+        }
+      }
+    },
     getBodyJson(str) {
+      if (!this.isJSON(str)) {
+        return false
+      }
       let reg = /\\/g;
       //使用replace方法将全部匹配正则表达式的转义符替换为空
       let replaceAfter = str.replace(reg, '').replace(/=/g, ':');
@@ -291,7 +308,11 @@ export default {
           "receiver": userId
         }).then(res => {
           if (res.length) {
-            let needMsgs = res.filter(msg => msg.data && JSON.parse(this.getBodyJson(msg.data)).value.scope)
+            let needMsgs = res.filter(msg => {
+              let jsonStr = this.getBodyJson(msg.data)
+              let bodyJson = jsonStr ? JSON.parse(jsonStr) : false
+              return bodyJson && bodyJson.value.scope
+            })
             r(needMsgs)
           } else {
             r([])

+ 129 - 85
TEAMModelOS/ClientApp/src/view/artexam/AcQuos.vue

@@ -1,109 +1,153 @@
 <template>
-    <el-tree
+	<el-tree
 		:data="treeData"
 		:props="defaultProps"
 		class="ac-quo-tree"
 		node-key="id"
 		ref="tree"
-        :render-content="renderContent"
+		:render-content="renderContent"
 		:render-after-expand="false"
-        @node-click="nodeClick"
+		@node-click="nodeClick"
 	></el-tree>
 </template>
 
 <script>
-    export default {
-        props:{
-            treeData:{
-                type:Array,
-                default:()=>{
-                    return []
-                }
-            },
-            settings:{
-                type:Array,
-                default:()=>{
-                    return []
-                }
-            }
+import ExamData from "./ExamData.vue"
+import WorkData from "./WorkData.vue"
+export default {
+    components:{
+        ExamData,WorkData
+    },
+	props: {
+		treeData: {
+			type: Array,
+			default: () => {
+				return []
+			}
+		},
+		artInfo: {
+			type: Object,
+			default: () => {
+				return {}
+			}
+		},
+		classList: {
+			type: Array,
+			default: () => {
+				return []
+			}
+		}
+	},
+	computed:{
+		subjectList(){
+			return this.artInfo?.subjects || []
+		}
+	},
+	data() {
+		return {
+			defaultProps: {
+				children: "children",
+				label: "name"
+			},
+			activeNode: undefined
+		}
+	},
+	methods: {
+        getNodeSetting(id){
+            return this.artInfo?.settings.find(item=>item.id === id)
         },
-        data(){
-            return {
-                defaultProps: {
-                    children: "children",
-                    label: "name"
-                },
-                activeNode: undefined
-            }
-        },
-        methods:{
-            nodeClick(node){
-                console.log('*****',node)
-                if(node.children.length) return
-                this.activeNode = node
-            },
-            hanldeCheckChange(){
-
-            },
-            renderContent(h, { node, data, store }) {
-                console.log(arguments)
-                let _this = this
-                // 不是最后一个节点则直接渲染label
-                if (node.childNodes.length) {
-                    return h("span", {}, node.label)
-                } else {
-                    return h(
-                        "div",
-                        {
-                            style: {
-                                width: "100%"
-                            }
-                        },
-                        [
-                            h("span", node.label),
-                            h('Tag',{
-                                class: "type-setting",
-                                props:{
-                                    color:'primary'
-                                },
-                                style: {
-                                    display: node.data.type == 1 || node.data.type == 2 ? undefined : "none"
-                                }
-                            },node.data.type == 1 ? '评测' : node.data.type == 2 ? '作业' : ''),
-                            _this.activeNode?.id == node.data.id && node.data.type === 1
-                                ? h('div', {
-                                    class:['data-wrap']    
-                                },'评测数据')
-                                : undefined,
-                            _this.activeNode?.id == node.data.id && node.data.type === 2
-                                ? h('div', {
-                                    class:['data-wrap']
-                                },'作业数据')
-                                : undefined
-                        ]
-                    )
-                }
-            },
-        }
-
-    }
+		nodeClick(node) {
+			if (node.children.length) return
+			this.activeNode = node
+		},
+		hanldeCheckChange() {},
+		renderContent(h, { node, data, store }) {
+			console.log(arguments)
+			let _this = this
+			// 不是最后一个节点则直接渲染label
+			if (node.childNodes.length) {
+				return h("span", {}, node.label)
+			} else {
+				return h(
+					"div",
+					{
+						style: {
+							width: "calc(100% - 30px)"
+						}
+					},
+					[
+						h("span", node.label),
+						h(
+							"Tag",
+							{
+								class: "type-setting",
+								props: {
+									color: "primary"
+								},
+								style: {
+									display:
+										node.data.type == 1 ||
+										node.data.type == 2
+											? undefined
+											: "none"
+								}
+							},
+							node.data.type == 1
+								? "评测"
+								: node.data.type == 2
+								? "作业"
+								: ""
+						),
+						_this.activeNode?.id == node.data.id &&
+						node.data.type === 1
+							? h(
+									ExamData,
+									{
+										class: ["data-wrap"],
+                                        props:{
+                                            taskInfo:_this.getNodeSetting(node.data.id),
+											subjectList: _this.subjectList,
+											classList: _this.classList
+                                        }
+									}
+							  )
+							: undefined,
+						_this.activeNode?.id == node.data.id &&
+						node.data.type === 2
+							? h(
+									WorkData,
+									{
+										class: ["data-wrap"],
+                                        props:{
+                                            taskInfo:_this.getNodeSetting(node.data.id),
+											subjectList: _this.subjectList,
+											classList: _this.classList
+                                        }
+									}
+							  )
+							: undefined
+					]
+				)
+			}
+		}
+	}
+}
 </script>
 
 <style lang="less" scoped>
-
 </style>
 <style lang="less">
 .ac-quo-tree .el-tree-node__content {
 	height: fit-content;
 	align-items: baseline;
 }
-.data-wrap{
-    min-height: 300px;
-    background: #f0f0f0;
-    margin: 10px 0px;
-    width: calc(100% - 10px);
+.data-wrap {
+	min-height: 300px;
+	background: #f0f0f0;
+	margin: 10px 0px;
+	width: calc(100% - 10px);
 }
-.type-setting{
-    margin-left: 10px;
+.type-setting {
+	margin-left: 10px;
 }
 </style>

+ 4 - 3
TEAMModelOS/ClientApp/src/view/artexam/Create.vue

@@ -420,12 +420,13 @@ export default {
 							}
 						)
 						for (const id of lastIds) {
+							let curNode = curSet.checked.checkedNodes.find(item=>item.id == id)
+							let type = curNode?.type || 0
 							let s = {
 								id,
+								name:curNode?.name || '',
 								task: []
 							}
-							let curNode = curSet.checked.checkedNodes.find(item=>item.id == id)
-							let type = curNode?.type || 0
 							//直接打分
 							if (type == 0) {
 								s.task.push({ type })
@@ -484,7 +485,7 @@ export default {
 					settings: settings,
 					startTime:this.artInfo.startTime,
 					endTime:this.artInfo.endTime,
-					subjects: this.subjectList.filter(item=>this.artInfo.subjects.includes(item))
+					subjects: this.subjectList.filter(item=>this.artInfo.subjects.includes(item.id))
 				}
 				this.$api.areaArt
 					.saveArt({

+ 80 - 0
TEAMModelOS/ClientApp/src/view/artexam/ExamData.vue

@@ -0,0 +1,80 @@
+<template>
+	<div class="exam-data">
+        <span>学科:</span>
+		<Select v-model="subjectId" style="width: 120px">
+			<Option
+				v-for="item in subjectList"
+				:value="item.id"
+				:key="item.id"
+				>{{ item.name }}</Option
+			>
+		</Select>
+        <span style="margin-left:10px">班级:</span>
+		<Select v-model="classId" style="width: 200px">
+			<Option
+				v-for="item in classList"
+				:value="item.id"
+				:key="item.id"
+				>{{ item.name }}</Option
+			>
+		</Select>
+	</div>
+</template>
+
+<script>
+export default {
+	props: {
+		taskInfo: {
+			type: Object,
+			default: () => {
+				return {}
+			}
+		},
+		subjectList: {
+			type: Array,
+			default: () => {
+				return []
+			}
+		},
+        classList:{
+			type: Array,
+			default: () => {
+				return []
+			}
+		},
+	},
+	data() {
+		return {
+            subjectId:'',
+            classId:''
+        }
+	},
+    watch:{
+        subjectList:{
+            immediate:true,
+            deep:true,
+            handler(n,o){
+                if(n && n.length){
+                    this.subjectId = n[0].id
+                }
+            }
+        },
+        classList:{
+            immediate:true,
+            deep:true,
+            handler(n,o){
+                if(n && n.length){
+                    this.classId = n[0].id
+                }
+            }
+        }
+    }
+}
+</script>
+
+<style lang="less" scoped>
+.exam-data{
+    padding: 5px 5px;
+    background: #f9f9f9;
+}
+</style>

+ 13 - 6
TEAMModelOS/ClientApp/src/view/artexam/ExamSubject.vue

@@ -1,16 +1,18 @@
 <template>
 	<div class="content-block">
 		<CheckboxGroup v-model="baseKn.subjects"  @on-change="handleSetKn">
-			<div class="check-item">
-				<Checkbox label="subject_painting">
+			<div class="check-item" v-show="subjects.includes('subject_painting')">
+				<!-- <Checkbox label="subject_painting">
 					<span class="subject-name">美术</span>
-				</Checkbox>
+				</Checkbox> -->
+				<span class="subject-name">美术</span>
 				<ExamSetting v-if="baseKn.subjects.includes('subject_painting')" :subject="'subject_painting'" @on-exam-change="handleExamInfo"></ExamSetting>
 			</div>
-			<div>
-				<Checkbox label="subject_music">
+			<div v-show="subjects.includes('subject_music')">
+				<!-- <Checkbox label="subject_music">
 					<span class="subject-name">音乐</span>
-				</Checkbox>
+				</Checkbox> -->
+				<span class="subject-name">音乐</span>
 				<ExamSetting v-if="baseKn.subjects.includes('subject_music')" :subject="'subject_music'" @on-exam-change="handleExamInfo"></ExamSetting>
 			</div>
 		</CheckboxGroup>
@@ -79,4 +81,9 @@ export default {
 .check-item{
     margin-bottom: 10px;
 }
+.subject-name{
+	font-weight: 600;
+	color: black;
+	margin-right: 10px;
+}
 </style>

+ 33 - 4
TEAMModelOS/ClientApp/src/view/artexam/Mgt.vue

@@ -13,7 +13,8 @@
 				</div>
 				<vuescroll>
 					<div :class="['art-item', curIndex == index ? 'art-item-active' : '']" v-for="(item,index) in artList" :key="item.id" @click="selectArt(index)">
-						<p>{{item.name}}</p>
+						<p class="art-name">{{item.name}}</p>
+						<p class="art-date"><Icon type="md-time" size="16"/>{{$jsFn.dateFormat(item.startTime)}}-{{$jsFn.dateFormat(item.endTime)}}</p>
 					</div>
 				</vuescroll>
 				<EmptyData v-show="!artList.length" :top="100"></EmptyData>
@@ -27,7 +28,7 @@
 							:label="item.label"
 							:name="item.name"
 						>
-							<AcQuos :settings="curSettings" :treeData="treeData"></AcQuos>
+							<AcQuos :artInfo="artInfo" :treeData="treeData" :classList="classList"></AcQuos>
 						</TabPane>
 					</Tabs>
 				</vuescroll>
@@ -51,7 +52,8 @@ export default {
 			curIndex:0,
 			quotas:[],
 			tabListShow:[],
-			tabList:[]
+			tabList:[],
+			classList:[]
 		}
 	},
 	computed:{
@@ -154,6 +156,7 @@ export default {
 			)
 		},
 		findArtSummary(){
+			this.classList = []
 			let params = {
 				id:this.artList[this.curIndex].id,
 				code: this.$store.state.userInfo.schoolCode
@@ -167,10 +170,27 @@ export default {
 					if(this.tabListShow.length){
 						this.tabName = this.tabListShow[0].name
 					}
+					if(this.artInfo?.classes){
+						this.getClassList()
+					}
 				},
 				(err) => {}
 			)
-		}
+		},
+		getClassList(){
+			let req = {
+                ids: this.artInfo.classes,
+                schoolId: this.$store.state.userInfo.schoolCode
+            }
+            this.$api.common.getGroupListByIds(req).then(
+				res=>{
+					this.classList = res.groups
+				},
+				err=>{
+					this.$Message.error('获取班级列表失败')
+				}
+			)
+		},
 	},
 	created(){
 		this.getAreaSetting()
@@ -179,6 +199,15 @@ export default {
 </script>
 
 <style lang="less" scoped>
+.art-name{
+	font-weight: 500;
+	font-size: 15px;
+	color: #17233d;
+}
+.art-date{
+	margin-top: 5px;
+	color: #808695;
+}
 .art-content{
 	padding-left: 10px;
 }

+ 80 - 0
TEAMModelOS/ClientApp/src/view/artexam/WorkData.vue

@@ -0,0 +1,80 @@
+<template>
+	<div class="work-data">
+        <span>学科:</span>
+		<Select v-model="subjectId" style="width: 120px">
+			<Option
+				v-for="item in subjectList"
+				:value="item.id"
+				:key="item.id"
+				>{{ item.name }}</Option
+			>
+		</Select>
+        <span style="margin-left:10px">班级:</span>
+		<Select v-model="classId" style="width: 200px">
+			<Option
+				v-for="item in classList"
+				:value="item.id"
+				:key="item.id"
+				>{{ item.name }}</Option
+			>
+		</Select>
+    </div>
+</template>
+
+<script>
+export default {
+    props:{
+        taskInfo:{
+            type: Object,
+            default:()=>{
+                return {}
+            }
+        },
+        subjectList: {
+			type: Array,
+			default: () => {
+				return []
+			}
+		},
+        classList:{
+			type: Array,
+			default: () => {
+				return []
+			}
+		},
+    },
+    data(){
+        return {
+            subjectId:'',
+            classId:''
+        }
+    },
+    watch:{
+        subjectList:{
+            immediate:true,
+            deep:true,
+            handler(n,o){
+                if(n && n.length){
+                    this.subjectId = n[0].id
+                }
+            }
+        },
+        classList:{
+            immediate:true,
+            deep:true,
+            handler(n,o){
+                if(n && n.length){
+                    this.classId = n[0].id
+                }
+            }
+        }
+    }
+}
+</script>
+
+<style lang="less" scoped>
+.work-data{
+    padding: 5px 5px;
+    background: #f9f9f9;
+}
+</style>

+ 13 - 6
TEAMModelOS/ClientApp/src/view/artexam/WorkSubject.vue

@@ -1,16 +1,18 @@
 <template>
 	<div class="content-block">
 		<CheckboxGroup v-model="baseWork.subjects"  @on-change="handleSetWork">
-			<div class="check-item">
-				<Checkbox label="subject_painting">
+			<div class="check-item" v-show="subjects.includes('subject_painting')">
+				<!-- <Checkbox label="subject_painting">
 					<span class="subject-name">美术</span>
-				</Checkbox>
+				</Checkbox> -->
+				<span class="subject-name">美术</span>
 				<WorkSetting v-if="baseWork.subjects.includes('subject_painting')" subject="subject_painting" @on-set-work="handleWorkInfo"></WorkSetting>
 			</div>
-			<div>
-				<Checkbox label="subject_music">
+			<div v-show="subjects.includes('subject_music')">
+				<!-- <Checkbox label="subject_music">
 					<span class="subject-name">音乐</span>
-				</Checkbox>
+				</Checkbox> -->
+				<span class="subject-name">音乐</span>
 				<WorkSetting v-if="baseWork.subjects.includes('subject_music')" subject="subject_music" @on-set-work="handleWorkInfo"></WorkSetting>
 			</div>
 		</CheckboxGroup>
@@ -69,6 +71,11 @@ export default {
 </script>
 
 <style lang="less" scoped>
+.subject-name{
+	font-weight: 600;
+	color: black;
+	margin-right: 10px;
+}
 .check-item{
     margin-bottom: 10px;
 }

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

@@ -852,6 +852,11 @@ export default {
           if (this.isSchool && this.isSavePoints && this.evaluationInfo.createType ===
             'import') {
             if (this.importKnowledges.length) {
+              let paperItem = {
+                code: this.editPaper ? this.editPaper.code.replace('Paper-', '') : (this.isSchool ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId),
+                subjectId: this.isSchool ? this.subjectList[this.evaluationInfo.paperSubject].id : null,
+                periodId: this.isSchool ? this.schoolInfo.period[this.evaluationInfo.paperPeriod].id : null,
+              }
               this.importKnowledges.push(...refreshList.map(i => i.knowledge).flat(1))
               await this.saveImportPoints([...new Set(this.importKnowledges)], paperItem)
             }
@@ -870,7 +875,7 @@ export default {
           })
         }).catch(err => {
           console.log(err);
-          this.$Message.fail(this.$t('evaluation.paperList.saveFail'))
+          this.$Message.error(this.$t('evaluation.paperList.saveFail'))
         })
       } else {
         this.$Message.warning(this.$t('evaluation.paperList.noItemTip'))

+ 3 - 2
TEAMModelOS/ClientApp/src/view/jyzx/index.vue

@@ -389,6 +389,7 @@ export default {
                                     if(arr) {
                                         this.abliyTotal += item.total >= times ? (times * 60) : arr.view
                                         if(item.id === this.needId.abilityId) {
+                                            // 能力点总时间根据后端返回数据换取
                                             item.total = parseInt(arr.view / 60)
                                         }
                                         if(!item.done && this.setting.limitMinutes != -1 && item.total > this.setting.limitMinutes) {
@@ -425,12 +426,12 @@ export default {
                     this.abliyTotal = 0
                     this.pointList.map(item => {
                         var times = this.setting.lessonMinutes * item.hour
-                        console.log(times);
                         if(item.currency === 1) {
                             item.done = false
                             let arr = res.abilityFiles.find(abl => {return abl.abilityId === item.id})
                             // item.total = 0
                             if(arr) {
+                                // 能力点总时间根据后端返回数据换取
                                 item.total = parseInt(arr.view / 60)
                                 this.abliyTotal += item.total >= times ? (times * 60) : arr.view
                                 item.done = item.total >= times ? true : false
@@ -1358,7 +1359,7 @@ export default {
 
         // 视频开始
         startTime(video, index) {
-            this.studyTime = 0
+            this.studyTime = this.studyTime ? this.studyTime : 0
             // 不是同一个视频
             if(this.videoEle != "video" + index) {
                 this.videoEle = "video" + index

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

@@ -17,7 +17,7 @@
               <Option value="zh-tw">中文(繁體)</Option>
               <Option value="en-us">English</Option>
             </Select>
-            <Checkbox v-model="cloudSetting.isSystemLang" @on-change="onMenuStatusChange">{{ $t('settings.langCheck')}}</Checkbox>
+            <!-- <Checkbox v-model="cloudSetting.isSystemLang" @on-change="onMenuStatusChange">{{ $t('settings.langCheck')}}</Checkbox> -->
           </span>
         </div>
         <!-- <div class="normal-settings-item">

+ 94 - 22
TEAMModelOS/Controllers/Common/ExamController.cs

@@ -26,6 +26,10 @@ using System.Net.Http;
 using TEAMModelOS.SDK.DI.CoreAPI;
 using Microsoft.AspNetCore.Hosting;
 using static TEAMModelOS.SDK.SchoolService;
+using Azure.Core;
+using DocumentFormat.OpenXml.Spreadsheet;
+using DocumentFormat.OpenXml.Wordprocessing;
+using Item = TEAMModelOS.SDK.Models.Cosmos.Common.Item;
 
 namespace TEAMModelOS.Controllers
 {
@@ -47,7 +51,7 @@ namespace TEAMModelOS.Controllers
         private readonly NotificationService _notificationService;
         private readonly CoreAPIHttpService _coreAPIHttpService;
         private readonly IWebHostEnvironment _environment;
-        public ExamController(IWebHostEnvironment environment,CoreAPIHttpService coreAPIHttpService, AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing,
+        public ExamController(IWebHostEnvironment environment, CoreAPIHttpService coreAPIHttpService, AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing,
             IOptionsSnapshot<Option> option, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, NotificationService notificationService, IConfiguration configuration)
         {
             _azureCosmos = azureCosmos;
@@ -238,7 +242,8 @@ namespace TEAMModelOS.Controllers
                         }
                         exam = await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(request, request.id, new PartitionKey($"{request.code}"));
                     }
-                    else {
+                    else
+                    {
                         if (request.startTime > now)
                         {
                             request.progress = "pending";
@@ -562,8 +567,8 @@ namespace TEAMModelOS.Controllers
 
 
         [ProducesDefaultResponseType]
-/*        [Authorize(Roles = "IES")]
-        [AuthToken(Roles = "teacher,admin")]*/
+        /*        [Authorize(Roles = "IES")]
+                [AuthToken(Roles = "teacher,admin")]*/
         [HttpPost("find-by-analysis")]
         public async Task<IActionResult> FindByAnalysis(JsonElement request)
         {
@@ -649,7 +654,7 @@ namespace TEAMModelOS.Controllers
                 {
                     stringBuilder.Append($" and c.owner= '{owner}' ");
                 }
-                
+
                 if (request.TryGetProperty("year", out JsonElement yy) && !string.IsNullOrWhiteSpace($"{yy}"))
                 {
                     int end = yy.GetInt32() + 1;
@@ -725,10 +730,10 @@ namespace TEAMModelOS.Controllers
                         {
                             exams.Add(obj.ToObject<ExamInfo>());
                         }
-                    }                   
+                    }
                 }
-                var groups = exams.Where(e => null != e.examType && !string.IsNullOrWhiteSpace(e.examType.id)).GroupBy(x =>x.examType.name).Select(y => new { key = y.Key,count = y.ToList().Count}).ToList();
-                return Ok(new { examInfo, token = token, year,count = exams.Count, groups });
+                var groups = exams.Where(e => null != e.examType && !string.IsNullOrWhiteSpace(e.examType.id)).GroupBy(x => x.examType.name).Select(y => new { key = y.Key, count = y.ToList().Count }).ToList();
+                return Ok(new { examInfo, token = token, year, count = exams.Count, groups });
             }
             catch (Exception e)
             {
@@ -1131,6 +1136,7 @@ namespace TEAMModelOS.Controllers
                     }
                     else
                     {
+
                         if ($"{scope}".Equals(Constant.ScopeStudent))
                         {
                             StuActivity activity = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<StuActivity>(id.ToString(), new PartitionKey($"Activity-{school}-{userId}"));
@@ -1163,7 +1169,67 @@ namespace TEAMModelOS.Controllers
                 await _dingDing.SendBotMsg($"OS,{_option.Location},exam/upsertRecord()\n{e.Message}\n{e.StackTrace}\n\n{id.GetString()}", GroupNames.醍摩豆服務運維群組);
                 return BadRequest();
             }
+        }
+        private async Task getArtInfoAsync(CosmosClient client, string artId, string school, double score, string acId, string subject, string quotaId, string rId, string userid, string picture, string name)
+        {
+            var aresponse = await client.GetContainer("TEAMModelOS", "Common").ReadItemStreamAsync(artId, new PartitionKey($"Art-{school}"));
+            ArtEvaluation art;
+            StudentArtResult artResult;
+            if (aresponse.Status == 200)
+            {
+                using var json = await JsonDocument.ParseAsync(aresponse.ContentStream);
+                art = json.ToObject<ArtEvaluation>();
+                var response = await client.GetContainer("TEAMModelOS", "Student").ReadItemStreamAsync(rId, new PartitionKey($"ArtResult-{artId}"));
+                if (response.Status == 200)
+                {
+                    using var json_1 = await JsonDocument.ParseAsync(response.ContentStream);
+                    artResult = json_1.ToObject<StudentArtResult>();
+                    bool flage = artResult.results.Exists(a => a.taskId == acId);
+                    if (flage)
+                    {
+                        artResult.results.ForEach(r =>
+                        {
+                            r.score = score;
+                        });
+                    }
+                    else
+                    {
+                        ArtQuotaResult quotaResult = new()
+                        {
+                            taskId = acId,
+                            subjectId = subject,
+                            quotaId = quotaId,
+                            score = score,
+                        };
+                        artResult.results.Add(quotaResult);
+                    }
 
+                    await client.GetContainer("TEAMModelOS", "Student").ReplaceItemAsync(artResult, artResult.id, new PartitionKey($"{artResult.code}"));
+                }
+                else
+                {
+                    artResult = new StudentArtResult
+                    {
+                        id = rId,
+                        pk = "ArtResult",
+                        code = $"ArtResult-{artId}",
+                        studentId = userid,
+                        picture = picture,
+                        studentName = name,
+                        artId = artId,
+                        classIds = art.classes,
+                    };
+                    ArtQuotaResult quotaResult = new()
+                    {
+                        taskId = acId,
+                        subjectId = subject,
+                        quotaId = quotaId,
+                        score = score
+                    };
+                    artResult.results.Add(quotaResult);
+                    await client.GetContainer("TEAMModelOS", "Student").CreateItemAsync(artResult, new PartitionKey($"{artResult.code}"));
+                }
+            }
         }
 
         [ProducesDefaultResponseType]
@@ -1207,7 +1273,7 @@ namespace TEAMModelOS.Controllers
                         examClassResults.Add(item);
                     }
                 }
-                
+
                 ExamClassResult classResult = new ExamClassResult();
                 List<Task<ItemResponse<StuActivity>>> tasks = new List<Task<ItemResponse<StuActivity>>>();
                 //ExamInfo classResult = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"{code}"));
@@ -1734,13 +1800,14 @@ namespace TEAMModelOS.Controllers
                     fp = s.filed;
                 }
                 List<List<double>> wno = new();
-                foreach (ExamResult exam in results) {
+                foreach (ExamResult exam in results)
+                {
                     int num = 0;
                     //确定当前循环科目索引位置
                     int index = subId.IndexOf(exam.subjectId);
                     //根据索引找到试卷分数
                     List<double> points = papers[index].point;
-                    List<double> wn = await getWrongNum(exam, points,infoIds);
+                    List<double> wn = await getWrongNum(exam, points, infoIds);
                     wno.Add(wn);
                 }
                 if (papers.IsNotEmpty())
@@ -2913,7 +2980,8 @@ namespace TEAMModelOS.Controllers
                                             from = $"ies5:{_option.Location}:private",
                                             to = ids,
                                             label = $"{bizcode}_school",
-                                            body = new { 
+                                            body = new
+                                            {
                                                 location = _option.Location,
                                                 biz = bizcode,
                                                 tmdid = userid,
@@ -3264,13 +3332,15 @@ namespace TEAMModelOS.Controllers
                             List<string> sIds = account.GetProperty("studentIds").ToObject<List<string>>();
                             List<double> sum = account.GetProperty("sum").ToObject<List<double>>();
                             List<double> nsum = new();
-                            foreach (double s in sum) {
+                            foreach (double s in sum)
+                            {
                                 double ns = 0;
                                 if (s < 0)
                                 {
                                     ns = 0;
                                 }
-                                else {
+                                else
+                                {
                                     ns = s;
                                 }
                                 nsum.Add(ns);
@@ -3281,9 +3351,10 @@ namespace TEAMModelOS.Controllers
                     }
                 }
             }
-            List<(string id, string name, SDK.Models.Custom eType, string scope, string owner, long ctime, List<PaperSimple> points, List<ExamSubject> subject,string source)> exam = new();
-            if (eIds.Count == 0) {
-                return Ok(new {code = 404});
+            List<(string id, string name, SDK.Models.Custom eType, string scope, string owner, long ctime, List<PaperSimple> points, List<ExamSubject> subject, string source)> exam = new();
+            if (eIds.Count == 0)
+            {
+                return Ok(new { code = 404 });
             }
             await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIterator(
                    queryText: $"select c.id,c.name,c.examType,c.scope,c.owner,c.createTime,c.papers ,c.subjects,c.source from c where c.id in ({string.Join(",", eIds.Select(o => $"'{o}'"))})"))
@@ -3314,7 +3385,7 @@ namespace TEAMModelOS.Controllers
                             account.GetProperty("owner").GetString(), account.GetProperty("createTime").GetInt64(), ps, subs, account.GetProperty("source").GetString()));
                     }
                 }
-            }            
+            }
             var scores = classResults.Select(x => new
             {
                 examId = x.eId,
@@ -3338,7 +3409,7 @@ namespace TEAMModelOS.Controllers
                     x.examId,
                     x.examName,
                     x.cname,
-                    studentId =  stuId.GetString(),
+                    studentId = stuId.GetString(),
                     x.owner,
                     x.createTime,
                     x.eType,
@@ -3349,7 +3420,8 @@ namespace TEAMModelOS.Controllers
                 });
                 return Ok(new { info });
             }
-            else {
+            else
+            {
                 var info = scores.Where(x => !string.IsNullOrEmpty(x.examName)).Select(x => new
                 {
                     x.examId,
@@ -3365,7 +3437,7 @@ namespace TEAMModelOS.Controllers
                     x.sum
                 });
                 return Ok(new { info });
-            };           
+            };
         }
 
         //阅卷信息统计
@@ -3632,7 +3704,7 @@ namespace TEAMModelOS.Controllers
             return (ansBlob, scores);
         }
 
-        private Task<List<double>> getWrongNum(ExamResult result, List<double> points,List<string> infoIds)
+        private Task<List<double>> getWrongNum(ExamResult result, List<double> points, List<string> infoIds)
         {
             int num = 0;
             List<double> wn = new List<double>();

+ 62 - 1
TEAMModelOS/Controllers/School/ArtReviewController.cs

@@ -12,6 +12,7 @@ using Microsoft.Extensions.Options;
 using OpenXmlPowerTools;
 using System;
 using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
 using System.Linq;
 using System.Net;
 using System.Text.Json;
@@ -150,7 +151,7 @@ namespace TEAMModelOS.Controllers
                             }
                             return Ok(new { results= results, status = 1 , continuationToken });
                         }
-                    case bool when $"{_opt}".Equals("save", StringComparison.OrdinalIgnoreCase) && request.TryGetProperty("studentScore", out JsonElement _studentScore):
+                    case bool when $"{_opt}".Equals("saveScore", StringComparison.OrdinalIgnoreCase) && request.TryGetProperty("studentScore", out JsonElement _studentScore):
                         {
                             //_studentScore的结构:
                             /*
@@ -169,6 +170,39 @@ namespace TEAMModelOS.Controllers
                                 }
                             ]
                              */
+                            List<StudentArt> results = _studentScore.Deserialize<List<StudentArt>>();
+                            var valid = results.Valid();
+                            if (!valid.isVaild)
+                            {
+                                return BadRequest(valid);
+                            }
+                            var ids= results.Select(x => $"{school}-{x.studentId}").ToHashSet();
+                            if (ids.Any()) {
+                                List< StudentArtResult > studentArtResults = new List<StudentArtResult >();
+                                string sql = $"SELECT value c FROM c   where  c.pk='ArtResult'  and c.id in ( {string.Join(",", ids.Select(x => $"'{x}'"))} ) ";
+                                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, Constant.Student)
+                                    .GetItemQueryIterator<StudentArtResult>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"ArtResult-{_artId}") }))
+                                {
+                                    studentArtResults.Add(item);
+                                }
+                                studentArtResults.ForEach(x => {
+                                    var res= results.FindAll(y => $"{school}-{y.studentId}".Equals(x.id));
+                                    if (res.Any())
+                                    {
+                                        res[0].results.ForEach(re => {
+                                           var result= x.results.FindAll(z => $"{z.taskId}".Equals(re.taskId) &&$"{z.subjectId}".Equals(re.subjectId) && $"{z.quotaId}".Equals(re.quotaId));
+                                            if (result.Any())
+                                            {
+                                                result[0].score = re.score;
+                                            }
+                                        });
+                                    }
+                                });
+                                foreach (var rs in studentArtResults) {
+                                    await  client.GetContainer(Constant.TEAMModelOS, Constant.Student).ReplaceItemAsync(rs, rs.id, new PartitionKey(rs.code));
+                                }
+                                return Ok(new { results = studentArtResults, status = 1 });
+                            }
                             break;
                         }
                 }
@@ -179,4 +213,31 @@ namespace TEAMModelOS.Controllers
             return Ok();
         }
     }
+    public class StudentArt {
+        [Required(ErrorMessage = "studentId 必须设置")]
+        public string studentId { get; set; }
+        public List<ArtResult> results { get; set; } = new List<ArtResult>();
+    }
+    public class ArtResult
+    {
+        /// <summary>
+        /// 任务id
+        /// </summary>
+        [Required(ErrorMessage = "taskId 必须设置")]
+        public string taskId { get; set; }
+        /// <summary>
+        /// 科目id
+        /// </summary>
+        [Required(ErrorMessage = "subjectId 必须设置")]
+        public string subjectId { get; set; }
+        /// <summary>
+        /// 指标id
+        /// </summary>
+        [Required(ErrorMessage = "quotaId 必须设置")] 
+        public string quotaId { get; set; }
+        /// <summary>
+        /// 分数
+        /// </summary>
+        public double score { get; set; }
+    }
 }

+ 16 - 2
TEAMModelOS/Controllers/Teacher/InitController.cs

@@ -419,15 +419,29 @@ namespace TEAMModelOS.Controllers
                 var result = await table.ExecuteQuerySegmentedAsync(new TableQuery<OAuthShow>().Where(qurey), null);
                 List<OAuthShow> shows = result.Results;
                 string lang = !string.IsNullOrWhiteSpace(teacherInfo.teacher.lang) ? teacherInfo.teacher.lang : head_lang;
-                if (string.IsNullOrWhiteSpace(lang)) {
+                if (string.IsNullOrWhiteSpace(lang))
+                {
                     if (_option.Location.Contains("China"))
                     {
                         lang = "zh-cn";
                     }
-                    else {
+                    else
+                    {
                         lang = "en-us";
                     }
                 }
+                else {
+                    if (lang.Equals("null")) {
+                        if (_option.Location.Contains("China"))
+                        {
+                            lang = "zh-cn";
+                        }
+                        else
+                        {
+                            lang = "en-us";
+                        }
+                    }
+                }
                 return Ok(new
                 {
                     lang=lang,

+ 3 - 3
TEAMModelOS/TEAMModelOS.csproj

@@ -60,9 +60,9 @@
     <SpaRoot>ClientApp\</SpaRoot>
     <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
     <UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-    <Version>5.2209.7</Version>
-    <AssemblyVersion>5.2209.7.1</AssemblyVersion>
-    <FileVersion>5.2209.7.1</FileVersion>
+    <Version>5.2209.14</Version>
+    <AssemblyVersion>5.2209.14.1</AssemblyVersion>
+    <FileVersion>5.2209.14.1</FileVersion>
     <Description>TEAMModelOS(IES5)</Description>
     <PackageReleaseNotes>IES版本说明版本切换标记202200701</PackageReleaseNotes>
     <PackageId>TEAMModelOS</PackageId>