Jelajahi Sumber

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

zhouj1203@hotmail.com 1 tahun lalu
induk
melakukan
8392c80334

+ 3 - 3
TEAMModelBI/TEAMModelBI.csproj

@@ -65,9 +65,9 @@
 		<SpaRoot>ClientApp\</SpaRoot>
 		<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
 		<UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-		<Version>5.2405.8</Version>
-		<AssemblyVersion>5.2405.8.1</AssemblyVersion>
-		<FileVersion>5.2405.8.1</FileVersion>
+		<Version>5.2405.15</Version>
+		<AssemblyVersion>5.2405.15.1</AssemblyVersion>
+		<FileVersion>5.2405.15.1</FileVersion>
 		<Description>TEAMModelBI(BI)</Description>
 		<PackageReleaseNotes>BI版本说明版本切换标记2022000908</PackageReleaseNotes>
 		<PackageId>TEAMModelBI</PackageId>

+ 3 - 3
TEAMModelOS.FunctionV4/TEAMModelOS.FunctionV4.csproj

@@ -5,9 +5,9 @@
 		<OutputType>Exe</OutputType>
 		<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
 		<SignAssembly>true</SignAssembly>
-		<Version>5.2405.8</Version>
-		<AssemblyVersion>5.2405.8.1</AssemblyVersion>
-		<FileVersion>5.2405.8.1</FileVersion>
+		<Version>5.2405.15</Version>
+		<AssemblyVersion>5.2405.15.1</AssemblyVersion>
+		<FileVersion>5.2405.15.1</FileVersion>
 		<PackageId>TEAMModelOS.FunctionV4</PackageId>
 		<Authors>teammodel</Authors>
 		<Company>醍摩豆(成都)信息技术有限公司</Company>

+ 40 - 2
TEAMModelOS.SDK/Models/Cosmos/School/Knowledge.cs

@@ -74,7 +74,20 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public string subjectId { get; set; }
 
-        public string name { get; set; } 
+        public string name { get; set; }
+
+        /// <summary>
+        /// 知识点
+        /// </summary>
+        public List<string> points { get; set; } = new List<string>();
+        /// <summary>
+        /// 知识点
+        /// </summary>
+        public List<string> pointsFromTree { get; set; } = new List<string>();
+        /// <summary>
+        /// 知识块
+        /// </summary>
+        public List<Block> blocks { get; set; } = new List<Block>();
         /// <summary>
         /// 知识点属性结构的节点
         /// </summary>
@@ -88,10 +101,22 @@ namespace TEAMModelOS.SDK.Models
         public string name { get; set; }
         public string pid { get; set; }
         /// <summary>
+        ///  第三方id
+        /// </summary>
+        public string tid { get; set; }
+        public int level { get; set; }
+        /// <summary>
         /// 知识点属性结构的子节点
         /// </summary>
         public List<PointTree> children { get; set; }= new List<PointTree>();
-        public List<string> cids { get; set; } = new List<string>();
+        /// <summary>
+        /// 直接子节点
+        /// </summary>
+        public List<string> subcids { get; set; } = new List<string>();
+        /// <summary>
+        /// 所有子节点
+        /// </summary>
+        public List<string> allcids { get; set; } = new List<string>();
         /// <summary>
         /// 使用次数
         /// </summary>
@@ -154,4 +179,17 @@ namespace TEAMModelOS.SDK.Models
         ]
     }
     */
+
+    public class KnowledgeCount
+    {
+        public string owner { get; set; }
+        public string name { get; set; }
+        public string scope {  get; set; }
+        public int pcount { get; set; }
+        public int bcount { get; set; }
+        public string id { get; set; }
+        public string periodId { get; set; }
+        public string subjectId { get; set; }
+
+    }
 }

+ 192 - 6
TEAMModelOS.SDK/Models/Service/KnowledgeService.cs

@@ -10,7 +10,41 @@ namespace TEAMModelOS.SDK.Models.Service
 {
     public  sealed class KnowledgeService
     {
-        public static List<PointNode> TreeToList(List<PointTree> trees, List<PointNode> nodes/*, List<Block> blocks,HashSet<string> points*/)
+        public static List<KnowledgeTreeDto> KnowledgeTranslate(List<Knowledge> knowledges)
+        {
+            List<KnowledgeTreeDto> knowledgeTrees = new List<KnowledgeTreeDto>();
+            foreach (var knowledge in knowledges)
+            {
+                HashSet<string> points = new HashSet<string>();
+                List<Block> blocks = new List<Block>();
+                List<PointTree> tree = KnowledgeService.ListToTree(knowledge.nodes);
+                foreach (var node in tree)
+                {
+                    points.Add(node.name);
+                    blocks.Add(new Block { name=node.name, source=2, points=  node.children!=null ? node.children.Select(x => x.name).ToList() : new List<string>() });
+                    node.allcids= KnowledgeService.GetChildIds(node, points, blocks);
+                }
+                blocks.AddRange(knowledge.blocks);
+
+                knowledge.points.AddRange(points);
+                knowledgeTrees.Add(new KnowledgeTreeDto
+                {
+                    id= knowledge.id,
+                    owner=knowledge.owner,
+                    scope=knowledge.scope,
+                    periodId=knowledge.periodId,
+                    subjectId=knowledge.subjectId,
+                    name=knowledge.name,
+                    tree=tree,
+                    points=knowledge.points,
+                    pointsFromTree=points.ToList(),
+                    blocks=blocks,
+                });
+            }
+            return knowledgeTrees;
+        }
+
+        public static List<PointNode> TreeToList(List<PointTree> trees, List<PointNode> nodes, List<Block> blocks,HashSet<string> points)
         {
             List<PointNode> list = new List<PointNode>();
             trees.ForEach(x => {
@@ -29,8 +63,8 @@ namespace TEAMModelOS.SDK.Models.Service
                     link = x.link,
                 };
                 list.Add(node);
-                //blocks.Add(new Block { name= x.name,points=x.nodes.Select(x=>x.name).ToList() });
-                //points.Add(x.name);
+                blocks.Add(new Block { name= x.name, points=x.children.Select(x => x.name).ToList() });
+                points.Add(x.name);
             });
            
             nodes.AddRange(list);
@@ -39,7 +73,7 @@ namespace TEAMModelOS.SDK.Models.Service
             {
                 if (null != tree.children && tree.children.Count > 0)
                 {
-                    TreeToList(tree.children, nodes/*, blocks, points*/);
+                    TreeToList(tree.children, nodes, blocks, points);
                 }
             }
             return nodes;
@@ -74,7 +108,7 @@ namespace TEAMModelOS.SDK.Models.Service
             return trees;
         }
 
-        static  public List<string> GetChildIds(PointTree node)
+        static  public List<string> GetChildIds(PointTree node,HashSet<string> points, List<Block> blocks)
         {
             List<string> childIds = new List<string>();
             if (node.children != null)
@@ -82,12 +116,164 @@ namespace TEAMModelOS.SDK.Models.Service
                 foreach (PointTree child in node.children)
                 {
                     childIds.Add(child.id);
+                    var allcids = GetChildIds(child, points, blocks);
+                    childIds.AddRange(allcids);
+                    child.allcids=allcids.Count>100 ? child.children.Select(x => x.id).ToList() : allcids;
+                    points.Add(child.name);
+                    blocks.Add(new Block { name=child.name, source=2, points=  child.children!=null ? child.children.Select(x => x.name).ToList() : new List<string>() });
+                }
+            }
+            return childIds;
+        }
+
+
+        public static PointTree BuildTree(List<MoofenKnowledgePointDto> pointDtos)
+        {
+            var root = new PointTree();
+            var stack = new Stack<PointTree>();
+            stack.Push(root);
+            foreach (var pointDto in pointDtos)
+            {
+                var node = new PointTree
+                {
+                    id = pointDto.id,
+                    tid = pointDto.id,
+                    name = pointDto.name,
+                    level = pointDto.level
+                };
+                while (stack.Count > 0 && stack.Peek().level >= node.level)
+                {
+                    stack.Pop();
+                }
+                if (stack.Count > 0)
+                {
+                    stack.Peek().children.Add(node);
+                }
+                stack.Push(node);
+            }
+
+            if (root.level==0  && root.children.IsNotEmpty())
+            {
+
+                foreach (var node in root.children)
+                {
+                    node.subcids=node.children.Select(x => x.tid).ToList();
+                    var cids = GetChildIds(node);
+                    node.allcids=cids.Count>100 ? new List<string>() : cids;
+                }
+            }
+            return root;
+        }
+
+        static List<string> GetChildIds(PointTree node)
+        {
+            List<string> childIds = new List<string>();
+            if (node.children != null)
+            {
+                foreach (PointTree child in node.children)
+                {
+                    childIds.Add(child.tid);
                     var cids = GetChildIds(child);
                     childIds.AddRange(cids);
-                    child.cids=cids.Count>100 ? child.children.Select(x => x.id).ToList() : cids;
+                    child.allcids=cids.Count>100 ? new List<string>() : cids;
+                    child.subcids=child.children.Select(x => x.tid).ToList();
                 }
             }
             return childIds;
         }
     }
+    //public class TreeNode
+    //{
+
+
+    //    public string name { get; set; }
+    //    public string id { get; set; }
+    //    /// <summary>
+    //    ///  第三方id
+    //    /// </summary>
+    //    public string tid { get; set; }
+    //    public int level { get; set; }
+    //    /// <summary>
+    //    /// 直接子节点
+    //    /// </summary>
+    //    public List<string> subcids { get; set; } = new List<string>();
+    //    /// <summary>
+    //    /// 所有子节点
+    //    /// </summary>
+    //    public List<string> allcids { get; set; } = new List<string>();
+    //    public List<PointTree> children { get; set; } = new List<PointTree>();
+    //}
+
+    public class MoofenKnowledgePointDto
+    {
+        public string id { get; set; }
+        public string name { get; set; }
+        public int level { get; set; }
+        public string kp1 { get; set; }
+        public string kp2 { get; set; }
+        public string kp3 { get; set; }
+        public string kp4 { get; set; }
+
+
+
+    }
+    public class MoofenQuestion
+    {
+        public int difficulty { get; set; }
+        public string questionCode { get; set; }
+        public MoofenScope scope { get; set; }
+        public List<MoofenOption> options { get; set; }
+        public MoofenType @type { get; set; }
+        public string trunk { get; set; }
+        public List<MoofenQuestion> questions { get; set; }
+        /// <summary>
+        /// 填空题的答案
+        /// </summary>
+        public List<MoofenFill> items { get; set; }
+        /// <summary>
+        /// 问答题的答案
+        /// </summary>
+        public string content { get; set; }
+        public List<MoofenKnowledgePoint> kps { get; set; }
+    }
+    public class MoofenFill
+    {
+        public string content { get; set; }
+    }
+
+    public class MoofenScope
+    {
+        public MoofenGrade grade { get; set; }
+    }
+
+    public class MoofenGrade
+    {
+        public string code { get; set; }
+        public string name { get; set; }
+    }
+
+    public class MoofenOption
+    {
+        public bool correct { get; set; }
+        public string label { get; set; }
+        public string content { get; set; }
+    }
+
+    public class MoofenType
+    {
+        public string code { get; set; }
+        public string name { get; set; }
+    }
+
+    public class MoofenKnowledgePoint
+    {
+        public string kpCode { get; set; }
+        public string kpId { get; set; }
+        public string kpSetId { get; set; }
+        public string kpName { get; set; }
+        public string subCode { get; set; }
+        public int kpLevel { get; set; }
+        public string id { get; set; }
+        public string parKpId { get; set; }
+    }
 }

