lsc 6 mesi fa
parent
commit
8b09e52d38

+ 1 - 1
build/webpack.dev.conf.js

@@ -44,7 +44,7 @@ const devWebpackConfig = merge(baseWebpackConfig, {
     watchOptions: {
       poll: config.dev.poll,
     },
-    https: true // Enable HTTPS
+    // https: true // Enable HTTPS
   },
   plugins: [
     new webpack.DefinePlugin({

+ 32 - 6
src/components/pages/aiAddCourse/addCourse.vue

@@ -4869,6 +4869,7 @@
                               :knowFileids="knowFileids"
                               :languageSetting="languageSetting" 
                               :userid="userid" 
+                              :aiJson="aiJson"
                               @setEvaList="setEvaList"
                               v-if="pjTemplateArray.indexOf(templateid) != -1 && pjIndex.indexOf(itemTool.tool[0]) != -1"
                               :ref="'evalist'+itemTaskIndex+toolIndex"></evaList>
@@ -4882,6 +4883,16 @@
                             </button>
                           </div>
                         </div>
+                        <div class="elist_css" v-if="pjTemplateArray.indexOf(templateid) != -1 && panElist(itemTask) > 0">
+                          <div class="elist_title">
+                            <div style=" display: flex; flex-direction: row; align-items: center; margin: 20px 0; ">
+                              <div class="lineTitle clineTitle" style="width: auto">任务评价体系</div>
+                            </div>
+                            <div>
+                              <MindTask  :showBar="false" :mindData="itemTask" style="width: 100%" :jsmindId="unitIndex + '-' + itemTaskIndex + 'mindTask' "></MindTask>
+                            </div>
+                          </div>
+                        </div>
                         <div class="elist_css" v-if="!(unitJson[unitJson.length - 1].easy == 4) && pjTemplateArray.indexOf(templateid) == -1"
                           v-loading="(taskDetailLoading4.indexOf('task-' + itemTaskIndex) !== -1) || (taskGLoading[itemTaskIndex] && taskGLoading[itemTaskIndex][2])" element-loading-text="小可正在努力生成中,请稍等...">
                           <div class="elist_title">
@@ -6926,6 +6937,7 @@ import htmlDocx from "html-docx-js/dist/html-docx";
 import TurndownService from 'turndown';
 import JSZip from "jszip";
 import evaList from "./evaList.vue";
+import MindTask from "./jsmind2";
 
 var OpenCC = require("opencc-js");
 let converter = OpenCC.Converter({
@@ -6960,7 +6972,8 @@ export default {
     aiCreateVideoDialog,
     wpdf,
     wOffice,
-    evaList
+    evaList,
+    MindTask
   },
   data() {
     return {
@@ -7402,7 +7415,7 @@ export default {
       knowinfoisAllSize: 0,
       knowinfoprogress: 0,
       knowFileids: [],
-      pjTemplateArray: [ 'cf5722a4-401b-11ef-b873-005056b86cp5' ],
+      pjTemplateArray: [ 'cf5722a4-401b-11ef-b873-005056b86cp5', '68629cfb-e719-48e9-a03d-56f189fb9cb0' ],
       pjIndex: [52, 48, 1, 3, 16, 45, 47, 41],
       taskAnLoading: [],
       dialogTemplateArray: [ 'cf5722a4-401b-11ef-b873-005056b86cd2', '68629cfb-e719-48e9-a03d-56f189fb9cb0' ],
@@ -7574,6 +7587,17 @@ export default {
         return count;
       };
     },
+    panElist(){
+      return function (array) {
+        let count = 0;
+        for(var i = 0; i < array.toolChoose.length; i++){
+          if(array.toolChoose[i].eList && array.toolChoose[i].eList.length){
+            count++
+          }
+        }
+        return count;
+      };
+    },
     dataCheckPan(){
       return function (fileid) {
         for(let i = 0; i < this.infoData.length; i++){
@@ -19506,11 +19530,13 @@ ${this.courseText && this.aiCallBack[0] == 2 ? '注意,优化原有的<参考
             // _this.unitJson2 = JSON.parse(JSON.stringify(_this.unitJson))
             _this.$forceUpdate();
             _this.$nextTick(()=>{
-              for (var j = 0; j < _task.toolChoose.length; j++) {
-                if(_this.pjTemplateArray.indexOf(_this.templateid) !=-1 && _this.pjIndex.indexOf(toolsJson[_task.toolChoose[j].tool].tool) != -1){
-                  _this.$refs['evalist'+index+j][0].openAiDialog();
+              setTimeout(() => {
+                for (var j = 0; j < _task.toolChoose.length; j++) {
+                  if(_this.pjTemplateArray.indexOf(_this.templateid) !=-1 && toolsJson[_task.toolChoose[j].tool] && _this.pjIndex.indexOf(toolsJson[_task.toolChoose[j].tool].tool) != -1){
+                    _this.$refs['evalist'+index+j][0].openAiDialog();
+                  }
                 }
-              }
+              }, 2000);
             })
           }
           

+ 16 - 3
src/components/pages/aiAddCourse/aiBox.vue

@@ -157,7 +157,8 @@ export default {
       ],
       part: "全部内容",
       checkBool: false,
-      loading: false
+      loading: false,
+      username: "",
     };
   },
   watch: {
@@ -474,13 +475,25 @@ export default {
         }
       };
     },
+    async getUserName() {
+      let params = { uid: this.userid };
+      try {
+        let res = await this.ajax.get(this.$store.state.api + "getUser", params);
+        this.username = res.data[0][0].name;
+      } catch (err) {
+        console.error(err);
+      }
+    },
     //保存消息
-    insertChat(_uid) {
+    async insertChat(_uid) {
       let _data = this.array.find(i => i.uid == _uid);
       if (!_data) return;
+      if(!this.username){
+        await this.getUserName()
+      }
       let params = {
         userId: this.userid,
-        userName: "qgt",
+        userName: this.username,
         groupId: "602def61-005d-11ee-91d8-005056b8q12w",
         answer: _data.aiContent,
         problem: _data.content,

+ 16 - 3
src/components/pages/aiAddCourse/aiBox2.vue

@@ -157,7 +157,8 @@ export default {
       ],
       part: "全部内容",
       checkBool: false,
-      loading: false
+      loading: false,
+      username: "",
     };
   },
   watch: {
@@ -458,13 +459,25 @@ export default {
         }
       };
     },
+    async getUserName() {
+      let params = { uid: this.userid };
+      try {
+        let res = await this.ajax.get(this.$store.state.api + "getUser", params);
+        this.username = res.data[0][0].name;
+      } catch (err) {
+        console.error(err);
+      }
+    },
     //保存消息
-    insertChat(_uid) {
+    async insertChat(_uid) {
       let _data = this.array.find(i => i.uid == _uid);
       if (!_data) return;
+      if(!this.username){
+        await this.getUserName()
+      }
       let params = {
         userId: this.userid,
-        userName: "qgt",
+        userName: this.username,
         groupId: "602def61-005d-11ee-91d8-005056b8q12w",
         answer: _data.aiContent,
         problem: _data.content,

+ 15 - 2
src/components/pages/aiAddCourse/aiBoxRight.vue

@@ -308,6 +308,7 @@ export default {
       faloading: false,
       fasource: null,
       saveUid: "",
+      username: ""
     };
   },
   watch: {
@@ -808,15 +809,27 @@ ATTENTION: Use '##' to SPLIT SECTIONS, not '#'.Output format carefully reference
         }
       };
     },
+    async getUserName() {
+      let params = { uid: this.userid };
+      try {
+        let res = await this.ajax.get(this.$store.state.api + "getUser", params);
+        this.username = res.data[0][0].name;
+      } catch (err) {
+        console.error(err);
+      }
+    },
     //保存消息
-    insertChat(_uid) {
+    async insertChat(_uid) {
       let _data = this.array.find(i => i.uid == _uid);
       this.saveUid = ''
       this.faloading = false
+      if(!this.username){
+        await this.getUserName()
+      }
       if (!_data) return;
       let params = {
         userId: this.userid,
-        userName: "qgt",
+        userName: this.username,
         groupId: "602def61-005d-11ee-91d8-005056b8q12w",
         answer: _data.aiContent,
         problem: _data.content,

+ 225 - 26
src/components/pages/aiAddCourse/evaList.vue

@@ -1,16 +1,21 @@
 <template>
-    <div style="position: relative;" v-loading="loading" :style="{ minHeight: loading ? '250px' : 'auto' }" element-loading-text="小可正在努力生成中,请稍等...">
-        <div class="c_pub_button_confirm stopBtn" v-if="loading" @click="cancelAjax()">停止</div>
+    <div style="position: relative;" v-loading="loading" :style="{ minHeight: loading ? '250px' : 'auto' }"
+        element-loading-text="小可正在努力生成中,请稍等...">
+        <div class="c_pub_button_confirm stopBtn" v-if="loading" @click="cancelAjax('elist')">停止</div>
         <div class="elist_title">
             <div style=" display: flex; flex-direction: row;align-items: center; margin: 20px 0; ">
                 <div class="lineTitle clineTitle">评价设置</div>
                 <div style="margin-left:auto;display: flex;">
-                    <div class="r_pub_button_op" style="margin-left:10px;" @contextmenu.prevent="openAiDialog(1)"
-                        @click="openAiDialog(2)">{{ (eList && eList.length) ? '重新生成评价' : '生成评价' }}</div>
+                    <div class="r_pub_button_op" style="margin-left:10px;" @click="openAiDialog('elist')">{{ (eList &&
+                        eList.length) ? '重新生成评价' : '生成评价' }}</div>
+                    <div  v-if="eList && eList.length" class="show_taskD" :class="{ show: interPan }" @click="toggleInterPan">
+                        <img src="../../../assets/icon/new/u_up.png" />
+                        {{ interPan ? '收起' : '展开' }}
+                    </div>
                 </div>
             </div>
         </div>
-        <div class="mbCss">
+        <div class="mbCss" v-show="interPan">
             <div class="pjCss">
                 <div v-if="eList && eList.length" class="elist_input">
                     <div v-for="(eItem, eIndex) in eList" :key="eIndex" class="elist_input_box">
@@ -37,9 +42,16 @@
                             <div style="width: calc(100%);">
                                 <div @click="openRule(eIndex)" class="ruleBtn">{{ eItem.isrule ? '收起细则' : '展开细则' }}
                                 </div>
-                                <div style="width: calc(100%);" class='op_task_box' v-if="eItem.isrule">
+                                <div style="width: calc(100%);" class='op_task_box' v-if="eItem.isrule" v-loading="ruleLoading.length && ruleLoading[eIndex]" element-loading-text='小可正在努力生成中,请稍等...'>
+                                    <div class="c_pub_button_confirm stopBtn" v-if="ruleLoading.length && ruleLoading[eIndex]" @click="cancelAjax('rule', eIndex)">停止</div>
                                     <textarea v-autoHeight="68" rows="2" class="binfo_input binfo_textarea" cols
                                         v-model="eItem.rule" placeholder="请输入评价细则"></textarea>
+                                    <div class="op_box">
+                                        <div class="op_remark"></div>
+                                        <div style="display: flex;">
+                                                <div class="r_pub_button_op" @click="openAiDialog('rule', eIndex)">{{ eList[eIndex].rule ? '重新生成' : '生成细则'}}</div>
+                                        </div>
+                                    </div>
                                 </div>
                             </div>
 
@@ -97,6 +109,10 @@ export default {
             type: Number,
             required: true
         },
+        aiJson: {
+            type: Object,
+            default: () => { }
+        }
     },
     data() {
         return {
@@ -104,6 +120,9 @@ export default {
             isEvaFold: true,
             loading: false,
             cancelToken: null,
+            ruleLoading: [],
+            cancelRuleToken: [],
+            interPan: false
         }
     },
     watch: {
@@ -142,16 +161,33 @@ export default {
         },
     },
     methods: {
-        cancelAjax() {
-            this.$message.success("已经成功停止生成评价设置")
-            if (this.cancelToken) {
-                this.cancelToken.cancel('Request canceled by the user.');
-                this.cancelToken = null;
-            }
-            if (this.loading) {
-                this.loading = false
+        toggleInterPan() {
+            this.interPan = !this.interPan;
+            this.forceUpdate();
+        },
+        cancelAjax(type, index) {
+            if(type == 'elist'){
+                this.$message.success("已经成功停止生成评价设置")
+                if (this.cancelToken) {
+                    this.cancelToken.cancel('Request canceled by the user.');
+                    this.cancelToken = null;
+                }
+                if (this.loading) {
+                    this.loading = false
+                }
+                this.$forceUpdate()
+            }else if(type == 'rule'){
+                this.$message.success("已经成功停止生成评价细则")
+                if (this.cancelRuleToken && this.cancelRuleToken[index]) {
+                    this.cancelRuleToken[index].cancel('Request canceled by the user.');
+                    this.cancelRuleToken[index] = null;
+                }
+                if (this.ruleLoading[index]) {
+                    this.ruleLoading[index] = false
+                }
+                this.$forceUpdate()
             }
-            this.$forceUpdate()
+
         },
         forceUpdate() {
             this.$forceUpdate();
@@ -167,8 +203,19 @@ export default {
             }
             return lang
         },
-        openAiDialog() {
+        openAiDialog(type, index) {
+            if (type == 'elist') {
+                this.aiElist();
+            } else if (type == 'rule') {
+                this.aiRule(index);
+            }
+        },
+        aiElist() {
             let _this = this
+            if(!_this.knowFileids.length){
+                this.$message.error(`请添加文件后,再生成评价`)
+                return
+            }
             _this.loading = true
 
             let fileid = _this.knowFileids.length ? [..._this.knowFileids] : []
@@ -191,12 +238,15 @@ Language: ${this.getLang()}
 【排序】通过设置卡片内容及正确顺序,用于教师使用排序类题目检查学生对知识的掌握和理解,参考指标为题目的正确率。。
 【选择匹配】通过上传题目图片与设置正确回答,用于教师使用选择匹配(连线)检查学生对知识的掌握和理解,参考指标为题目的正确率。
 
-你要学习上传的文件。文件中包含了该学科的“核心素养”和“课程目标”。“学科核心素养”指学生应具备的,能够适应终身发展和社会发展需要的必备品格和关键能力。“课程目标”指课程本身要实现的具体目标和意图。它规定了某一教育阶段的学生通过课程学习以后,在发展品德、智力、体质等方面期望实现的程度,它是确定课程内容、教学目标和教学方法的基础。当选择多个学科时,上传的文件中会有《跨学科素养参考资料》,跨学科素养能力指具有跨文化一致性的、能够跨越一系列情境长期存在和发挥作用的、个体用于应对和解决日常工作和生活中遇到的各种复杂挑战和需求的能力;例如“个人社会责任”“任务规划”“自我管理”“承担风险”等。你要理解学科核心素养和学科目标之间的关系。你生成的评价标准可以被理解为课程目标。
+你要学习上传的文件。你只需要学习文件中“课程目标”一级标题下的内容,其中包含了该学科的“核心素养”和“目标”。“学科核心素养”指学生应具备的,能够适应终身发展和社会发展需要的必备品格和关键能力。“目标”指课程本身要实现的具体目标和意图。它规定了某一教育阶段的学生通过课程学习以后,在发展品德、智力、体质等方面期望实现的程度,它是确定课程内容、教学目标和教学方法的基础。
+当选择多个学科时,上传的文件中会有《跨学科素养参考资料》,跨学科素养能力指具有跨文化一致性的、能够跨越一系列情境长期存在和发挥作用的、个体用于应对和解决日常工作和生活中遇到的各种复杂挑战和需求的能力;例如“个人社会责任”“任务规划”“自我管理”“承担风险”等。
+你要理解学科核心素养和学科目标之间的关系。你生成的评价标准可以被理解为课程目标。
 
 #目标#
 你需要完成以下五个步骤:
 1.你要结合<任务描述:${taskDetail}><工具名称:${tool}>和<工具描述:${toolDetail}>生成适合当前作业的评价标准。评价标准用于评估学生的能力。
-2.你要严格按照上传的文件中的“核心素养”和“课程目标”将评价标准对应到课程目标中,并且用学科核心素养归类。3.只有当上传的文件包含多个学科的课程标准时,允许你检索《跨学科素养参考资料》。你需要先检索学科的课程标准,如果你判断当前的评价标准无法对应具体学科的核心素养,可以检索《跨学科素养参考资料》,找到最合适的并输出。输出的内容一定要包含“核心素养”和“上传文件对应的学科”。
+2.你要严格检索和匹配上传文件的核心素养和课程目标内容。你要先将评价标准对应到课程目标中,然后检索上传的文件中的“核心素养”与评价标准进行匹配。所有的核心素养信息必须以上传文件的内容为依据,不可以使用其他的默认信息或者模版!每个评价标准必须与文件中明确的核心素养对应。避免使用文件中未出现的任何术语。
+3.只有当上传的文件包含多个学科的课程标准时,允许你检索《跨学科素养参考资料》。你需要先检索学科的课程标准,如果你判断当前的评价标准无法对应具体学科的核心素养,可以检索《跨学科素养参考资料》,找到最合适的并输出。
 4.你要根据第一步生成的评价标准制定每一条标准的六级评价细则,这个评价细则将用于对学生能力的打分。
 5.你要将前四步生成的内容整理成json格式。
 
@@ -211,7 +261,7 @@ Language: ${this.getLang()}
 
 #输出要求#
 1.评价标准的个数为3个,最多不能超过5个。每一个评价标准不能超过30字。生成的评价标准只能和当前的工具描述相关。选择题、排序、选择匹配工具只生成1个评价标准。输出内容和格式要求参考#评价标准范例#。注意!输出内容不能复制范例内容。注意!不要出现#评价标准错误范例#中的情况。
-2.每1个评价标准只对应1个关联度最高的核心素养。学科核心素养输出参考#核心素养输出范例#。注意!1个评价标准不能对应多个核心素养。
+2.每1个评价标准只对应1个关联度最高的核心素养。学科核心素养输出参考#核心素养输出范例#。注意!1个评价标准不能对应多个核心素养。不允许出现上传文件中没有的核心素养。严格按照上传文件中检索到的核心素养输出。每个评价标准必须与文件中明确的核心素养对应。避免使用文件中未出现的任何术语。不要出现#核心素养错误范例#中的情况。
 3.具体的评价细则分为6级——0星,1星,2星,3星,4星,5星。输出格式参考#评价细则范例#。
 4.参考#json格式范例#,将内容整理成json格式。**之间的内容为json格式中的代码。以*[*开头,以*]*结尾。每一条评价标准、核心素养以及评价细则以*{*开头,以*}*结尾。核心素养前有*"core":*。评价标准前有*"std":*。评价细则前有*"rule":*。具体内容放在""之间。格式如下:
 [
@@ -238,12 +288,16 @@ Language: ${this.getLang()}
 4 星,问题或需求的大部分被识别;
 5 星,问题或需求都被识别。 
 
+#核心素养错误范例#
+错误范例1:评价标准是“学生能够展示诗歌与美术作品的创作主题和过程”。输出“审美创造(艺术)”是错误的,因为艺术学科的核心素养中没有“审美创造”。
+错误范例2:评价标准是“学生能通过文档工具记录并总结对诗词的人文感悟。”。输出“表达与交流(语文)”是错误的,因为艺术学科的核心素养中没有“表达与交流”。
+
 #核心素养输出范例#
 评价标准:学生应该能准确指出光合作用发生的具体部位(叶绿体),并解释叶绿体在光合作用中的重要性。
 这一条标准对应了《义务教育科学课程标准(2022年版)》中“科学观念”这一条核心素养,识别上传文件对应的学科为“科学”。所以输出内容为:科学观念(科学)。
 
 评价标准:学生能够通过文档工具清晰表达小学生活的回忆与未来期望。
-这一条标准对应了《义务教育艺术课程标准(2022年版)》中“艺术表现”这一条核心素养,识别上传文件对应的学科为“艺术”。所以输出内容为:科学观念(艺术)。
+这一条标准对应了《义务教育艺术课程标准(2022年版)》中“艺术表现”这一条核心素养,识别上传文件对应的学科为“艺术”。所以输出内容为:艺术表现(艺术)。
 
 评价标准:学生能够在小组讨论中积极表达观点。
 这一条标准对应了《跨学科素养参考资料》中“合作能力”这一条核心素养,识别上传文件对应的学科为“跨学科”。所以输出内容为:合作能力(跨学科)。
@@ -333,6 +387,106 @@ Language: ${this.getLang()}
                 console.log(error);
             });
         },
+        aiRule(index) {
+            if (!this.eList[index].target || !this.eList[index].detail) {
+                this.$message.error(`评价信息完善信息后再生成细则`)
+                return;
+            }
+            this.ruleLoading[index] = true
+            this.$forceUpdate();
+            let message = `NOTICE
+Role: 你是一个专业的项目式学习导师
+Language: ${this.getLang()}
+ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
+Instruction: Based on the context, follow "Format example", write content.
+
+#Context
+##要求
+${this.aiJson['aiRateRule']}
+
+<评价标准:${this.eList[index].detail}>
+<素养:${this.eList[index].target}>
+
+参考#Format example#,将内容整理成字符串格式。。以*====*开头,以*====*结尾。格式如下:
+==== 
+0 星,作业内容与作业要求无关;
+1 星,没有识别问题和需求;
+2 星,问题或需求没有被清晰理解或准确识别;
+3 星,问题或需求的一部分被识别;
+4 星,问题或需求的大部分被识别;
+5 星,问题或需求都被识别。 
+==== 
+
+# Format example
+==== 
+0 星,作业内容与作业要求无关;
+1 星,没有识别问题和需求;
+2 星,问题或需求没有被清晰理解或准确识别;
+3 星,问题或需求的一部分被识别;
+4 星,问题或需求的大部分被识别;
+5 星,问题或需求都被识别。 
+==== `
+            this.cancelRuleToken[index] = this.ajax.setCancelSource();
+            let parm = {
+                assistant_id: 'b19f1a1a-7586-11ef-8ce0-12e77c4cb76b',
+                message: [{ "type": "text", "text": this.languageSetting == 1 ? converter2(message.replaceAll('\n', " ").replaceAll('*', "")) : message.replaceAll('\n', " ").replaceAll('*', "") }],
+                session_name: uuidv4(),
+                userId: this.userid,
+                file_ids: [],
+                model: 'gpt-4o-2024-08-06',
+                temperature: this.mode == 3 ? 0.5 : 0.1,
+            }
+            this.ajax
+                .post("https://gpt4.cocorobo.cn/ai_agent_park_chat", parm, this.cancelRuleToken[index])
+                .then(async (response) => {
+                    console.log(response);
+                    let data = response.data.FunctionResponse
+                    if (data.message) {
+                        console.log(data.message);
+
+                        let content = data.message;
+
+                        var regex = new RegExp('====([^=]+)====');
+                        let match = content.match(regex);
+                        if (match) {
+                            content = match[1].trim().replaceAll(' ', '');
+                            // 获取匹配到的内容并去除两端空格 
+                            console.log('contentInsideDoubleEquals', content);
+                            if (content.indexOf('0星') == -1 || content.indexOf('2星') == -1 || content.indexOf('3星') == -1 || content.indexOf('4星') == -1 || content.indexOf('5星') == -1) {
+                                console.log("未有星级。");
+                                this.cancelRuleToken[index] = null
+                                this.aiRule(index)
+                                return
+                            }
+                            //  return 
+                        } else {
+                            console.log("未找到匹配的内容。");
+                            this.cancelRuleToken[index] = null
+                            this.aiRule(index)
+                            return
+                        }
+
+                        let elist = JSON.parse(JSON.stringify(this.eList[index]))
+                        elist.rule = JSON.parse(JSON.stringify(content.replaceAll("#", "")))
+                        this.$set(this.eList, index, elist)
+                        this.$forceUpdate();
+                        this.ruleLoading[index] = false
+                        this.cancelRuleToken[index] = null
+                        this.$message.success(`评价细则生成成功`)
+                    } else {
+                        this.ruleLoading[index] = false
+                        this.cancelRuleToken[index] = null
+                    }
+                    this.$forceUpdate();
+
+                })
+                .catch((error) => {
+                    this.cancelRuleToken[index] = null
+                    this.ruleLoading[index] = false
+                    this.$forceUpdate();
+                    console.log(error);
+                });
+        },
         addEList() {
 
         },
@@ -363,6 +517,14 @@ Language: ${this.getLang()}
     mounted() {
         let elist = this.unitJson[0].chapterInfo[0].taskJson[this.itemTaskIndex].toolChoose[this.toolIndex].eList
         this.eList = elist ? JSON.parse(JSON.stringify(elist)) : []
+        for (let i = 0; i < this.eList.length; i++) {
+            setTimeout(() => {
+                this.eList[i].rule += "*0*%*";
+                setTimeout(() => {
+                    this.eList[i].rule = this.eList[i].rule.replaceAll("*0*%*", "");
+                }, 0);
+            }, 500);
+        }
     }
 }
 </script>
@@ -848,6 +1010,22 @@ Language: ${this.getLang()}
     display: flex
 }
 
+.op_box {
+  position: absolute;
+  bottom: 10px;
+  display: none;
+  align-items: center;
+  justify-content: space-between;
+  width: calc(100% - 20px);
+  left: 50%;
+  transform: translateX(-50%);
+}
+
+.op_box .op_remark {
+  color: #8E8E8E;
+  font-size: 14px;
+}
+
 .binfo_input {
     width: 100%;
     margin: 0;
@@ -905,11 +1083,32 @@ Language: ${this.getLang()}
     background-image: url(../../../assets/icon/new/u_op.png);
 }
 
-.stopBtn{
-  z-index: 999999;
-  position: absolute;
-  left: 50%;
-  top: calc(50% + 70px);
-  transform: translateX(-50%);
+.stopBtn {
+    z-index: 999999;
+    position: absolute;
+    left: 50%;
+    top: calc(50% + 70px);
+    transform: translateX(-50%);
+}
+
+.show_taskD {
+  min-width: fit-content;
+  margin-left: 10px;
+  display: flex;
+  align-items: center;
+  font-size: 14px;
+  cursor: pointer;
+  color: #0061FF;
+}
+
+.show_taskD>img {
+  width: 15px;
+  margin-right: 5px;
+  transition: 0.2s all;
+  transform: rotate(-90deg);
+}
+
+.show_taskD.show>img {
+  transform: rotate(0deg);
 }
 </style>

+ 620 - 0
src/components/pages/aiAddCourse/jsmind2.vue

@@ -0,0 +1,620 @@
+<template>
+  <!-- 普通菜单 -->
+  <div class="jsmind_layout">
+    <div class="noMind" v-if="mindV">
+      <span>暂无数据</span>
+    </div>
+    <div :id="jsmindId" ref="container" class="jsmind_container"></div>
+  </div>
+</template>
+
+<script>
+import "jsmind/style/jsmind.css";
+import jsMind from "jsmind/js/jsmind.js";
+window.jsMind = jsMind;
+
+require("jsmind/js/jsmind.draggable.js");
+require("jsmind/js/jsmind.screenshot.js");
+export default {
+  props: {
+    showBar: {
+      // 是否显示工具栏,显示启用编辑
+      type: Boolean,
+      default: true,
+    },
+    theme: {
+      // 主题
+      type: String,
+      default: "primary",
+    },
+    lineColor: {
+      // 线条颜色
+      type: String,
+      default: "skyblue",
+    },
+    mindData: {
+      type: Object,
+      default: {},
+    },
+    jsmindId: {
+      type: String,
+      default: "jsmind_container",
+    },
+  },
+  data() {
+    return {
+      mindV: false,
+      i: 0,
+      mind: {},
+      jm: null,
+      isZoomIn: false,
+      isZoomOut: false,
+      level: 0,
+      nodeOptions: [
+        { value: 1, label: "展开到一级节点" },
+        { value: 2, label: "展开到二级节点" },
+        { value: 3, label: "展开到三级节点" },
+        { value: 0, label: "展开全部节点" },
+        { value: -1, label: "隐藏全部节点" },
+      ],
+      themeOptions: [
+        { value: "default", label: "default" },
+        { value: "primary", label: "primary" },
+        { value: "warning", label: "warning" },
+        { value: "danger", label: "danger" },
+        { value: "success", label: "success" },
+        { value: "info", label: "info" },
+        { value: "greensea", label: "greensea" },
+        { value: "nephrite", label: "nephrite" },
+        { value: "belizehole", label: "belizehole" },
+        { value: "wisteria", label: "wisteria" },
+        { value: "asphalt", label: "asphalt" },
+        { value: "orange", label: "orange" },
+        { value: "pumpkin", label: "pumpkin" },
+        { value: "pomegranate", label: "pomegranate" },
+        { value: "clouds", label: "clouds" },
+        { value: "asbestos", label: "asbestos" },
+      ],
+      localTheme: this.theme,
+      dialogVisible: false,
+      nodeOption: {
+        content: "",
+        bgColor: "",
+        fontColor: "",
+        fontSize: "",
+        fontWeight: "",
+        fontStyle: "",
+      },
+    };
+  },
+  watch: {
+    mindData: {
+      handler: function (cur, old) {
+        console.log(cur.task);
+        let data = this.setMindData(cur)
+        this.mind = data;
+        this.$forceUpdate()
+        if (data.data.length) {
+          if (data.data[0].topic === "" && data.data.length === 1) {
+            this.mindV = true;
+          } else {
+            this.mindV = false;
+          }
+          setTimeout(() => {
+            if (this.jm) {
+              this.jm.show(this.mind);
+            } else {
+              this.open_empty();
+            }
+          }, 1000);
+        }
+      },
+      deep: true, //对象内部的属性监听,也叫深度监听
+    },
+  },
+  created() { },
+  mounted() {
+    this.getData();
+    // this.mouseWheel();
+  },
+  methods: {
+    beforeUpload(file) {
+      // 上传文件之前钩子
+      if (file) {
+        jsMind.util.file.read(file, (jsmindData) => {
+          const mind = jsMind.util.json.string2json(jsmindData);
+          if (mind) {
+            this.jm.show(mind);
+            this.$message({ type: "success", message: "打开成功" });
+          } else {
+            this.prompt_info("不能打开mindmap文件");
+          }
+        });
+      } else {
+        this.prompt_info("请先选择文件");
+        return false;
+      }
+    },
+    upload() { },
+    getData() {
+      //   this.$API({
+      //     name: "getMind",
+      //   })
+      //     .then((res) => {
+      //       this.mind = res.data;
+      //       this.open_empty();
+      //     })
+      //     .catch((error) => {
+      //       this.$message.error(error);
+      //     });
+      let data = this.setMindData(this.mindData)
+      this.mind = data;
+      // debugger
+      this.$forceUpdate()
+      if (data.data.length) {
+        if (data.data[0].topic === "" && data.data.length === 1) {
+          this.mindV = true;
+        } else {
+          this.mindV = false;
+        }
+        setTimeout(() => {
+          if (this.jm) {
+            this.jm.show(this.mind);
+          } else {
+            this.open_empty();
+          }
+        }, 1000);
+      }
+    },
+    setMindData(json) {
+      let data = {
+        meta: {
+          name: json.task,
+          author: "dd@163.com",
+          version: "0.2",
+        },
+        format: "node_array",
+        data: []
+      };
+      data.data.push({ id: "root", isroot: true, topic: json.task });
+      console.log(`111`, json.task);
+      let elist = []
+      let toolChoose = json.toolChoose;
+      for (let i = 0; i < toolChoose.length; i++) {
+        if(toolChoose[i].eList && toolChoose[i].eList.length){
+          let list = toolChoose[i].eList.map(item=>{
+            return {
+              ...item,
+              index: i
+            }
+          })
+          elist.push(...list)
+        }
+      }
+      if(elist.length){
+        let listName = []
+      for(var i = 0;i<elist.length;i++){
+        let item = elist[i]
+        if(listName.indexOf(item.target) == -1){
+          listName.push(item.target)
+        }
+      }
+      let _eJson = {}
+      for(var i = 0;i<listName.length;i++){
+        let item = listName[i]
+        _eJson[item] = {
+          child: {}
+        }
+        for(var j = 0;j<elist.length;j++){
+          let item2 = elist[j]
+          if(item2.target == item){
+            if(_eJson[item].child[item2.detail]){
+              if(_eJson[item].child[item2.detail].child.indexOf(item2.index) == -1){
+                _eJson[item].child[item2.detail].child.push(item2.index)
+              }
+            }else{
+              _eJson[item].child[item2.detail] = {
+                child: [item2.index]
+              }
+            }
+          }
+        }
+      }
+      let _JsonName = Object.keys(_eJson)
+      for(var i = 0;i<_JsonName.length;i++){
+        let item = _eJson[_JsonName[i]]
+        data.data.push({
+          id: _JsonName[i],
+          parentid: "root",
+          topic: _JsonName[i],
+        })
+        let _eJsonz = Object.keys(item.child)
+        let _e3 = item.child
+        for(var j = 0;j<_eJsonz.length;j++){
+          let item2 = _e3[_eJsonz[j]]
+          data.data.push({
+            id: _eJsonz[j],
+            parentid: _JsonName[i],
+            topic: _eJsonz[j],
+          })
+          let _eJsonz2 = Object.keys(item2.child)
+          let _e4 = item2.child
+          for(var z = 0;z<_eJsonz2.length;z++){
+            // let item3 = _e4[_eJsonz2[z]]
+            for(var zz = 0;zz<_e4.length;zz++){
+              data.data.push({
+                id: `${_eJsonz[j]}-${_eJsonz2[z]}-${zz}`,
+                parentid: _eJsonz[j],
+                topic: `工具${_e4[zz] + 1}`,
+              })
+            }
+
+          }
+          }
+        }
+      }
+
+      console.log(json.task, data);
+      return data
+    },
+    open_empty() {
+      const options = {
+        container: this.jsmindId, // 必选,容器ID
+        editable: this.showBar, // 可选,是否启用编辑
+        theme: this.localTheme, // 可选,主题
+        view: {
+          line_width: 2, // 思维导图线条的粗细
+          // line_color: this.lineColor, // 思维导图线条的颜色
+        },
+        shortcut: {
+          enable: true, // 禁用快捷键
+        },
+        layout: {
+          hspace: 20, // 节点之间的水平间距
+          vspace: 10, // 节点之间的垂直间距
+          pspace: 13, // 节点与连接线之间的水平间距(用于容纳节点收缩/展开控制器)
+        },
+        mode: "side", // 显示模式,子节点只分布在根节点右侧
+      };
+      this.jm = jsMind.show(options, this.mind);
+      // 改变窗口大小重置画布
+      window.onresize = () => {
+        this.jm.resize();
+      };
+      this.getDepth(this.jm.mind.root, 1);
+      this.$forceUpdate();
+      setTimeout(()=>{
+        this.jm.show(this.mind);
+      },1000)
+    },
+    // 获取层级数 i
+    getDepth(obj, k) {
+      this.i = Math.max(this.i, k);
+      if (obj.children) {
+        obj.children.forEach((v) => {
+          this.getDepth(v, k + 1);
+        });
+      }
+    },
+    save_nodearray_file() {
+      const mindData = this.jm.get_data("node_array");
+      const mindName = mindData.meta.name;
+      const mindStr = jsMind.util.json.json2string(mindData);
+      jsMind.util.file.save(mindStr, "text/jsmind", mindName + ".jm");
+    },
+    screen_shot() {
+      this.jm.screenshot.shootDownload();
+    },
+    expand_all() {
+      this.jm.expand_all();
+    },
+    collapse_all() {
+      this.jm.collapse_all();
+    },
+    expand_to_level(num) {
+      switch (num) {
+        case -1:
+          this.collapse_all();
+          break;
+        case 0:
+          this.expand_all();
+          break;
+        default:
+          this.jm.expand_to_depth(num);
+          break;
+      }
+    },
+    zoomIn() {
+      if (this.jm.view.zoomIn()) {
+        this.isZoomOut = false;
+      } else {
+        this.isZoomIn = true;
+      }
+    },
+    zoomOut() {
+      // debugger;
+      if (this.jm.view.zoomOut()) {
+        this.isZoomIn = false;
+      } else {
+        this.isZoomOut = true;
+      }
+    },
+    prompt_info(msg) {
+      this.$message({ type: "warning", message: msg });
+    },
+    get_nodearray_data() {
+      const mindData = this.jm.get_data("node_array");
+      const mindString = jsMind.util.json.json2string(mindData);
+      this.$message({ type: "info", message: mindString });
+    },
+    set_theme(themeName) {
+      this.jm.set_theme(themeName);
+    },
+    scrollFunc(e) {
+      e = e || window.event;
+      if (e.wheelDelta) {
+        if (e.wheelDelta > 0) {
+          this.zoomIn();
+        } else {
+          this.zoomOut();
+        }
+      } else if (e.detail) {
+        if (e.detail > 0) {
+          this.zoomIn();
+        } else {
+          this.zoomOut();
+        }
+      }
+      this.jm.resize();
+    },
+    // 鼠标滚轮放大缩小
+    mouseWheel() {
+      if (document.addEventListener) {
+        document.addEventListener("domMouseScroll", this.scrollFunc, false);
+      }
+      this.$refs.container.onmousewheel = this.scrollFunc;
+    },
+    // 新增节点
+    addNode() {
+      let selectedNode = this.jm.get_selected_node();
+      if (!selectedNode) {
+        this.$message({ type: "warning", message: "请先选择一个节点!" });
+        return;
+      }
+      let nodeid = jsMind.util.uuid.newid();
+      let topic = "new Node";
+      let newNode = this.jm.add_node(selectedNode, nodeid, topic);
+      if (newNode) {
+        this.jm.select_node(nodeid);
+        this.jm.begin_edit(nodeid);
+        this.getDepth(this.jm.mind.root, 1);
+      }
+    },
+    // 新增兄弟节点
+    addBrotherNode() {
+      let selectedNode = this.jm.get_selected_node();
+      if (!selectedNode) {
+        this.$message({ type: "warning", message: "请先选择一个节点!" });
+        return;
+      } else if (selectedNode.isroot) {
+        this.$message({
+          type: "warning",
+          message: "不能在根节点添加,请重新选择节点!",
+        });
+        return;
+      }
+      let nodeid = jsMind.util.uuid.newid();
+      let topic = "new Node";
+      let newNode = this.jm.insert_node_after(selectedNode, nodeid, topic);
+      if (newNode) {
+        this.jm.select_node(nodeid);
+        this.jm.begin_edit(nodeid);
+      }
+    },
+    // 获取选中标签的 ID
+    get_selected_nodeid() {
+      let selectedNode = this.jm.get_selected_node();
+      if (selectedNode) {
+        return selectedNode.id;
+      } else {
+        return null;
+      }
+    },
+    // 删除节点
+    removeNode() {
+      let selectedId = this.get_selected_nodeid();
+      if (!selectedId) {
+        this.$message({
+          type: "warning",
+          message: "请先选择一个节点!",
+        });
+        return;
+      }
+      this.jm.remove_node(selectedId);
+      this.i = 0;
+      this.getDepth(this.jm.mind.root, 1);
+    },
+    // 编辑节点
+    editNode() {
+      let selectedId = this.get_selected_nodeid();
+      if (!selectedId) {
+        this.$message({ type: "warning", message: "请先选择一个节点!" });
+        return;
+      }
+      let nodeObj = this.jm.get_node(selectedId);
+      this.nodeOption.content = nodeObj.topic;
+      this.nodeOption.bgColor = nodeObj.data["background-color"];
+      this.nodeOption.fontColor = nodeObj.data["foreground-color"];
+      this.nodeOption.fontSize = nodeObj.data["font-size"];
+      this.nodeOption.fontWeight = nodeObj.data["font-weight"];
+      this.nodeOption.fontStyle = nodeObj.data["font-style"];
+      this.dialogVisible = true;
+    },
+    sureEditNode() {
+      let selectedId = this.get_selected_nodeid();
+      this.jm.update_node(selectedId, this.nodeOption.content);
+      this.jm.set_node_font_style(
+        selectedId,
+        this.nodeOption.fontSize,
+        this.nodeOption.fontWeight,
+        this.nodeOption.fontStyle
+      );
+      this.jm.set_node_color(
+        selectedId,
+        this.nodeOption.bgColor,
+        this.nodeOption.fontColor
+      );
+      this.nodeOption = {
+        content: "",
+        bgColor: "",
+        fontColor: "",
+        fontSize: "",
+        fontWeight: "",
+        fontStyle: "",
+      };
+      this.dialogVisible = false;
+    },
+  },
+  beforeDestroy() {
+    // document.removeEventListener("domMouseScroll", this.scrollFunc, false);
+  },
+};
+</script>
+
+<style scoped>
+.jsmind_layout {
+  display: flex;
+  flex-direction: column;
+  /* width: 700px; */
+  height: calc(100%);
+  /* height: 500px; */
+  /* margin: 15px 5px 0 0; */
+  /* background: #fff; */
+  overflow: hidden;
+  flex-shrink: 0;
+  position: relative;
+  width: 100%;
+  width: 100%;
+  background: #f1f1f1;
+  border-radius: 5px;
+}
+
+.jsmind_title {
+  position: absolute;
+  top: 20px;
+  left: 20px;
+  font-size: 20px;
+  color: #8d8d8d;
+}
+
+.noMind {
+  /* position: absolute; */
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 200px;
+  background: #fff;
+}
+
+.jsmind_layout .jsmind_toolbar {
+  width: 100%;
+  padding: 0 10px 10px 10px;
+  height: auto;
+  flex-shrink: 0;
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  background-color: #f8f9fa;
+  box-shadow: 0 0 4px #b8b8b8;
+}
+
+.jsmind_layout>>>.el-button--medium,
+.jsmind_layout>>>.el-input--medium {
+  margin-top: 10px;
+}
+
+.jsmind_layout #jsmind_container {
+  /* flex: 1 1 auto; */
+  height: 100%;
+}
+
+.jsmind_layout .jsmind_container {
+  /* flex: 1 1 auto; */
+  height: 100%;
+}
+
+.jsmind_layout>>>.jsmind-inner {
+  /* overflow: hidden auto !important; */
+  /* height: auto; */
+}
+
+.jsmind_layout>>>.el-upload-list {
+  display: none !important;
+}
+
+/* 隐藏滚动条 */
+.jsmind_layout .jsmind-inner::-webkit-scrollbar {
+  display: none;
+}
+
+.jsmind_layout .pad {
+  margin-right: 10px;
+}
+
+.jsmind_layout .pad-left {
+  margin-left: 10px;
+}
+
+.jsmind_layout>>>jmnode {
+  white-space: inherit;
+  word-wrap: break-word;
+  max-width: 500px;
+  max-height: 75px;
+  overflow: auto;
+}
+
+.jsmind_layout>>>jmnode::-webkit-scrollbar {
+  /*滚动条整体样式*/
+  width: 6px;
+  /*高宽分别对应横竖滚动条的尺寸*/
+  height: 6px;
+}
+
+/*定义滚动条轨道 内阴影+圆角*/
+.jsmind_layout>>>jmnode::-webkit-scrollbar-track {
+  border-radius: 10px;
+  background-color: rgba(0, 0, 0, 0.1);
+}
+
+/*定义滑块 内阴影+圆角*/
+.jsmind_layout>>>jmnode::-webkit-scrollbar-thumb {
+  border-radius: 10px;
+  -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
+  background-color: rgba(0, 0, 0, 0.1);
+}
+
+.jsmind_layout>>>jmnode.selected {
+  background-color: #b9b9b9;
+  color: #fff;
+  box-shadow: 2px 2px 8px #777;
+}
+
+.jsmind_layout>>>jmnode.selected {
+  background-color: #b9b9b9;
+  color: #fff;
+  box-shadow: 2px 2px 8px #777;
+}
+
+.jsmind_layout>>>jmnode:hover {
+  box-shadow: 2px 2px 8px #777;
+}
+
+.jsmind_layout .form-con {
+  padding-top: 20px;
+}
+
+.jsmind_layout .ele-width {
+  width: 96%;
+}
+</style>

+ 1 - 0
src/components/pages/teacherOffice/index.vue

@@ -648,6 +648,7 @@ export default {
           this.total = res.data[0].length > 0 ? res.data[0][0].num : 0;
           this.tableData = res.data[0];
           console.log(this.tableData, "tableData");
+          this.selectGrage()
         })
         .catch((err) => {
           this.isLoading = false;