Browse Source

Merge branch 'develop' of http://163.228.141.122:3000/TEAMMODEL/TEAMModelOS into develop

jeff 6 months ago
parent
commit
1a076e3ed6

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

@@ -1642,6 +1642,15 @@ const LANG_EN_US = {
             tip13: 'Switching  will clear the current answers setting, do you confirm to switch? ',
             onlyUpper: 'Only capital letters can be entered for objective questions.',
             modifyPaper: 'Modify',
+            paperNum: 'Number of test papers created in batches',
+            handScore: 'Manual allocation',
+            relateTag: 'Related tag',
+            addQuesTips: 'Create up to 100 questions',
+            tip14: 'No key concept selected for the question! ',
+            tip15: 'The total score of the test paper is inconsistent with allocation',
+            tip16: 'Question',
+            tip17: ' was not found, or the number of questions queried is less than the required number of questions, please resetting',
+            tip18: 'Not saved successfully',
         },
         secretTip1: 'Not public yet',
         secretTip2: 'Checking the box means that only the school administrators and I can see this exam file',
@@ -5705,6 +5714,15 @@ const LANG_EN_US = {
             wrong: "Class Incorrect Rate",
             wrongNum: "No. of Incorrect",
             gneratingPDF: 'Generating PDF...',
+            uploadWrong: 'Download wrong question set',
+            ansPosition: 'Answer position',
+            followQues: 'Follow the question',
+            pdfEnd: 'End of PDF',
+            tips1: 'Currenly number of wrong questions is',
+            tips2: ', print up to 50 questions',
+            tips3: 'Failed to obtain school information, please download again',
+            pdfName: 'Wrong question set',
+            tips4: 'Failed to generate PDF',
         },
         myAchievement: {
             examAch: "Assessment Results",

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

@@ -1641,6 +1641,15 @@ const LANG_ZH_CN = {
             tip12: '多选题答案数与题目数不一致,请检查后重试!',
             onlyUpper:'客观题仅能输入大写字母',
             modifyPaper: '修改试卷',
+            paperNum: '批量创建试卷数量',
+            handScore: '手动配分',
+            relateTag: '关联标签',
+            addQuesTips: '最多创建100道题目',
+            tip14: '题目未选择知识点!',
+            tip15: '试卷配分与试卷总分不一致',
+            tip16: '第',
+            tip17: '题未查询到题目,或查询的题目数量少于所需题目数量,请重新配置',
+            tip18: '未保存成功',
         },
         secretTip1:'暂不公开',
         secretTip2:'勾选后保存的试卷仅有管理员及本人能看到',
@@ -5702,6 +5711,15 @@ const LANG_ZH_CN = {
             wrong: "班级错误率",
             wrongNum: "错误次数",
             gneratingPDF: '正在生成PDF...',
+            uploadWrong: '下载错题集',
+            ansPosition: '答案显示位置',
+            followQues: '跟随题目',
+            pdfEnd: '文档末尾',
+            tips1: '当前错题数量',
+            tips2: '道,最多打印50道题目',
+            tips3: '获取学校信息失败,请重新下载',
+            pdfName: '错题集',
+            tips4: '生成PDF失败',
         },
         myAchievement: {
             examAch: "评测成绩",

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

@@ -1644,6 +1644,15 @@ const LANG_ZH_TW = {
             tip13: '切換模式將會清空目前已設定的答案,是否確認切換?',
             onlyUpper: '客觀題答案僅能輸入大寫英文字母',
             modifyPaper: '修改試卷',
+            paperNum: '批次建立試卷數量',
+            handScore: '手動配分',
+            relateTag: '關聯標籤',
+            addQuesTips: '最多新建100題題目',
+            tip14: '題目未選擇知識點! ',
+            tip15: '試卷配分加總與試卷總分不一致',
+            tip16: '第',
+            tip17: '題未查詢到題目,或查詢的題目數量少於所需題目數量,請重新設定',
+            tip18: '未儲存成功',
         },
         secretTip1: '暫不公開',
         secretTip2: '勾選後儲存的試卷僅有管理員及本人能看到',
@@ -5705,6 +5714,15 @@ const LANG_ZH_TW = {
             wrong: "班級錯誤率",
             wrongNum: "錯誤次數",
             gneratingPDF: '正在產生PDF...',
+            uploadWrong: '下載錯題集',
+            ansPosition: '答案顯示位置',
+            followQues: '跟隨題目',
+            pdfEnd: 'PDF文件末端',
+            tips1: '目前錯題數',
+            tips2: '道,最多印50個題目',
+            tips3: '取得學校資訊失敗,請重新下載',
+            pdfName: '錯題集',
+            tips4: '產生PDF失敗',
         },
         myAchievement: {
             examAch: "評量成績",

+ 16 - 16
TEAMModelOS/ClientApp/src/common/BaseQuickArtPaper.vue

@@ -26,16 +26,16 @@
 				</Option>
 			</Select>
 		</div>
-		<p class="title">试卷标签
+		<p class="title">{{ $t('evaluation.paperTag') }}
 			<!-- <span style="font-size: 14px;">(所有试卷将使用同一标签)</span> -->
 		</p>
 		<Input v-model="paperInfo.tags" v-special-char :placeholder="$t('evaluation.quickPaper.tip1')" />
-		<p class="title">试卷总分
+		<p class="title">{{ $t('evaluation.exerciseList.totalScore') }}
 			<!-- <span style="font-size: 14px;">(所有试卷将使用相同总分)</span> -->
 		</p>
 		<InputNumber v-model="paperInfo.score" :max="1000" :min="1" style="width: 30%;" />
 		<p class="title">
-			<span style="margin-right: 10px;">批量创建试卷数量</span>
+			<span style="margin-right: 10px;">{{ $t('evaluation.quickPaper.paperNum') }}</span>
 			<!-- <span>份</span> -->
 		</p>
 		<InputNumber v-model="paperNum" :max="100" :min="1" style="width: 30%;"></InputNumber>
@@ -45,23 +45,23 @@
 			</p>
 			<!-- <p class="upper-tip">* {{ $t("evaluation.quickPaper.onlyUpper") }}</p> -->
 			<div class="add-type-list">
-				<span class="type-item" @click="doAddItem()">添加题目</span>
-				<span class="type-item" @click="fenpeiscore()" style="background-color: #b0b0b0;">手动配分</span>
+				<span class="type-item" @click="doAddItem()">{{ $t('evaluation.index.addExercise') }}</span>
+				<span class="type-item" @click="fenpeiscore()" style="background-color: #b0b0b0;">{{ $t('evaluation.quickPaper.handScore') }}</span>
 			</div>
 			<div class="items">
 				<div v-if="!orderItemsArr.length" style="margin: 20px 10px; color: #999999">{{ $t("evaluation.quickPaper.tip5") }}</div>
 				<div class="order-item-list" v-else>
 					<div class="order-item" v-for="(item, index) in orderItemsArr" :key="index">
 						<span class="item-type">{{ index + 1 }}</span>
-						<span>题目类型:</span>
+						<span>{{ $t('evaluation.createPaper.questype') }}:</span>
 						<Select v-model="item.type" style="width: 80px; margin: 0 10px" transfer>
-							<Option value="single">单选题</Option>
-							<Option value="multiple">多选题</Option>
-							<Option value="judge">判断题</Option>
+							<Option value="single">{{ $t('evaluation.single') }}</Option>
+							<Option value="multiple">{{ $t('evaluation.multiple') }}</Option>
+							<Option value="judge">{{ $t('evaluation.judge') }}</Option>
 						</Select>
 						<span style="margin: 0 10px">{{ $t("syllabus.score") }}:</span>
 						<InputNumber v-model="item.score" :min="1" :max="paperInfo.score"></InputNumber>
-						<span style="margin: 0 10px">关联知识点:</span>
+						<span style="margin: 0 10px">{{ $t('evaluation.exerciseList.relatePoints') }}:</span>
 						<span>
 							<Button type="info" style="margin: 6px;" @click="onSelectPoints(index)" v-if="!item.knowledge.length">{{$t('evaluation.newExercise.choosePoint')}}</Button>
 							<span v-for="(knowledge, kIndex) in item.knowledge" :key="kIndex" class="exercise-item-point">
@@ -71,7 +71,7 @@
 								</span>
 							</span>
 						</span>
-						<span style="margin: 0 10px">关联标签:</span>
+						<span style="margin: 0 10px">{{ $t('evaluation.quickPaper.relateTag') }}:</span>
 						<Select v-model="item.tags" clearable style="width: 100px; margin-right: 15px;">
 							<Option v-for="(tag, index) in tags" :value="tag" :key="index">
 								{{ tag }}
@@ -163,7 +163,7 @@
 			/* 手动添加试题 */
 			doAddItem() {
 				if (this.orderItemsArr.length > 100) {
-					this.$Message.warning('最多创建100道题目');
+					this.$Message.warning(this.$t('evaluation.quickPaper.addQuesTips'));
 					return;
 				}
 				// 新建题目,默认为单选题
@@ -267,7 +267,7 @@
 				}
 				let info = this.orderItemsArr.find(item => !item.knowledge.length)
 				if(info) {
-					this.$Message.warning('题目未选择知识点!');
+					this.$Message.warning(this.$t('evaluation.quickPaper.tip14'));
 					return;
 				}
 				let itemScore = 0
@@ -275,7 +275,7 @@
 					itemScore += item.score
 				})
 				if(itemScore != this.paperInfo.score) {
-					this.$Message.warning('试卷配分与试卷总分不一致');
+					this.$Message.warning(this.$t('evaluation.quickPaper.tip15'));
 					return;
 				}
 				/* 根据每个题目的 题型+知识点 查询相关题目,分配给每份试卷
@@ -333,7 +333,7 @@
 					if(qIndex.length) {
 						let message = qIndex.join('、')
 						this.$Message.warning({
-							content: `第${message}题未查询到题目,或查询的题目数量少于所需题目数量,请重新配置`,
+							content: `${this.$t('evaluation.quickPaper.tip16')}${message}${this.$t('evaluation.quickPaper.tip17')}`,
 							duration: 7,
 							closable: true
 						});
@@ -470,7 +470,7 @@
 						paperArr.forEach(item => {
 							message = (message ? '、' : '') + item.value
 						})
-						this.$Message.warning(`${message}未保存成功`)
+						this.$Message.warning(`${message}${this.$t('evaluation.quickPaper.tip18')}`)
 					} else {
 						this.$Message.success(this.$t('result.tip4'))
 					}

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

@@ -164,6 +164,7 @@ export default {
       }
     },
     initEditor() {
+      if(this.editor) this.editor.destroy()
       this.editorContent = ""
       let that = this
       let editor = new E(this.$refs['composeEditor' + this.index])

+ 9 - 9
TEAMModelOS/ClientApp/src/components/student-web/WrongQusetion/QuesList.vue

@@ -173,19 +173,19 @@
                 </template>
             </div>
         </Modal>
-        <Modal v-model="uploadPdf" title="下载错题集" @on-ok="uploadQues()" class="wrong-ques-modal">
+        <Modal v-model="uploadPdf" :title="$t('studentWeb.wrongTopic.uploadWrong')" @on-ok="uploadQues()" class="wrong-ques-modal">
             <div>
                 <Form label-position="top">
-                    <FormItem label="答案显示位置">
+                    <FormItem :label="$t('studentWeb.wrongTopic.ansPosition')">
                         <RadioGroup v-model="pdfAnsType">
-                            <Radio :label="0">跟随题目</Radio>
-                            <Radio :label="1">文档末尾</Radio>
+                            <Radio :label="0">{{ $t('studentWeb.wrongTopic.followQues') }}</Radio>
+                            <Radio :label="1">{{ $t('studentWeb.wrongTopic.pdfEnd') }}</Radio>
                         </RadioGroup>
                     </FormItem>
                 </Form>
             </div>
             <div v-if="topicFilterList.length > 50" style="margin-top: 20px;">
-                <Alert type="warning">当前错题数量{{ topicTotal }}道,最多打印50道题目</Alert>
+                <Alert type="warning">{{ $t('studentWeb.wrongTopic.tips1') }}{{ topicTotal }}{{ $t('studentWeb.wrongTopic.tips2') }}</Alert>
                 <!-- <Icon type="md-alert" color="orange" />
                 错题集最多打印50道题目,如果继续打印,请勾选:
                 <p><Checkbox v-model="quesNumOver">确认继续打印</Checkbox></p> -->
@@ -705,7 +705,7 @@ export default {
             let systemSub = this.courseNow.subjectList ? (this.courseNow.subjectList.find(item => item.id === this.basicSubId) || {name: ''}) : {name: ''}
             pageInfo.courseName = this.courseNow.subjectList ? systemSub.name : this.courseNow.name
             if(!pageInfo.schoolName) {
-                this.$Message.warning('获取学校信息失败,请重新下载')
+                this.$Message.warning(this.$t('studentWeb.wrongTopic.tips3'))
                 this.uploadLoading = false
                 return
             }
@@ -739,20 +739,20 @@ export default {
                             let objectUrl = window.URL.createObjectURL(blob);
                             let a = document.createElement('a');
                             a.href = objectUrl;
-                            a.download = this.userInfo.name + '错题集'
+                            a.download = this.userInfo.name + this.$t('studentWeb.wrongTopic.pdfName')
                             a.click()
                             a.remove()
                         }
                         downloadRes()
                     } else {
-                        this.$Message.warning('生成PDF失败')
+                        this.$Message.warning(this.$t('studentWeb.wrongTopic.tips4'))
                     }
                 }).finally(() => {
                     this.uploadLoading = false
                 })
             }).catch(e => {
                 console.log('99999999999999', e);
-                this.$Message.warning('生成PDF失败')
+                this.$Message.warning(this.$t('studentWeb.wrongTopic.tips4'))
                 this.uploadLoading = false
             })
         },

+ 1 - 1
TEAMModelOS/ClientApp/src/view/train/TrainDetail.vue

@@ -1139,7 +1139,7 @@ export default {
                     }
                 },
                 err => {
-                    if (res.code && res.code == 1) {
+                    if (res?.code && res.code == 1) {
                         this.$Message.error(this.$t('td.td149'))
                     } else {
                         this.$Message.error(this.$t('td.td150'))

+ 30 - 5
TEAMModelOS/Controllers/School/SchoolTeacherController.cs

@@ -70,9 +70,8 @@ namespace TEAMModelOS.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-teacher-all")]
-        [AuthToken(Roles = "teacher,admin,student")]
-
 #if !DEBUG
+        [AuthToken(Roles = "teacher,admin,student")]
         [Authorize(Roles = "IES")]
 #endif
 
@@ -86,6 +85,8 @@ namespace TEAMModelOS.Controllers
             List<ScTeacher> teachers = new List<ScTeacher>();
             try
             {
+                School school = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(school_code.GetString(), new PartitionKey("Base"));
+                List<Subject> subjects = school.period.SelectMany(c => c.subjects).ToList();
                 await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIteratorSql<ScTeacher>
                 (queryText: $"SELECT c.subjectIds, c.id, c.name,   c.picture ,c.status, c.job, c.createTime, ARRAY_LENGTH(c.permissions) as permissionCount,c.permissions,c.roles , c.size FROM c",
                 requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school_code}") }))
@@ -94,17 +95,39 @@ namespace TEAMModelOS.Controllers
                     {
                         item.createTime = item.createTime / 1000;
                     }
+                    foreach (var subId in item.subjectIds) {
+                        string sname = string.Empty;
+                        sname = subjects.Where(c => c.id.Equals(subId)).FirstOrDefault()?.name;
+                        item.subjectNames.Add(sname);
+
+                    }
                     teachers.Add(item);
                 }
 
                 if (teachers.IsNotEmpty())
                 {
                     List<IdNameCode> groupLists = new List<IdNameCode>();
-                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIteratorSql<IdNameCode>
-                        (queryText: $"SELECT c.id, c.name, m.id as code  FROM c join m in c.members  where  c.type='research' and m.id in ({string.Join(",", teachers.Select(x => $"'{x.id}'"))}) ",
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIteratorSql
+                        (queryText: $"SELECT c.id, c.name, c.year, m.id as code  FROM c join m in c.members  where  c.type='research' and m.id in ({string.Join(",", teachers.Select(x => $"'{x.id}'"))}) ",
                         requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"GroupList-{school_code}") }))
                     {
-                        groupLists.Add(item);
+                        using var json = await JsonDocument.ParseAsync(item.Content);
+                        if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                        {
+                            var accounts = json.RootElement.GetProperty("Documents").EnumerateArray();
+                            while (accounts.MoveNext())
+                            {
+                                JsonElement account = accounts.Current;
+                                groupLists.Add(account.ToObject<IdNameCode>());
+                                teachers.ForEach(x => {
+                                    if (account.TryGetProperty("year", out JsonElement year))
+                                    {
+                                        x.year = year.GetInt32();
+                                    }
+                                  
+                                });                           
+                            }
+                        }
                     }
                     if (groupLists.IsNotEmpty())
                     {
@@ -414,11 +437,13 @@ namespace TEAMModelOS.Controllers
             public List<string> permissions { get; set; }
             public List<string> roles { get; set; }
             public List<string> subjectIds { get; set; }
+            public List<string> subjectNames { get; set; } = new List<string>();
             public List<IdNameCode> groups { get; set; } = new List<IdNameCode>();
             public string note { get; set; }
             public string phone { get; set; }
             public string email { get; set; }
             public List<TEAMModelOS.SDK.Models.Teacher.TeacherArea> areas { get; set; } = new List<TEAMModelOS.SDK.Models.Teacher.TeacherArea>();
+            public int year { get; set; }
 
         }
         /// <summary>

+ 80 - 0
TEAMModelOS/Controllers/Third/XunFeiJYY/XunFeilJYYController.cs

@@ -0,0 +1,80 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK;
+using TEAMModelOS.Models;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Microsoft.AspNetCore.Authorization;
+using System.Threading.Tasks;
+using TEAMModelOS.Controllers.Third.LePei;
+using Microsoft.Azure.Amqp.Encoding;
+using System;
+using TEAMModelOS.SDK.Extension;
+using System.Text.Json;
+
+
+namespace TEAMModelOS.Controllers.Third.XunFeiJYY
+{
+    /// <summary>
+    /// 讯飞教育云
+    /// </summary>
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+    [ApiController]
+    [Route("xunfei-jjy")]
+    public class XunFeilJYYController : ControllerBase
+    {
+        public static readonly string authurl = "http://www.jyyun.com/sso-oauth/authorize";
+        public static readonly string url= "https://open.jyyun.com";
+        public static readonly string appid = "ea4e44e1dea54caba7b06bdea72970fa";
+        public static readonly string appsecret = "bb79a189fb9c22e9ae1a62b279a112c0";
+        public static readonly string apikey = "305C300D06092A864886F70D0101010500034B003048024100C362EAB80DDFD682367592DD8274A40A9FE9F37DDEC56AC8E0FBE4A5A6D9F6FDAAA495460821CA94EF4A955B582822D7BB289142F2C562FC04DA2D3B940C3D730203010001";
+        public static readonly string testuserid = "fbc284072a40da84adbe206f721b3285bc5101240c006447328c7afa3b7ae20d122a14a73144eea261756cce3e83c3f6ef940d9e8d823c7c";
+        public static readonly string testschlid = "fbc284072a40da841b643aa367013eb18a1d351ed46b0feb15f629530e2f3c1137ae30823af5c69d3b88ef0fa3c761efee102032fc5d2a5a";
+        private readonly AzureCosmosFactory _azureCosmos;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+        private readonly AzureStorageFactory _azureStorage;
+        private readonly CoreAPIHttpService _coreAPIHttpService;
+        private readonly IWebHostEnvironment _environment;
+        private readonly IConfiguration _configuration;
+        private readonly ILogger<XunFeilJYYController> _logger;
+
+        public XunFeilJYYController(ILogger<XunFeilJYYController> logger, IConfiguration configuration, IWebHostEnvironment environment, 
+            CoreAPIHttpService coreAPIHttpService, AzureStorageFactory azureStorage, DingDing dingDing, AzureCosmosFactory azureCosmos, IOptionsSnapshot<Option> option)  
+        {
+            _logger = logger;
+            _configuration = configuration;
+            _environment = environment;
+            _coreAPIHttpService = coreAPIHttpService;
+            _azureStorage = azureStorage;
+            _dingDing = dingDing;
+            _azureCosmos = azureCosmos;
+            _option = option?.Value;
+        }
+        [HttpPost("gen-sso")]
+        [AllowAnonymous]
+        public async Task<IActionResult> Sso(JsonElement json )
+        {
+            json.TryGetProperty("p", out var p);
+            if ($"{p}".Equals("xunfei-jjy-sso"))
+            {
+                string HostName = HttpContext.GetHostName();
+                if (!string.IsNullOrWhiteSpace(_option.HostName))
+                {
+                    HostName = _option.HostName;
+                }
+                string xunfei_url = $"{authurl}?appkey={appid}&redirectUri=https://{HostName}/xunfei-jjy/sso&state={DateTimeOffset.Now.ToUnixTimeMilliseconds()}&display=web";
+                return Ok(new { xunfei_url, code = 200 });
+            }
+            else 
+            {
+                return Ok(new { code = 400, msg = "参数错误" });
+            }
+           
+        }
+    }
+}