+ 3 - 3
TEAMModelOS.SDK/TEAMModelOS.SDK.csproj

@@ -2,9 +2,9 @@
 
 	<PropertyGroup>
 		<TargetFramework>net6.0</TargetFramework>
-		<Version>5.2405.8</Version>
-		<AssemblyVersion>5.2405.8.1</AssemblyVersion>
-		<FileVersion>5.2405.8.1</FileVersion>
+		<Version>5.2405.15</Version>
+		<AssemblyVersion>5.2405.15.1</AssemblyVersion>
+		<FileVersion>5.2405.15.1</FileVersion>
 		<PackageReleaseNotes>发版</PackageReleaseNotes>
 	</PropertyGroup>
 

+ 88 - 31
TEAMModelOS/ClientApp/src/common/BaseQuickPaper.vue

@@ -61,12 +61,12 @@
 			<div class="ans-input-wrap">
 				<div class="answer-item" v-if="paperInfo.items[0].count" style="display: flex; align-items: center">
 					<span class="type">{{ paperInfo.items[0].count > 1 ? `1 ~ ${paperInfo.items[0].count}` : "1" }}</span>
-					<Input v-model="singleAns" @mousewheel.native.prevent :type="answerInputMode === 'number' ? 'number' : 'text'" @on-keydown="onSingleInput" :placeholder="$t('evaluation.quickPaper.tip2')" />
+					<Input v-model="singleAns" @mousewheel.native.prevent :type="answerInputMode === 'number' ? 'number' : 'text'" @on-change="removeChinese($event, 0, 'single')" @on-keydown="onSingleInput" :placeholder="$t('evaluation.quickPaper.tip2')" />
 				</div>
 				<div class="answer-item" v-if="paperInfo.items[1].count">
 					<div v-for="(item, index) in paperInfo.items[1].count" :key="index" style="display: flex; align-items: center">
 						<span class="type">{{ item + paperInfo.items[0].count }}</span>
-						<Input v-model="multipleAns[index]" @mousewheel.native.prevent :type="answerInputMode === 'number' ? 'number' : 'text'" @on-keydown="onMultipleInput($event, index)" :placeholder="$t('evaluation.quickPaper.tip3')" />
+						<Input v-model="multipleAns[index]" @mousewheel.native.prevent :type="answerInputMode === 'number' ? 'number' : 'text'" @on-change="removeChinese($event, index, 'multiple')" @on-keydown="onMultipleInput($event, index)" :placeholder="$t('evaluation.quickPaper.tip3')" />
 					</div>
 				</div>
 				<div class="answer-item" v-if="paperInfo.items[2].count">
@@ -146,7 +146,7 @@
 							</span>
 						</span>
 						<span v-if="item.type !== 'subjective' || item.answerType === 'audio'">{{ $t("evaluation.quickPaper.ans") }}:</span>
-						<Input v-if="item.type !== 'subjective' || item.answerType === 'audio'" v-model="item.answer" :type="(item.type === 'single' || item.type === 'multiple') && answerInputMode === 'number' ? 'number' : 'text'" @mousewheel.native.prevent  @on-change="onOrderInputChange(item, index)" @on-keydown="onOrderInputRule($event, item, index)" :placeholder="$t('evaluation.quickPaper.tip6')" style="width: 220px; margin: 0 10px; " />
+						<Input v-if="item.type !== 'subjective' || item.answerType === 'audio'" v-model="item.answer" :type="(item.type === 'single' || item.type === 'multiple') && answerInputMode === 'number' ? 'number' : 'text'" @mousewheel.native.prevent @on-change="removeChinese($event, index, item.type)" @on-keydown="onOrderInputRule($event, item, index)" :placeholder="$t('evaluation.quickPaper.tip6')" style="width: 220px; margin: 0 10px" />
 						<span style="margin: 0 10px">{{ $t("syllabus.score") }}</span>
 						<InputNumber v-model="item.score" :min="1" :max="100"></InputNumber>
 						<span style="margin-left: 10px; cursor: pointer" @click="doRemoveItem(index)"><Icon type="md-trash" color="#FA8C16" size="18" /></span>
@@ -195,7 +195,7 @@
 		created() {
 			this.initQuickPaper();
 			this.$store.dispatch("user/getSchoolProfile").then((res) => {
-				if(res.school_base){
+				if (res.school_base) {
 					this.schoolInfo = res.school_base;
 					this.onPeriodChange(0);
 				}
@@ -225,11 +225,11 @@
 						this.orderItemsArr
 							.filter((i) => i.type === "single" || i.type === "multiple")
 							.forEach((i) => {
-								i.answer = '';
+								i.answer = "";
 							});
 					},
-					onCancel:() => {
-						this.answerInputMode = this.answerInputMode === 'code' ? 'number' : 'code'
+					onCancel: () => {
+						this.answerInputMode = this.answerInputMode === "code" ? "number" : "code";
 					}
 				});
 			},
@@ -367,7 +367,7 @@
 							type: item.type,
 							score: item.score || 10,
 							options: item.opts,
-							answer: ["single", "multiple"].includes(item.type) && this.answerInputMode === "number" ? item.answer.map((k) => k.charCodeAt() - 64).join("") : (item.type === 'single' ? item.answer[0] : item.answer.join('')),
+							answer: ["single", "multiple"].includes(item.type) && this.answerInputMode === "number" ? item.answer.map((k) => k.charCodeAt() - 64).join("") : item.type === "single" ? item.answer[0] : item.answer.join(""),
 							answerType: item.answerType,
 							answerLang: item.answerLang,
 							useAutoScore: item.useAutoScore
@@ -387,16 +387,16 @@
 			/* 针对多选强制排序 */
 			onOrderInputChange(item, index) {
 				if (item.type === "multiple") {
-					let sortVal = ''
-					if(this.answerInputMode === 'number'){
-						sortVal = item.answer
-						.replace(/[^0-9.]/g, "")
-						.split("")
-						.map((i) => Number(i))
-						.sort()
-						.join("");
-					}else{
+					let sortVal = "";
+					if (this.answerInputMode === "number") {
 						sortVal = item.answer
+							.replace(/[^0-9.]/g, "")
+							.split("")
+							.map((i) => Number(i))
+							.sort()
+							.join("");
+					} else {
+						sortVal = item.answer;
 					}
 					this.$set(this.orderItemsArr[index], "answer", sortVal);
 				}
@@ -406,7 +406,7 @@
 				console.log(e, item, index);
 				if (item.type === "single") {
 					// 判断是否为数字
-					let isNum = !isNaN(Number(e.key)) && (Number(e.key) > 0);
+					let isNum = !isNaN(Number(e.key)) && Number(e.key) > 0;
 					// 判断e.key是不是A到K的大写字母
 					let isUpperCase = /^[A-Z]+$/.test(e.key);
 					let isKeyOk = this.answerInputMode === "code" ? isUpperCase : isNum;
@@ -420,12 +420,12 @@
 						e.returnValue = true;
 					}
 				} else if (item.type === "multiple") {
-					let isNum = !isNaN(Number(e.key)) && (Number(e.key) > 0);
+					let isNum = !isNaN(Number(e.key)) && Number(e.key) > 0;
 					// 判断e.key是不是A到K的大写字母
 					let isUpperCase = /^[A-Z]+$/.test(e.key);
 					let isKeyOk = (this.answerInputMode === "code" ? isUpperCase : isNum) && e.keyCode !== 229;
-					console.error('isKeyOk',isKeyOk)
-					console.error('isKeyOk',e.key)
+					console.error("isKeyOk", isKeyOk);
+					console.error("isKeyOk", e.key);
 					let allowPress = e.key === "Backspace" || e.key === "ArrowLeft" || e.key === "ArrowRight" || e.key.includes("CapsLock");
 					let isLimitLength = item.answer.length >= item.options;
 					let isOverMax = Number(e.key) > item.options;
@@ -438,14 +438,71 @@
 					}
 				}
 			},
-			removeChinese(val){
-				console.error('val',val)
-				this.singleAns = this.singleAns.replaceAll(val.data,'')
-				console.error('val',this.singleAns)
+			codeOrder(str,type) {
+				if(type === 'single'){
+					return str
+				}
+				const order = ["A", "B", "C", "D", "E", "F", "G", "H", "I"];
+				// 创建字母到索引的映射
+				const charMap = {};
+				order.forEach((char, index) => {
+					charMap[char] = index;
+				});
+				// 将字符串转换为数组并按照指定顺序排序
+				const sortedStr = str
+					.split("")
+					.sort((a, b) => charMap[a] - charMap[b])
+					.join("");
+				return sortedStr;
+			},
+			removeChinese(val, index, type) {
+				if (!["single", "multiple"].includes(type)) return;
+				let newStrLength = val.data ? val.data.length : 0;
+				let optionLength = this.buildMode === "type" ? (type === "single" ? this.paperInfo.items[0].options : this.paperInfo.items[1].options) : this.orderItemsArr[index].options;
+				if (this.answerInputMode === "code") {
+					const allowedChars = ["A", "B", "C", "D", "E", "F", "G", "H", "I"].slice(0, optionLength);
+					const fullAnsStr = this.buildMode === "type" ? (type === "single" ? this.singleAns : this.multipleAns[index]) : this.orderItemsArr[index].answer; // 转换为大写以便匹配
+					let isDel = val.inputType === "deleteContentBackward";
+					let newStr = "";
+					if (!allowedChars.includes(val.data) && !isDel) {
+						// 如果最后输入的字符不在允许的数组中,则阻止输入
+						newStr = this.codeOrder(fullAnsStr.slice(0, -1 * newStrLength),type);
+					} else {
+						newStr = this.codeOrder(fullAnsStr,type);
+					}
+					this.$nextTick(() => {
+						if (this.buildMode === "type") {
+							if (type === "single") {
+								this.singleAns = newStr;
+							} else {
+								this.$set(this.multipleAns, index, newStr);
+							}
+						} else {
+							this.$set(this.orderItemsArr[index], "answer", newStr);
+						}
+					});
+				} else {
+					const fullAnsStr = this.buildMode === "type" ? (type === "single" ? this.singleAns.toUpperCase() : this.multipleAns[index]) : this.orderItemsArr[index].answer;
+					let sortVal = fullAnsStr
+						.replace(/[^0-9.]/g, "")
+						.split("")
+						.map((i) => Number(i))
+						.sort()
+						.join("");
+					if (this.buildMode === "type") {
+						if (type === "single") {
+							this.singleAns = fullAnsStr;
+						} else {
+							this.$set(this.multipleAns, index, sortVal);
+						}
+					} else {
+						this.$set(this.orderItemsArr[index], "answer", type === "single" ?  fullAnsStr : sortVal);
+					}
+				}
 			},
 			/* 单选答案输入监听规则 */
 			onSingleInput(e) {
-				let isNum = !isNaN(Number(e.key)) && (Number(e.key) > 0);
+				let isNum = !isNaN(Number(e.key)) && Number(e.key) > 0;
 				// 判断e.key是不是A到K的大写字母
 				let isUpperCase = /^[A-Z]+$/.test(e.key);
 				let isKeyOk = this.answerInputMode === "code" ? isUpperCase : isNum;
@@ -464,7 +521,7 @@
 			},
 			/* 多选答案输入监听规则 */
 			onMultipleInput(e, index) {
-				let isNum = !isNaN(Number(e.key)) && (Number(e.key) > 0);
+				let isNum = !isNaN(Number(e.key)) && Number(e.key) > 0;
 				// 判断e.key是不是A到K的大写字母
 				let isUpperCase = /^[A-Z]+$/.test(e.key);
 				let isKeyOk = this.answerInputMode === "code" ? isUpperCase : isNum;
@@ -494,7 +551,7 @@
 				}
 				const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/png";
 				if (!isJpgOrPng) {
-					this.$Message.warning(this.$t('cusMgt.batch.tips3'));
+					this.$Message.warning(this.$t("cusMgt.batch.tips3"));
 					return;
 				}
 				const isLt5M = file.size / 1024 / 1024 < 5;
@@ -565,9 +622,9 @@
 			/* 获取自定义模式下的试题答案 */
 			getOrderItemAnswer(item) {
 				if (item.type === "single") {
-					return this.answerInputMode === 'number' ? [String.fromCharCode(64 + parseInt(item.answer))] : [item.answer];
+					return this.answerInputMode === "number" ? [String.fromCharCode(64 + parseInt(item.answer))] : [item.answer];
 				} else if (item.type === "multiple") {
-					return this.answerInputMode === 'number' ? item.answer.split("").map((i) => String.fromCharCode(64 + parseInt(i))) : item.answer.split("");
+					return this.answerInputMode === "number" ? item.answer.split("").map((i) => String.fromCharCode(64 + parseInt(i))) : item.answer.split("");
 				} else {
 					return [item.answer];
 				}
@@ -678,7 +735,7 @@
 						this.$Message.warning(this.$t("evaluation.quickPaper.tip10"));
 						return;
 					} else {
-						console.error(this.orderItemsArr)
+						console.error(this.orderItemsArr);
 						if (this.orderItemsArr.some((i) => ["single", "multiple"].includes(i.type) && !i.answer)) {
 							this.$Message.warning(this.$t("evaluation.exerciseList.noAnswerTip"));
 							return;

+ 10 - 9
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperViewBox/PaperTest.vue

@@ -223,7 +223,7 @@
                                             <AudioRecorder :textData="checkers[index]" :index="index" @dataGet="getComposeAns" />
                                         </template>
                                         <template v-else-if="item.answerType === 'file' || item.answerType === 'image'">
-                                            <Upload type="drag" :accept="subjectiveAccept" action="" :before-upload="file => customUpload(file, index)">
+                                            <Upload type="drag" :accept="subjectiveAccept(item)" action="" :before-upload="file => customUpload(file, index)">
                                                 <div style="padding: 20px 0" ref="upload1">
                                                     <Icon type="ios-cloud-upload" size="52" :style="{color: checkers[index].length ? '#b4b4b4' : '#2d8cf0' }"></Icon>
                                                     <p>
@@ -482,7 +482,7 @@
                                         <AudioRecorder :textData="checkers[queNo]" :index="queNo" @dataGet="getComposeAns" />
                                     </template>
                                     <template v-else-if="showExam[queNo].answerType === 'file' || showExam[queNo].answerType === 'image'">
-                                        <Upload type="drag" :accept="subjectiveAccept" action="" :before-upload="file => customUpload(file, queNo)">
+                                        <Upload type="drag" :accept="subjectiveAccept(showExam[queNo])" action="" :before-upload="file => customUpload(file, queNo)">
                                             <div style="padding: 20px 0" ref="upload1">
                                                 <Icon type="ios-cloud-upload" size="52" :style="{color: checkers[queNo].length ? '#b4b4b4' : '#2d8cf0' }"></Icon>
                                                 <p>
@@ -1532,6 +1532,14 @@
                 document.getElementsByClassName("img-wrap")[0].scrollIntoView()
                 document.getElementsByClassName("instant-exam-box")[0].scrollIntoView()
             },
+            
+            subjectiveAccept(data) {
+                if(data.answerType === 'image') {
+                    return '.png, .jpg, .jpeg'
+                } else {
+                    return ''
+                }
+            },
         },
 
         watch: {
@@ -1630,13 +1638,6 @@
                     return name.substr(name.lastIndexOf(".") + 1)
                 }
             },
-            subjectiveAccept() {
-                if(this.showExam[this.queNo].answerType === 'image') {
-                    return '.png, .jpg, .jpeg'
-                } else {
-                    return ''
-                }
-            },
             instantPaper() {
                 return this.getPaperInfo.qamode === 1 || this.paperData.qamode
             },

+ 18 - 2
TEAMModelOS/ClientApp/src/view/evaluation/index/DfPage.less

@@ -36,10 +36,26 @@
         }
     }
 
+    .exercise-box {
+        display: flex;
+        height: calc(100% - 60px);
+
+        .point-tree {
+            width: calc(30% - 20px);
+            height: 800px;
+            margin: 0 10px;
+            background: #fff;
+
+            .el-tree-node__label {
+                font-size: 16px;
+            }
+        }
+    }
+
     .create-body {
-        width: 98%;
+        width: 70%;
         margin: 0px auto;
-        height: ~"calc(100% - 45px)";
+        height: 800px;
         // display: flex;
 
         .ivu-page {

+ 396 - 146
TEAMModelOS/ClientApp/src/view/evaluation/index/DfPage.vue

@@ -50,161 +50,185 @@
                 <Button @click="backToBank" class="btn-back-to-bank" icon="md-arrow-round-back" style="margin-left: 10px">{{ $t('evaluation.newExercise.backToBank')}}</Button>
             </div>
         </div>
-        <div class="create-body">
-            <div class="filter-wrap">
-                <div class="filter-item">
-                    <span class="filter-title">{{$t('evaluation.filter.grade')}}:</span>
-                    <RadioGroup v-model="filterGrade" type="button" @on-change="getDfList()">
-                        <Radio v-for="(item, index) in gradeList" :key="index" :label="index + 1" style="margin-bottom: 5px;">{{ item }}</Radio>
-                    </RadioGroup>
-                </div>
-                <div class="filter-item">
-                    <span class="filter-title">{{$t('evaluation.filter.subject')}}:</span>
-                    <RadioGroup v-model="filterSubject" type="button" @on-change="getDfList()">
-                        <Radio v-for="(item, index) in subjectList" :key="index" :label="item.id" style="margin-bottom: 5px;">{{ item.name }}</Radio>
-                    </RadioGroup>
-                </div>
-                <div class="filter-item">
-                    <span class="filter-title">{{$t('evaluation.filter.type')}}:</span>
-                    <RadioGroup v-model="filterType" type="button" @on-change="getDfList()">
-                        <Radio label="all" style="margin-bottom: 5px;">全部</Radio>
-                        <Radio v-for="(item, index) in typeList" :key="index" :label="item.id" style="margin-bottom: 5px;">{{ item.name }}</Radio>
-                    </RadioGroup>
-                </div>
-                <div class="filter-item">
-                    <span class="filter-title">{{$t('evaluation.filter.diff')}}:</span>
-                    <RadioGroup v-model="filterDiff" type="button" @on-change="getDfList()">
-                        <Radio label="all" style="margin-bottom: 5px;">全部</Radio>
-                        <Radio v-for="(item, index) in exersicesDiff" :key="index" :label="index + 1" style="margin-bottom: 5px;">{{ item }}</Radio>
-                    </RadioGroup>
-                </div>
-                <div class="filter-item" v-if="$store.state.userInfo.hasSchool">
-                    <span class="filter-title">{{$t('evaluation.filter.origin')}}:</span>
-                    <RadioGroup v-model="filterOrigin" type="button" @on-change="getDfList()">
-                        <Radio label="public" style="margin-bottom: 5px;">公共题库</Radio>
-                        <Radio label="school" style="margin-bottom: 5px;">学校题库</Radio>
-                    </RadioGroup>
-                </div>
-            </div>
-            <div class="bank-action-bar">
-                <div class="action-tools">
-                    <div class="action-tool">
-                        <Input v-model="searchVal" placeholder="输入关键词搜索试题..." style="width: 300px;" clearable search @on-search="getDfList()"></Input>
-                    </div>
-                    <div class="action-tool">
-                        <Checkbox v-model="isAllOpen" @on-change="onHandleToggle">{{ $t('evaluation.exerciseList.showAllAnswer') }}</Checkbox>
+        <div class="exercise-box">
+            <div class="point-tree">
+                <vuescroll>
+                    <div class="filter-wrap">
+                        <!-- 根据学段展示对应科目以及年级 -->
+                        <div class="filter-item">
+                            <span class="filter-title">{{$t('evaluation.filter.period')}}:</span>
+                            <RadioGroup v-model="filterFixedPeriod" type="button" @on-change="getFixedSub">
+                                <Radio v-for="(item, index) in fixedGrade" :key="index" :label="item.periodId" style="margin-bottom: 5px;">{{ item.period }}</Radio>
+                            </RadioGroup>
+                        </div>
+                        <div class="filter-item">
+                            <span class="filter-title">{{$t('evaluation.filter.subject')}}:</span>
+                            <RadioGroup v-model="filterSubject" type="button" @on-change="getPointArr()">
+                                <Radio v-for="(item, index) in fixedSubjectShow" :key="index" :label="index" style="margin-bottom: 5px;">{{ item.subject }}</Radio>
+                            </RadioGroup>
+                        </div>
                     </div>
-                </div>
-                <div class="action-tools" style="display:flex;align-items: center;">
-                    <Checkbox v-model="isSelectAll" @on-change="onSelectAll" v-if="($access.can('admin.*||exercise-upd'))">{{ $t('evaluation.choosePageItems') }}</Checkbox>
-                    <span style="margin-left:20px">
-                        {{ $t('evaluation.exerciseList.totalTip1') }}
-                        <span style="font-size: 18px;color: #ff0206;margin: 0 10px;font-weight: bold;">{{ totalNum }}</span>
-                        {{ $t('evaluation.exerciseList.unit') }}
-                    </span>
-                </div>
-            </div>
-            <div v-if="!exerciseList.length" class="no-data-text">
-                <img src="@/assets/icon/no_data_evaluation.png" width="120" />
-                <span style="margin-top: 15px; color: #808080">{{$t('evaluation.noData')}}</span>
+                    <el-tree ref="pointTree" class="tree" :data="pointList" :props="defaultProps" node-key="tid" check-on-click-node accordion highlight-current @node-click="handleNodeClick" style="height: 100%"></el-tree>
+                </vuescroll>
             </div>
-            <div v-else class="content-wrap" ref="mathJaxContainer">
-                <div class="exercise-item" v-for="(item, index) of exerciseList" :key="index" @click="onQuestionToggle(index, item.id, $event)">
-                    <!-- 题干部分 -->
-                    <div class="item-question">
-                        <div>
-                            <div class="item-question-order">{{ pageSize * (pageNum - 1) + index + 1 }} :</div>
-                            <div class="item-question-text" v-html="item.question"></div>
+            <div class="create-body">
+                <vuescroll>
+                    <div class="filter-wrap">
+                        <div class="filter-item">
+                            <span class="filter-title">{{$t('evaluation.filter.grade')}}:</span>
+                            <RadioGroup v-model="filterGrade" type="button" @on-change="getDfList()">
+                                <Radio v-for="(item, index) in gradeListShow" :key="index" :label="item" style="margin-bottom: 5px;">{{ item }}</Radio>
+                            </RadioGroup>
+                        </div>
+                        <!-- <div class="filter-item">
+                            <span class="filter-title">{{$t('evaluation.filter.subject')}}:</span>
+                            <RadioGroup v-model="filterSubject" type="button" @on-change="getDfList()">
+                                <Radio v-for="(item, index) in subjectList" :key="index" :label="item.id" style="margin-bottom: 5px;">{{ item.name }}</Radio>
+                            </RadioGroup>
+                        </div> -->
+                        <div class="filter-item">
+                            <span class="filter-title">{{$t('evaluation.filter.type')}}:</span>
+                            <RadioGroup v-model="filterType" type="button" @on-change="getDfList()">
+                                <Radio label="all" style="margin-bottom: 5px;">全部</Radio>
+                                <Radio v-for="(item, index) in typeList" :key="index" :label="item.id" style="margin-bottom: 5px;">{{ item.name }}</Radio>
+                            </RadioGroup>
+                        </div>
+                        <div class="filter-item">
+                            <span class="filter-title">{{$t('evaluation.filter.diff')}}:</span>
+                            <RadioGroup v-model="filterDiff" type="button" @on-change="getDfList()">
+                                <Radio label="all" style="margin-bottom: 5px;">全部</Radio>
+                                <Radio v-for="(item, index) in exersicesDiff" :key="index" :label="index + 1" style="margin-bottom: 5px;">{{ item }}</Radio>
+                            </RadioGroup>
+                        </div>
+                        <div class="filter-item" v-if="$store.state.userInfo.hasSchool">
+                            <span class="filter-title">{{$t('evaluation.filter.origin')}}:</span>
+                            <RadioGroup v-model="filterOrigin" type="button" @on-change="getDfList()">
+                                <Radio label="public" style="margin-bottom: 5px;">公共题库</Radio>
+                                <Radio label="school" style="margin-bottom: 5px;">学校题库</Radio>
+                            </RadioGroup>
                         </div>
-                        <span class="item-btn-toggle" style="justify-content: flex-end;">
-                            <Icon v-if="item.type !== 'compose'" :type="collapseList.indexOf(index) > -1 ? 'ios-arrow-dropup' : 'ios-arrow-dropdown'" />
-                        </span>
-                    </div>
-                    <div class="exercise-item-children" v-if="item.children.length">
-                        <BaseChild ref="childRef" :children="item.children" inBank></BaseChild>
                     </div>
-                    <!-- 选项部分 -->
-                    <div v-for="(option, optionIndex) in item.option" :key="optionIndex" class="item-options">
-                        <div class="item-option-content">
-                            <div class="item-option-order">
-                                {{ String.fromCharCode(64 + parseInt(optionIndex + 1)) }} :
+                    <div class="bank-action-bar">
+                        <div class="action-tools">
+                            <div class="action-tool">
+                                <Input v-model="searchVal" placeholder="输入关键词搜索试题..." style="width: 300px;" clearable search @on-search="getDfList()"></Input>
                             </div>
-                            <div class="item-option-text" v-html="option.value"></div>
+                            <div class="action-tool">
+                                <Checkbox v-model="isAllOpen" @on-change="onHandleToggle">{{ $t('evaluation.exerciseList.showAllAnswer') }}</Checkbox>
+                            </div>
+                        </div>
+                        <div class="action-tools" style="display:flex;align-items: center;">
+                            <Checkbox v-model="isSelectAll" @on-change="onSelectAll" v-if="($access.can('admin.*||exercise-upd'))">{{ $t('evaluation.choosePageItems') }}</Checkbox>
+                            <span style="margin-left:20px">
+                                {{ $t('evaluation.exerciseList.totalTip1') }}
+                                <span style="font-size: 18px;color: #ff0206;margin: 0 10px;font-weight: bold;">{{ totalNum }}</span>
+                                {{ $t('evaluation.exerciseList.unit') }}
+                            </span>
                         </div>
                     </div>
-                    <transition name="slide" v-if="item.type !== 'compose'">
-                        <div v-show="collapseList.indexOf(exerciseList.indexOf(item)) > -1" class="toggle-area">
-                            <div>
-                                <!-- 答案展示部分 -->
-                                <div class="item-explain">
-                                    <span class="explain-title">【{{$t('evaluation.answer')}}】</span>
-                                    <div class="item-explain-details">
-                                        <!-- 问答题答案 -->
-                                        <div v-if="item.type === 'subjective' || item.type === 'complete' || item.type === 'connector' || item.type === 'correct' ">
-                                            <span v-for="(answer, index) in item.answer" :key="index" v-html="item.answer.length ? answer : $t('evaluation.noAnswer')"></span>
-                                        </div>
-                                        <!-- 判断题答案 -->
-                                        <div v-else-if="item.type === 'judge'">
-                                            <span>{{ item.answer.length ? (item.answer[0] === 'A' ? $t('evaluation.isTrue') : $t('evaluation.isFalse')) : $t('utils.noData') }}</span>
-                                        </div>
-                                        <!-- 其余题型答案 -->
-                                        <div v-else>
-                                            <span :class="[ item.type === 'complete' ? 'item-answer-item' : '']" v-for="(answer, index) in item.answer" :key="index">{{ answer }}</span>
-                                        </div>
-                                    </div>
+                    <div v-if="!exerciseList.length" class="no-data-text">
+                        <img src="@/assets/icon/no_data_evaluation.png" width="120" />
+                        <span style="margin-top: 15px; color: #808080">{{$t('evaluation.noData')}}</span>
+                    </div>
+                    <div v-else class="content-wrap" ref="mathJaxContainer">
+                        <div class="exercise-item" v-for="(item, index) of exerciseList" :key="index" @click="onQuestionToggle(index, item.id, $event)">
+                            <!-- 题干部分 -->
+                            <div class="item-question">
+                                <div>
+                                    <div class="item-question-order">{{ pageSize * (pageNum - 1) + index + 1 }} :</div>
+                                    <div class="item-question-text" v-html="item.question"></div>
                                 </div>
-                                <!-- 解析部分 -->
-                                <div class="item-explain">
-                                    <span class="explain-title">【{{$t('evaluation.explain')}}】</span>
-                                    <div class="item-explain-details">
-                                        <span v-html="item.explain ||$t('utils.noData')"></span>
+                                <span class="item-btn-toggle" style="justify-content: flex-end;">
+                                    <Icon v-if="item.type !== 'compose'" :type="collapseList.indexOf(index) > -1 ? 'ios-arrow-dropup' : 'ios-arrow-dropdown'" />
+                                </span>
+                            </div>
+                            <div class="exercise-item-children" v-if="item.children.length">
+                                <BaseChild ref="childRef" :children="item.children" inBank></BaseChild>
+                            </div>
+                            <!-- 选项部分 -->
+                            <div v-for="(option, optionIndex) in item.option" :key="optionIndex" class="item-options">
+                                <div class="item-option-content">
+                                    <div class="item-option-order">
+                                        {{ String.fromCharCode(64 + parseInt(optionIndex + 1)) }} :
                                     </div>
+                                    <div class="item-option-text" v-html="option.value"></div>
                                 </div>
-                                <!-- 知识点部分 -->
-                                <div class="item-explain">
-                                    <span class="explain-title">【{{$t('evaluation.knowledgePoints')}}】</span>
-                                    <div class="item-explain-details">
-                                        <span v-if="!item.knowledge || !item.knowledge.length">{{ $t('utils.noData') }}</span>
-                                        <div v-else>
-                                            <span v-for="(point, index) in item.knowledge" class="item-point-tag" :key="index">
-                                                {{ point }}
-                                            </span>
+                            </div>
+                            <transition name="slide" v-if="item.type !== 'compose'">
+                                <div v-show="collapseList.indexOf(exerciseList.indexOf(item)) > -1" class="toggle-area">
+                                    <div>
+                                        <!-- 答案展示部分 -->
+                                        <div class="item-explain">
+                                            <span class="explain-title">【{{$t('evaluation.answer')}}】</span>
+                                            <div class="item-explain-details">
+                                                <!-- 问答题答案 -->
+                                                <div v-if="item.type === 'subjective' || item.type === 'complete' || item.type === 'connector' || item.type === 'correct' ">
+                                                    <span v-for="(answer, index) in item.answer" :key="index" v-html="item.answer.length ? answer : $t('evaluation.noAnswer')"></span>
+                                                </div>
+                                                <!-- 判断题答案 -->
+                                                <div v-else-if="item.type === 'judge'">
+                                                    <span>{{ item.answer.length ? (item.answer[0] === 'A' ? $t('evaluation.isTrue') : $t('evaluation.isFalse')) : $t('utils.noData') }}</span>
+                                                </div>
+                                                <!-- 其余题型答案 -->
+                                                <div v-else>
+                                                    <span :class="[ item.type === 'complete' ? 'item-answer-item' : '']" v-for="(answer, index) in item.answer" :key="index">{{ answer }}</span>
+                                                </div>
+                                            </div>
                                         </div>
-                                    </div>
-                                </div>
-                                <!-- 补救资源部分 -->
-                                <div class="item-explain" v-show="isShowAnswer">
-                                    <span class="explain-title">【{{ $t('evaluation.newExercise.repair') }}】</span>
-                                    <div class="item-explain-details">
-                                        <div v-if="item.repair && item.repair.length" style="display: flex; flex-wrap: wrap;">
-                                            <div class="repair-item" v-for="(link, index) in item.repair" :key="index">
-                                                <img :src="$tools.getFileThum(link.type, link.name)" width="20" />
-                                                <span class="repair-item-link" @click.stop="onRepairLinkClick(link)">{{ link.name }}</span>
+                                        <!-- 解析部分 -->
+                                        <div class="item-explain">
+                                            <span class="explain-title">【{{$t('evaluation.explain')}}】</span>
+                                            <div class="item-explain-details">
+                                                <span v-html="item.explain ||$t('utils.noData')"></span>
+                                            </div>
+                                        </div>
+                                        <!-- 知识点部分 -->
+                                        <div class="item-explain">
+                                            <span class="explain-title">【{{$t('evaluation.knowledgePoints')}}】</span>
+                                            <div class="item-explain-details">
+                                                <span v-if="!item.knowledge || !item.knowledge.length">{{ $t('utils.noData') }}</span>
+                                                <div v-else>
+                                                    <span v-for="(point, index) in item.knowledge" class="item-point-tag" :key="index">
+                                                        {{ point }}
+                                                    </span>
+                                                </div>
+                                            </div>
+                                        </div>
+                                        <!-- 补救资源部分 -->
+                                        <div class="item-explain" v-show="isShowAnswer">
+                                            <span class="explain-title">【{{ $t('evaluation.newExercise.repair') }}】</span>
+                                            <div class="item-explain-details">
+                                                <div v-if="item.repair && item.repair.length" style="display: flex; flex-wrap: wrap;">
+                                                    <div class="repair-item" v-for="(link, index) in item.repair" :key="index">
+                                                        <img :src="$tools.getFileThum(link.type, link.name)" width="20" />
+                                                        <span class="repair-item-link" @click.stop="onRepairLinkClick(link)">{{ link.name }}</span>
+                                                    </div>
+                                                </div>
+                                                <span v-else>{{ $t('utils.noData') }}</span>
                                             </div>
                                         </div>
-                                        <span v-else>{{ $t('utils.noData') }}</span>
                                     </div>
                                 </div>
-                            </div>
-                        </div>
-                    </transition>
-                    <!-- 底部题目操作栏 -->
-                    <div class="item-tools">
-                        <span class="item-tools-info">{{$t('evaluation.filter.grade')}}:{{ gradeList[parseInt(item.grade) - 1] }}</span>
-                        <span class="item-tools-info">{{$t('evaluation.filter.subject')}}:{{ item.subject }}</span>
-                        <span class="item-tools-info">{{$t('evaluation.filter.type')}}:{{ exersicesType[item.type] }}</span>
-                        <span class="item-tools-info">{{$t('evaluation.filter.diff')}}:{{ exersicesDiff[item.level - 1] }}</span>
+                            </transition>
+                            <!-- 底部题目操作栏 -->
+                            <div class="item-tools">
+                                <span class="item-tools-info">{{$t('evaluation.filter.grade')}}:{{ gradeList[parseInt(item.grade) - 1] }}</span>
+                                <span class="item-tools-info">{{$t('evaluation.filter.subject')}}:{{ item.subject }}</span>
+                                <span class="item-tools-info">{{$t('evaluation.filter.type')}}:{{ exersicesType[item.type] }}</span>
+                                <span class="item-tools-info">{{$t('evaluation.filter.diff')}}:{{ exersicesDiff[item.level - 1] }}</span>
 
-                        <div class="buttons" style="float:right;display:flex;flex-direction:row-reverse;align-items:center">
-                            <Button type="info" :style="{backgroundColor: selectedArr.map((i) => i.id).indexOf(item.id) > -1 ? '#bbbbbb' : '#2db7f5'}" @click.stop="handleChoose(item)">
-                                {{ids.indexOf(item.id) > -1 ? $t('evaluation.removeItem') : $t('evaluation.selectItem')}}
-                            </Button>
+                                <div class="buttons" style="float:right;display:flex;flex-direction:row-reverse;align-items:center">
+                                    <Button type="info" :style="{backgroundColor: selectedArr.map((i) => i.id).indexOf(item.id) > -1 ? '#bbbbbb' : '#2db7f5'}" @click.stop="handleChoose(item)">
+                                        {{ids.indexOf(item.id) > -1 ? $t('evaluation.removeItem') : $t('evaluation.selectItem')}}
+                                    </Button>
+                                </div>
+                            </div>
                         </div>
                     </div>
-                </div>
+                    <!-- 底部分页区域 -->
+                    <Page :total="totalNum" show-sizer show-total :page-size="pageSize" :current="pageNum" @on-page-size-change="pageSizeChange" @on-change="pageChange" :page-size-opts="[10, 20, 30]" />
+                </vuescroll>
             </div>
-            <!-- 底部分页区域 -->
-            <Page :total="totalNum" show-sizer show-total :page-size="pageSize" :current="pageNum" @on-page-size-change="pageSizeChange" @on-change="pageChange" :page-size-opts="[10, 20, 30]" />
         </div>
         <Drawer title="已选择题目" width="40" :mask-closable="false" v-model="showQues" class="select-ques">
             <!-- <RadioGroup v-model="saveType" @on-change="saveTypeChange">
@@ -381,6 +405,7 @@ export default {
         return {
             isLoading: false,
             gradeList: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级', '七年级', '八年级', '九年级', '十年级', '十一年级', '十二年级'],
+            gradeListShow: [],
             subjectList: [
                 {id: '语文', name: '语文'},
                 {id: '数学', name: '数学'},
@@ -402,8 +427,8 @@ export default {
             exersicesDiff: this.$GLOBAL.EXERCISE_DIFFS(),
             exersicesType: this.$GLOBAL.EXERCISE_TYPES(),
             exersicesField: this.$GLOBAL.EXERCISE_LEVELS(),
-            filterGrade: 1,
-            filterSubject: '语文',
+            filterGrade: '一年级',
+            filterSubject: 0,
             filterType: 'all',
             filterDiff: 'all',
             filterOrigin: 'public',
@@ -449,10 +474,20 @@ export default {
             schoolInfo: {},
             schGradeList: [], //当前学校的年级
             schSubjectList: [], //当前学校的学科
+            fixedGrade: [],
+            fixedSubject: [],
+            fixedSubjectShow: [],
+            filterFixedPeriod: 'primary',
+            pointList: [],
+            defaultProps: {
+                children: 'children',
+                label: 'name'
+            },
+            nodePoint: null,
         }
     },
     created() {
-        this.getDfList()
+        // this.getDfList()
     },
     computed: {
         ids() {
@@ -478,22 +513,161 @@ export default {
     watch: {
     },
     async mounted () {
+        this.fixedSubject = [
+            {
+                "subject": "语文",
+                "subjectId": "subject_chinese"
+            },
+            {
+                "subject": "数学",
+                "subjectId": "subject_math"
+            },
+            {
+                "subject": "英语",
+                "subjectId": "subject_english"
+            },
+            {
+                "subject": "物理",
+                "subjectId": "subject_physics"
+            },
+            {
+                "subject": "化学",
+                "subjectId": "subject_chemistry"
+            },
+            {
+                "subject": "生物",
+                "subjectId": "subject_biology"
+            },
+            {
+                "subject": "政治",
+                "subjectId": "subject_politics"
+            },
+            {
+                "subject": "历史",
+                "subjectId": "subject_history"
+            },
+            {
+                "subject": "地理",
+                "subjectId": "subject_geography"
+            },
+        ]
+        if(this.isSchool && this.$store.state.user?.schoolProfile?.school_base.period) {
+            let periodArr = ['primary', 'junior', 'senior']
+            this.$store.state.user?.schoolProfile?.school_base.period.forEach(item => {
+                if(periodArr.includes(item.periodType)) {
+                    this.fixedGrade.push({
+                        period: item.periodType === 'primary' ? '小学' : (item.periodType === 'junior' ? '初中' :  '高中'),
+                        key: item.periodType === 'primary' ? '1' : (item.periodType === 'junior' ? '2' :  '3'),
+                        periodId: item.periodType,
+                        gradeCount: item.gradeCount
+                    })
+                }
+            })
+            if(!this.fixedGrade.length) {
+                this.$Modal.confirm({
+                    content: '学段类型不符合,请设置学段类型(目前支持小学、初中、高中),当前页面将展示默认学段',
+                })
+                this.fixedGrade = [
+                    {
+                        "period": "小学",
+                        "periodId": "primary",
+                        gradeCount: 6,
+                        key: '1',
+                    },
+                    {
+                        "period": "初中",
+                        "periodId": "junior",
+                        gradeCount: 3,
+                        key: '2',
+                    },
+                    {
+                        "period": "高中",
+                        "periodId": "senior",
+                        gradeCount: 3,
+                        key: '3',
+                    }
+                ]
+            }
+        } else {
+            this.fixedGrade = [
+                {
+                    "period": "小学",
+                    "periodId": "primary",
+                    gradeCount: 6,
+                    key: '1',
+                },
+                {
+                    "period": "初中",
+                    "periodId": "junior",
+                    gradeCount: 3,
+                    key: '2',
+                },
+                {
+                    "period": "高中",
+                    "periodId": "senior",
+                    gradeCount: 3,
+                    key: '3',
+                }
+            ]
+        }
+        this.getFixedSub('primary')
         this.schoolInfo = await this.getSchoolBaseInfo()
         if(this.$store.state.userInfo.hasSchool) {
             this.onPeriodChange(0)
         }
     },
     methods: {
+        async getFixedSub(data) {
+            // 个人未加入学校,使用默认小学:1-6年级  初中:7-9九年  高中:10-12年级
+            console.log('111111', data);
+            this.filterFixedPeriod = data
+            this.filterSubject = 0
+            switch (data) {
+                case 'primary':
+                    this.fixedSubjectShow = this.fixedSubject.slice(0, 3)
+                    this.gradeListShow = this.gradeList.slice(0, this.fixedGrade[0].gradeCount === 5 ? 5 : 6)
+                    break
+                case 'junior':
+                    this.fixedSubjectShow = this.fixedSubject
+                    this.gradeListShow = this.gradeList.slice(this.fixedGrade[0].gradeCount === 5 ? 5 : 6, 9)
+                    break
+                case 'senior':
+                    this.fixedSubjectShow = this.fixedSubject
+                    this.gradeListShow = this.gradeList.slice(9, 12)
+                    break
+                default:
+                    break
+            }
+            this.filterGrade = this.gradeListShow[0]
+            this.getPointArr()
+        },
+        async getPointArr() {
+            this.isLoading = true
+            let host = this.$store.state.user.userProfile.osblob_uri
+            let url = `${host}/third/moofen/kp-${this.filterFixedPeriod}-${this.fixedSubjectShow[this.filterSubject].subjectId}.json?${this.$store.state.user.userProfile.osblob_sas}`
+            let jsonInfo = await this.$tools.getFile(url)
+            this.pointList = JSON.parse(jsonInfo)
+            this.nodePoint = `${this.filterFixedPeriod === 'primary' ? '1' : (this.filterFixedPeriod === 'junior' ? '2' :  '3')}${this.pointList[0].tid}`
+            this.$nextTick(() => {
+                this.$refs.pointTree.setCurrentKey(this.pointList[0].tid)
+            })
+            // this.isLoading = false
+            this.getDfList()
+        },
         getDfList() {
             this.isLoading = true
             let param = {
-                subject: this.filterSubject,
-                grades: this.filterGrade,
+                subject: this.fixedSubjectShow[this.filterSubject].subject,
+                grades: null,
                 // type: this.filterType,
                 // difficulty: this.filterDiff,
                 pageSize: this.pageSize,
                 currentPage: this.pageNum,
+                // hasKps: '1',
+                // kpIds: []
             }
+            param.grades = this.gradeList.findIndex(item => item === this.filterGrade) + 1
+            if(this.pointList.length) param.kpIds = [this.nodePoint]
             if(this.filterDiff != 'all') param.difficulty = this.filterDiff
             if(this.filterType != 'all') param.type = this.filterType
             if(this.searchVal) param.search = this.searchVal
@@ -740,14 +914,15 @@ export default {
                 this.$Message.warning('请完善信息')
                 return
             }
-            // 弹出框让用户选择学段、年级、学科,以及试卷名称
-            if(this.isSchool) {
-                this.selectedArr.forEach(item => {
+            this.selectedArr.forEach(item => {
+                if(this.isSchool) {
                     item.periodId = this.schoolInfo.period[this.selEvalInfo.paperPeriod].id
                     item.gradeIds = [String(this.selEvalInfo.paperGrade)]
                     item.subjectId = this.schSubjectList[this.selEvalInfo.paperSubject].id
-                })
-            }
+                }
+                item.scope = this.isSchool ? 'school' : 'private'
+                item.code = this.isSchool ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId
+            })
             console.log('开始保存');
             // 组成试卷,必要将题目保存在blob
             if(this.selEvalInfo.savetype.includes('paper')) {
@@ -1278,6 +1453,12 @@ export default {
                 }
             })
         },
+        handleNodeClick(data) {
+            if(data.id != this.nodePoint) {
+                this.nodePoint = `${this.filterFixedPeriod === 'primary' ? '1' : (this.filterFixedPeriod === 'junior' ? '2' :  '3')}${data.tid}`
+                this.getDfList()
+            }
+        },
     },
 }
 </script>
@@ -1334,4 +1515,73 @@ export default {
         }
     }
 }
+
+.point-tree {
+    .el-tree-node__label {
+        font-size: 16px;
+    }
+    .el-tree-node__content {
+        height: 35px;
+        padding-left: 0 !important;
+    }
+}
 </style>
+
+<style scoped>
+.tree /deep/ .el-tree-node {
+  position: relative;
+  padding-left: 16px;
+}
+
+.tree /deep/ .el-tree-node__children {
+  padding-left: 16px;
+}
+
+.tree /deep/ .el-tree-node :last-child:before {
+  height: 38px;
+}
+
+.tree /deep/ .el-tree > .el-tree-node:before {
+  border-left: none;
+}
+
+.tree-container /deep/ .el-tree > .el-tree-node:after {
+  border-top: none;
+}
+
+.tree /deep/ .el-tree-node:before {
+  content: "";
+  left: -4px;
+  position: absolute;
+  right: auto;
+  border-width: 1px;
+}
+
+.tree /deep/ .el-tree-node:after {
+  content: "";
+  left: -4px;
+  position: absolute;
+  right: auto;
+  border-width: 1px;
+}
+
+.tree /deep/ .el-tree-node:before {
+  border-left: 1px dashed #bebebe;
+  bottom: 0px;
+  height: 100%;
+  top: -20px;
+  width: 1px;
+}
+
+.tree /deep/ .el-tree-node:after {
+  border-top: 1px dashed #bebebe;
+  height: 20px;
+  top: 20px;
+  width: 12px;
+}
+
+.tree /deep/ .ivu-tooltip-popper {
+  font-size: 12px !important;
+}
+</style>
+

+ 1 - 1
TEAMModelOS/ClientApp/src/view/research-center/ResearchMgtOld.vue

@@ -69,7 +69,7 @@
 					</Dropdown>
 				</div>
 				<div class="ad-filter-item" v-show="showRangePicker">
-					<DatePicker :value="filterJson.timeRange" :editable="false" :options="timeOptions" format="yyyy/MM/dd" type="daterange" placement="bottom-end" :placeholder="$t('lessonRecord.rangeTip')" @on-change="onTimeRangeChange"></DatePicker>
+					<DatePicker :value="filterJson.timeRange" :editable="false" :options="timeOptions" format="yyyy/MM/dd" type="daterange" placement="bottom-start" :placeholder="$t('lessonRecord.rangeTip')" @on-change="onTimeRangeChange"></DatePicker>
 				</div>
 				<div class="ad-filter-item" v-show="!hideAdFilter || showRangePicker">
 					<Button type="primary" shape="circle" @click="doSearch">{{ $t("lessonRecord.search") }}</Button>

+ 4 - 0
TEAMModelOS/ClientApp/src/view/signupActivity/infoComponent/skContent.vue

@@ -1134,6 +1134,10 @@ export default {
                 this.$Message.warning(this.$t('activity.message.field43'))
                 return
             }
+            if(!this.workDrawer && this.manualAssignIds.length > this.ruleInfo.taskCount) {
+                this.$Message.warning('不满足分配次数,请重新分配')
+                return
+            }
             this.changeLoad(true)
             let list = this.workDrawer ? [this.manualAssignId] : this.manualAssignIds
             // 报名那的分配可以多选,只能新增,不能删除,调多次接口来保存

+ 198 - 55
TEAMModelOS/Controllers/Both/KnowledgeController.cs

@@ -20,6 +20,9 @@ using HTEXLib.COMM.Helpers;
 using static SKIT.FlurlHttpClient.Wechat.TenpayV3.Models.CreateApplyForSubjectApplymentRequest.Types;
 using OpenXmlPowerTools;
 using static Microsoft.Extensions.Logging.EventSource.LoggingEventSource;
+using OfficeOpenXml;
+using TEAMModelOS.Controllers.Third.Moofen;
+using DocumentFormat.OpenXml.Drawing.Charts;
 namespace TEAMModelOS.Controllers.Both
 {
     [ProducesResponseType(StatusCodes.Status200OK)]
@@ -44,7 +47,99 @@ namespace TEAMModelOS.Controllers.Both
             _azureRedis = azureRedis;
             _httpTrigger = httpTrigger;
         }
+        [ProducesDefaultResponseType]
+        [HttpPost("item-import")]
+        [Authorize(Roles = "IES")]
+        [AuthToken(Roles = "admin", Permissions = "knowledge-upd")]
+        public IActionResult ItemImport([FromForm] IFormFile file)
+        {
+            var tokenAuth = HttpContext.GetAuthTokenInfo();
+            ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
+            List<dynamic> period_subject = new List<dynamic>();
+            List<MoofenKnowledgePointDto> pointDtos = new List<MoofenKnowledgePointDto>();
+            List<string> titles = new List<string>();
+            List<List<string>> datas = new List<List<string>>();
+            using (ExcelPackage package = new ExcelPackage(file.OpenReadStream()))
+            {
+                ExcelWorksheets sheets = package.Workbook.Worksheets;
+                var sheet = sheets.FirstOrDefault();
+                if (sheet!= null)
+                {
 
+                    var rows = sheet.Dimension.Rows;
+                    var columns = sheet.Dimension.Columns;
+                    for (int r = 1; r <= rows; r++)
+                    {
+                        List<string> data = new List<string>();
+                        for (int c = 1; c <= columns; c++)
+                        {
+                            var value = sheet.GetValue(r, c);
+                            if (r == 1)
+                            {
+                                if (!string.IsNullOrWhiteSpace($"{value}"))
+                                {
+                                    titles.Add($"{value}");
+                                }
+                                else
+                                {
+                                    break;
+                                }
+                            }
+                            else
+                            {
+                                if (c > titles.Count)
+                                {
+                                    break;
+                                }
+                                else
+                                {
+                                    data.Add($"{value}");
+                                }
+                            }
+                        }
+                        if (data.Any())
+                        {
+                            datas.Add(data);
+                        }
+                    }
+                }
+            }
+            int index = 1;
+            foreach (var data in datas)
+            {
+                MoofenKnowledgePointDto knowledgePointDto = new MoofenKnowledgePointDto { kp1 = data[0], kp2= data[1], kp3 = data[2], kp4=  data[3], id=$"{index}" };
+                if (!string.IsNullOrWhiteSpace(knowledgePointDto.kp1))
+                {
+                    knowledgePointDto.level=1;
+                    knowledgePointDto.name=knowledgePointDto.kp1;
+                }
+                if (!string.IsNullOrWhiteSpace(knowledgePointDto.kp2))
+                {
+                    knowledgePointDto.level=2;
+                    knowledgePointDto.name=knowledgePointDto.kp2;
+                }
+                if (!string.IsNullOrWhiteSpace(knowledgePointDto.kp3))
+                {
+                    knowledgePointDto.level=3;
+                    knowledgePointDto.name=knowledgePointDto.kp3;
+                }
+                if (!string.IsNullOrWhiteSpace(knowledgePointDto.kp4))
+                {
+                    knowledgePointDto.level=4;
+                    knowledgePointDto.name=knowledgePointDto.kp4;
+                }
+                pointDtos.Add(knowledgePointDto);
+                index++;
+            } // 构建树形结构
+            var tree = KnowledgeService.BuildTree(pointDtos);
+            tree.name=$"{file.FileName}";
+            KnowledgeTreeDto knowledge = new KnowledgeTreeDto()
+            {
+                name=tree.name,
+                tree= tree.children,
+            };
+            return Ok(new { knowledgeTree =knowledge});
+        }
 
         [ProducesDefaultResponseType]
         [HttpPost("read-knowledge")]
@@ -114,21 +209,10 @@ namespace TEAMModelOS.Controllers.Both
                     knowledges.Add(item);
                 }
             }
-
-            return Ok(new {  });
+            return Ok(new { knowledgeTrees = KnowledgeService. KnowledgeTranslate(knowledges) });
         }
 
-        private void KnowledgeTranslate(List<Knowledge> knowledges) { 
-        
-            foreach (var knowledge in knowledges)
-            {
-                List<PointTree> tree =  KnowledgeService.ListToTree(knowledge.nodes);
-                foreach (var point in tree)
-                {
-                    point.cids= KnowledgeService.GetChildIds(point);
-                }
-            }
-        }
+      
         [ProducesDefaultResponseType]
         [HttpPost("modify-knowledge-node")]
 #if !DEBUG
@@ -197,26 +281,24 @@ namespace TEAMModelOS.Controllers.Both
                 if (change) {
                     await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, tbname).UpsertItemAsync(knowledge, new PartitionKey(code));
                 }
-            }
-            if (updateData.IsNotEmpty()) 
-            {
-                try
+                if (updateData.IsNotEmpty() &&updateRel==1)
                 {
-                    _ = _httpTrigger.RequestHttpTrigger(new { old_new = old_new, owner = $"{owner}", scope=$"{scope}", subjectId=$"{subjectId}" }, _option.Location, "knowledge-change");
-                }
-                catch (Exception ex)
-                {
-                    //暂不处理
+                    try
+                    {
+                        _ = _httpTrigger.RequestHttpTrigger(new { old_new = old_new, owner = $"{owner}", scope = $"{scope}", subjectId = $"{subjectId}" }, _option.Location, "knowledge-change");
+                    }
+                    catch (Exception ex)
+                    {
+                        //暂不处理
+                    }
                 }
+                var dtos =  KnowledgeService.KnowledgeTranslate(new List<Knowledge> { knowledge });
+                return Ok(new { knowledgeTree = dtos[0] });
             }
-            return Ok(json);
+            return Ok(new {code =404});
         }
 
 
-
-   
-
-
         [ProducesDefaultResponseType]
         [HttpPost("upsert-knowledge")]
 #if !DEBUG
@@ -237,10 +319,11 @@ namespace TEAMModelOS.Controllers.Both
 
             string code = string.Empty;
             Knowledge old =  null;
-            //var blocks = new List<Block>(); 
-            //var points = new HashSet<string>();
+            Knowledge knowledgeDb=null;
+            var blocks = new List<Block>(); 
+            var points = new HashSet<string>();
             var nodes = new List<PointNode>();
-            KnowledgeService.TreeToList(knowledge.tree, nodes);
+            KnowledgeService.TreeToList(knowledge.tree, nodes, blocks, points);
             if (knowledge.scope.Equals("school"))
             {
                 if (!string.IsNullOrWhiteSpace(knowledge.subjectId)  && !string.IsNullOrWhiteSpace(knowledge.periodId))
@@ -256,29 +339,32 @@ namespace TEAMModelOS.Controllers.Both
                     if (old!=null)
                     {
                         knowledge.id = old.id;
-                        //foreach (var p in old.points) { 
-                        //    points.Add(p);
-                        //}
-                        //foreach (var b in old.blocks) {
-                        //    var bks=  blocks.FindAll(x => x.name.Equals(b.name));
-                        //    if (bks.IsNotEmpty())
-                        //    {
-                        //        foreach (var bk in bks)
-                        //        {
-                        //            bk.points.AddRange(b.points);
-                        //            bk.points= bk.points.Distinct().ToList();
-                        //        }
-                        //    }
-                        //    else {
-                        //        blocks.Add(b);
-                        //    }
-                        //}
+                        foreach (var p in old.points)
+                        {
+                            points.Add(p);
+                        }
+                        foreach (var b in old.blocks)
+                        {
+                            var bks = blocks.FindAll(x => x.name.Equals(b.name));
+                            if (bks.IsNotEmpty())
+                            {
+                                foreach (var bk in bks)
+                                {
+                                    bk.points.AddRange(b.points);
+                                    bk.points= bk.points.Distinct().ToList();
+                                }
+                            }
+                            else
+                            {
+                                blocks.Add(b);
+                            }
+                        }
                     }
                     else
                     {
                         knowledge.id = Guid.NewGuid().ToString();
                     }
-                    Knowledge knowledgeDb = new Knowledge
+                    knowledgeDb = new Knowledge
                     {
                         id=knowledge.id,
                         code=code,
@@ -288,15 +374,23 @@ namespace TEAMModelOS.Controllers.Both
                         scope=knowledge.scope,
                         //blocks=blocks,
                         pk="Knowledge",
-                       // points=points.ToList(),
+                        // points=points.ToList(),
                         nodes=nodes,
                         owner=knowledge.owner,
                     };
-                    return Ok(knowledgeDb);
-                    // await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS,Constant.School).UpsertItemAsync(knowledgeDb,new PartitionKey(code));
+                    var count = new { pcount = points.Count, bcount = blocks.Count,name =knowledge.name };
+                    //处理知识点,知识块计数问题
+                    string key = $"KnowledgeNew:Count:{knowledge.owner}-{knowledge.periodId}";
+                    string filed = knowledge.subjectId;
+                    await _azureRedis.GetRedisClient(8).HashSetAsync(key, filed, count.ToJsonString());
+                    await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).UpsertItemAsync(knowledgeDb, new PartitionKey(code));
+                }
+                else {
+                    return BadRequest();
                 }
             }
-            else {
+            else 
+            {
                 code=$"Knowledge-{knowledge.owner}";
                 if (!string.IsNullOrWhiteSpace(knowledge.id)) 
                 {
@@ -306,7 +400,7 @@ namespace TEAMModelOS.Controllers.Both
                         knowledge.id = Guid.NewGuid().ToString();
                     }
                 }
-                Knowledge knowledgeDb = new Knowledge
+                  knowledgeDb = new Knowledge
                 {
                     id=knowledge.id,
                     code=code,
@@ -320,8 +414,57 @@ namespace TEAMModelOS.Controllers.Both
                     nodes=nodes,
                     owner=knowledge.owner,
                 };
-                return Ok(knowledgeDb);
-             //   await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(knowledgeDb, new PartitionKey(code));
+                //处理知识点,知识块计数问题
+                string key = $"KnowledgeNew:Count:{knowledge.owner}";
+                string filed = knowledge.id;
+                var count = new { pcount = points.Count, bcount = blocks.Count, name = knowledge.name };
+                await _azureRedis.GetRedisClient(8).HashSetAsync(key, filed, count.ToJsonString());
+                await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(knowledgeDb, new PartitionKey(code));
+               
+            }
+            if (knowledgeDb!=null)
+            {
+                var dtos = KnowledgeService.KnowledgeTranslate(new List<Knowledge> { knowledgeDb });
+                return Ok(new { knowledgeTree = dtos[0] });
+            }
+            else {
+                return BadRequest();
+            }
+        }
+        [ProducesDefaultResponseType]
+        [HttpPost("find-count")]
+        [Authorize(Roles = "IES")]
+        [AuthToken(Roles = "teacher,admin,student", Permissions = "knowledge-read,knowledge-upd")]
+        public async Task<IActionResult> FindCount(JsonElement json)
+        {
+            var (userid, _, _, school) = HttpContext.GetAuthTokenInfo();
+            if (!json.TryGetProperty("scope", out var _scope)) {
+                return BadRequest();
+            }
+            if ($"{_scope}".Equals("school", StringComparison.OrdinalIgnoreCase))
+            {
+                if (!json.TryGetProperty("periodId", out var periodId))
+                {
+                    return BadRequest();
+                }
+                School schoolBase = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(school, new PartitionKey("Base"));
+                var period = schoolBase.period.Find(x => x.id.Equals($"{periodId}", StringComparison.OrdinalIgnoreCase));
+                var values = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"KnowledgeNew:Count:{period.id}");
+                if (values!=null  && values!=default && values.Length>0)
+                {
+                    foreach (var value in values)
+                    {
+
+                        KnowledgeCount record = value.Value.ToString().ToObject<KnowledgeCount>();
+                        record.periodId=period.id;
+                        record.subjectId=value.Name;
+                        record.owner=school;
+                        record.scope="school";
+                    }
+                }
+            }
+            else { 
+                
             }
             return Ok();
         }

+ 10 - 5
TEAMModelOS/Controllers/Common/ActivityController.cs

@@ -3586,14 +3586,19 @@ namespace TEAMModelOS.Controllers
                                             }
                                         }
                                         //已分配作品,强制删除。
-                                        string sql = $"select value c from c join t in c.contestTasks where t.uploadId='{enroll.upload.uploadId}' and c.pk='ActivityExpertTask' ";
-                                        var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityExpertTask>(sql, $"ActivityExpertTask-{_activityId}");
-                                        if (result.list.IsNotEmpty()) 
+                                        if (!string.IsNullOrWhiteSpace(enroll.upload?.uploadId)) 
                                         {
-                                            foreach (var activityExpertTask in result.list) {
-                                                await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).DeleteItemStreamAsync(activityExpertTask.id, new PartitionKey(activityExpertTask.code));
+                                            string sql = $"select value c from c join t in c.contestTasks where t.uploadId='{enroll.upload.uploadId}' and c.pk='ActivityExpertTask' ";
+                                            var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityExpertTask>(sql, $"ActivityExpertTask-{_activityId}");
+                                            if (result.list.IsNotEmpty())
+                                            {
+                                                foreach (var activityExpertTask in result.list)
+                                                {
+                                                    await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).DeleteItemStreamAsync(activityExpertTask.id, new PartitionKey(activityExpertTask.code));
+                                                }
                                             }
                                         }
+                                       
                                         if (responseActivityEnrollDel.Status==204)
                                         {
                                             return Ok(new { code = 204, msg = "退出成功!" });

+ 1 - 1
TEAMModelOS/Controllers/Third/IRS/ThirdIRSController.cs

@@ -255,7 +255,7 @@ namespace TEAMModelOS.Controllers
                                     sender = stu.stuid,
                                     timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                                     waitReturn = false,
-                                    payload = new { irsno = "", answer = ans }
+                                    payload = new { irsno = "", answer = ans ,taskId= lessonTask.id}
                                 });
                                 await hub.Clients.User(stu.userid).SendCoreAsync("onMessage", new[]{
                                     new 

+ 4 - 147
TEAMModelOS/Controllers/Third/Moofen/MoofenController.cs

@@ -34,6 +34,7 @@ using System.IO.Packaging;
 using Microsoft.Azure.Amqp.Framing;
 using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing;
 using DocumentFormat.OpenXml.Office2010.Excel;
+using TEAMModelOS.SDK.Models.Service;
 namespace TEAMModelOS.Controllers.Third.Moofen
 {
     [ProducesResponseType(StatusCodes.Status200OK)]
@@ -147,7 +148,7 @@ namespace TEAMModelOS.Controllers.Third.Moofen
                     pointDtos.Add( knowledgePointDto );
                 }
                 // 构建树形结构
-                var tree = BuildTree(pointDtos);
+                var tree =KnowledgeService. BuildTree(pointDtos);
                 tree.name=$"{period}-{subject}";
                 var json= tree.children.ToJsonString();
                 string subjectId = string.Empty;
@@ -194,59 +195,7 @@ namespace TEAMModelOS.Controllers.Third.Moofen
             return Ok(new { period_subject });
         }
 
-        private   TreeNode BuildTree(List<MoofenKnowledgePointDto> pointDtos)
-        {
-            var root = new TreeNode();
-            var stack = new Stack<TreeNode>();
-            stack.Push(root);
-            foreach (var pointDto in pointDtos)
-            {
-                var node = new TreeNode
-                {
-                    id = pointDto.id,
-                    tid = pointDto.id,
-                    name = pointDto.name,
-                    level = pointDto.level
-                };
-                while (stack.Count > 0 && stack.Peek().level >= node.level)
-                {
-                    stack.Pop();
-                }
-                if (stack.Count > 0)
-                {
-                    stack.Peek().children.Add(node);
-                }
-                stack.Push(node);
-            }
-
-            if (root.level==0  && root.children.IsNotEmpty()) {
-               
-                foreach (var node in root.children)
-                {
-                    node.subcids=node.children.Select(x => x.tid).ToList();
-                    var cids = GetChildIds(node);
-                    node.allcids=cids.Count>100 ? new List<string>():cids ;
-                }
-            }
-            return root;
-        }
-
-        static List<string> GetChildIds(TreeNode node)
-        {
-            List<string> childIds = new List<string>();
-            if (node.children != null)
-            {
-                foreach (TreeNode child in node.children)
-                {
-                    childIds.Add(child.tid);
-                    var cids = GetChildIds(child);
-                    childIds.AddRange(cids);
-                    child.allcids=cids.Count>100 ? new List<string>() : cids;
-                    child.subcids=child.children.Select(x => x.tid).ToList();
-                }
-            }
-            return childIds;
-        }
+       
 
         [HttpPost("moofen/question")]
         [AuthToken(Roles = "teacher,admin")]
@@ -612,97 +561,5 @@ namespace TEAMModelOS.Controllers.Third.Moofen
             return Ok(new { code = 400 });
         }
     }
-    public class TreeNode
-    {
-       
-
-        public string name {  get; set; }
-        public string id { get; set; }
-        /// <summary>
-        ///  第三方id
-        /// </summary>
-        public string tid { get; set; }
-        public int level {  get; set; }
-        /// <summary>
-        /// 直接子节点
-        /// </summary>
-        public List<string> subcids { get; set; } = new List<string>();
-        /// <summary>
-        /// 所有子节点
-        /// </summary>
-        public List<string> allcids { get; set; }= new List<string>();
-        public List<TreeNode> children { get; set; } = new List<TreeNode>();
-    }
-
-    public class MoofenKnowledgePointDto
-    {
-        public string id { get; set; }
-        public string name { get; set; }
-        public int level { get; set; }
-        public string kp1 { get; set; }
-        public string kp2 { get; set; }
-        public string kp3 { get; set; }
-        public string kp4 { get; set; }
-      
-     
-      
-    }
-    public class MoofenQuestion
-    {
-        public int difficulty { get; set; }
-        public string questionCode { get; set; }
-        public MoofenScope scope { get; set; }
-        public List<MoofenOption> options { get; set; }
-        public MoofenType @type { get; set; }
-        public string trunk { get; set; }
-        public List<MoofenQuestion> questions { get; set; }
-        /// <summary>
-        /// 填空题的答案
-        /// </summary>
-        public List<MoofenFill> items { get; set; }
-        /// <summary>
-        /// 问答题的答案
-        /// </summary>
-        public string content { get; set; }
-        public List<MoofenKnowledgePoint> kps { get; set; }
-    }
-    public class MoofenFill
-    {
-        public string content { get; set; }
-    }
-
-    public class MoofenScope { 
-        public MoofenGrade grade { get; set; }  
-    }
-
-    public class MoofenGrade 
-    {
-        public string code { get; set; }
-        public string name { get; set; }
-    }
-    
-    public class MoofenOption
-    {
-        public bool correct { get; set; }
-        public string label { get; set; }
-        public string content { get; set; }
-    }
-
-    public class MoofenType
-    {
-        public string code { get; set; }
-        public string name { get; set; }
-    }
-
-    public class MoofenKnowledgePoint
-    {
-        public string kpCode { get; set; }
-        public string kpId { get; set; }
-        public string kpSetId { get; set; }
-        public string kpName { get; set; }
-        public string subCode { get; set; }
-        public int kpLevel { get; set; }
-        public string id { get; set; }
-        public string parKpId { get; set; }
-    }
+   
 }

+ 28 - 5
TEAMModelOS/Controllers/XTest/TestController.cs

@@ -107,7 +107,7 @@ namespace TEAMModelOS.Controllers
             _azureService=azureService;
         }
 
-
+        //
 
 
         /// <summary>
@@ -120,11 +120,34 @@ namespace TEAMModelOS.Controllers
         [RequestSizeLimit(102_400_000_00)] //最大10000m左右
         public async Task<IActionResult> RemoveStuCourse(JsonElement json)
         {
-            _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id="1535418750",name="醍摩豆研发", nickname="醍摩豆研发" } }, $"invite_school", Constant.NotifyType_IES5_Management,
-                                 new Dictionary<string, object> {  { "schoolName", "醍摩豆学校" }, { "schoolId", $"hbcn" } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+            var values2 = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Knowledge:Count:hygjqb-b9ec7e9e-da26-46f5-ad94-8d5d0df09f721");
+            var values1 = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Knowledge:Count:hygjqb-b9ec7e9e-da26-46f5-ad94-8d5d0df09f72");
+            if (values1!=null  && values1!=default && values1.Length>0)
+            {
+               foreach (var value in values1)
+                {
+                    JsonElement record = value.Value.ToString().ToObject<JsonElement>();
+                    if (record.TryGetProperty("pcount", out JsonElement pcout))
+                    {
+                        if (int.TryParse($"{pcout}", out int countP))
+                        {
+                            // countPoint = countPoint + countP;
+                        }
+                    }
+                    if (record.TryGetProperty("bcount", out JsonElement bcout))
+                    {
+                        if (int.TryParse($"{bcout}", out int countB))
+                        {
+                            // countBlock = countBlock + countB;
+                        }
+                    }
+                    var name = value.Name;
+                    var value2 = value.Value;
+                    var json1 = value.Value.ToString();
+                    var json2 = value.ToString();
 
-            //Accumulate accumulate= json.ToObject<Accumulate>();
-            //await SystemService.RecordAccumulateData(_azureRedis,_dingDing, accumulate);
+                }
+            }
             return Ok();
         }
 

+ 4 - 4
TEAMModelOS/TEAMModelOS.csproj

@@ -79,11 +79,11 @@
 		<SpaRoot>ClientApp\</SpaRoot>
 		<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
 		<UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-		<Version>5.2405.8</Version>
-		<AssemblyVersion>5.2405.8.1</AssemblyVersion>
-		<FileVersion>5.2405.8.1</FileVersion>
+		<Version>5.2405.15</Version>
+		<AssemblyVersion>5.2405.15.1</AssemblyVersion>
+		<FileVersion>5.2405.15.1</FileVersion>
 		<Description>TEAMModelOS(IES5)</Description>
-		<PackageReleaseNotes>IES版本说明版本切换标记5.2405.8.1</PackageReleaseNotes>
+		<PackageReleaseNotes>IES版本说明版本切换标记5.2405.15.1</PackageReleaseNotes>
 		<PackageId>TEAMModelOS</PackageId>
 		<Authors>teammodel</Authors>
 		<Company>醍摩豆(成都)信息技术有限公司</Company>

+ 1 - 1
TEAMModelOS/appsettings.Development.json

@@ -18,7 +18,7 @@
     "IdTokenSalt": "8263692E2213497BB55E74792B7900B4",
     "HttpTrigger": "https://teammodelosfunction-test.chinacloudsites.cn/api/",
     //"HttpTrigger": "http://localhost:7071/api/"
-    "Version": "5.2405.8.1"
+    "Version": "5.2405.15.1"
   },
   "Azure": {
 

+ 1 - 1
TEAMModelOS/appsettings.json

@@ -18,7 +18,7 @@
     "Exp": 86400,
     "IdTokenSalt": "8263692E2213497BB55E74792B7900B4",
     "HttpTrigger": "https://teammodelosfunction.chinacloudsites.cn/api/",
-    "Version": "5.2405.8.1"
+    "Version": "5.2405.15.1"
   },
   "Azure": {
     "Storage": {