11wqe1 7 months ago
parent
commit
fc4b28416b

+ 22 - 0
package-lock.json

@@ -13,6 +13,7 @@
         "dayjs": "^1.11.7",
         "diff": "^5.1.0",
         "echarts": "^5.2.2",
+        "echarts-wordcloud": "^2.1.0",
         "element-ui": "^2.15.6",
         "file-saver": "^2.0.5",
         "gantt-elastic": "^1.0.12",
@@ -10360,6 +10361,14 @@
         "zrender": "5.2.1"
       }
     },
+    "node_modules/echarts-wordcloud": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/echarts-wordcloud/-/echarts-wordcloud-2.1.0.tgz",
+      "integrity": "sha512-Kt1JmbcROgb+3IMI48KZECK2AP5lG6bSsOEs+AsuwaWJxQom31RTNd6NFYI01E/YaI1PFZeueaupjlmzSQasjQ==",
+      "peerDependencies": {
+        "echarts": "^5.0.1"
+      }
+    },
     "node_modules/echarts/node_modules/tslib": {
       "version": "2.3.0",
       "resolved": "https://registry.nlark.com/tslib/download/tslib-2.3.0.tgz?cache=0&sync_timestamp=1628722556410&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftslib%2Fdownload%2Ftslib-2.3.0.tgz",
@@ -32542,6 +32551,12 @@
         }
       }
     },
+    "echarts-wordcloud": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/echarts-wordcloud/-/echarts-wordcloud-2.1.0.tgz",
+      "integrity": "sha512-Kt1JmbcROgb+3IMI48KZECK2AP5lG6bSsOEs+AsuwaWJxQom31RTNd6NFYI01E/YaI1PFZeueaupjlmzSQasjQ==",
+      "requires": {}
+    },
     "ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz",
@@ -37336,6 +37351,7 @@
         "dayjs": "^1.11.7",
         "diff": "^5.1.0",
         "echarts": "^5.2.2",
+        "echarts-wordcloud": "2.1.0",
         "element-ui": "^2.15.6",
         "extract-text-webpack-plugin": "^3.0.0",
         "file-loader": "^1.1.4",
@@ -45754,6 +45770,12 @@
             }
           }
         },
+        "echarts-wordcloud": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmmirror.com/echarts-wordcloud/-/echarts-wordcloud-2.1.0.tgz",
+          "integrity": "sha512-Kt1JmbcROgb+3IMI48KZECK2AP5lG6bSsOEs+AsuwaWJxQom31RTNd6NFYI01E/YaI1PFZeueaupjlmzSQasjQ==",
+          "requires": {}
+        },
         "ee-first": {
           "version": "1.1.1",
           "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz",

+ 1 - 0
package.json

@@ -17,6 +17,7 @@
     "dayjs": "^1.11.7",
     "diff": "^5.1.0",
     "echarts": "^5.2.2",
+    "echarts-wordcloud": "^2.1.0",
     "element-ui": "^2.15.6",
     "file-saver": "^2.0.5",
     "gantt-elastic": "^1.0.12",

+ 141 - 231
src/components/components/choseWordCloud.vue

@@ -1,253 +1,163 @@
 <template>
-    <div>
-        <!-- <el-dialog title="词云" :visible.sync="dialogVisibleWordCloud" :append-to-body="true" width="800px"
-            :before-close="handleClose" class="dialog_diy dialog_diy3"> -->
-            <div class="wordCloud__tagBall" :style="{ width: `500px`, height: `500px` }" @mouseenter="stop"
-                @mouseleave="start" v-if="data.length">
-                <span class="wordCloud__tag" v-for="(item, index) of data" :key="index"
-                    :style="{ color: color[index % color.length], ...contentEle[index].style }"
-                    :title="item.name ">{{ item.name }}</span>
-                    <!-- + item.value -->
-            </div>
-            <div class="noneBox" v-else>暂无内容</div>
-        <!-- </el-dialog> -->
-    </div>
+  <div v-loading="loading">
+	<div class="chart" id="charts_canvas" ref="chartRef"></div>
+  </div>
 </template>
-   
-   
+
 <script>
+import { v4 as uuidv4 } from "uuid";
+import * as echarts from 'echarts';
+import "echarts-wordcloud";
 export default {
-    name: 'cloudWork',
-    props: {
-        dialogVisibleWordCloud: {
-            type: Boolean,
-        },
-        // 测试数据
-        data: {
-            type: Array,
-            default: () => []
-        }
-    },
-    data: () => ({
-        color: ['#2D4DB6', '#04B67C', '#D1AF07', '#E27914', '#CB4A4D', '#B02690'],
-        contentEle: [],
-        direction: '-1',
-        speed: 400,
-        animateID: null,
-        width:500,
-        height:500,
-    }),
-    watch: {
-        dialogVisibleWordCloud(newValue, oldValue) {
-            if(newValue){
-                this.contentEle = this.data.map(() => ({
-                    x: 0,
-                    y: 0,
-                    z: 0,
-                    style: {}
-                }));
-                this.innit();
-            }else{
-                window.cancelAnimationFrame(this.animateID);
-            }
-        }
+  name: "cloudWork",
+  props: {
+    dialogVisibleWordCloud: {
+      type: Boolean
     },
-    created() {
-        // this.contentEle = this.data.map(() => ({
-        //     x: 0,
-        //     y: 0,
-        //     z: 0,
-        //     style: {}
-        // }));
-    },
-    mounted() {
-        this.innit();
-    },
-    methods: {
-        handleClose(done) {
-            this.close();
-            // done()
-        },
-        close() {
-            this.$emit("update:dialogVisibleWordCloud", false)
-        },
-        innit() {
-            const RADIUSX = (this.width - 50) / 2;
-            const RADIUSY = (this.height - 50) / 2;
-            this.contentEle = [];
-            for (let i = 0; i < this.data.length; i += 1) {
-                const k = -1 + (2 * (i + 1) - 1) / this.data.length;
-                const a = Math.acos(k);
-                const b = a * Math.sqrt(this.data.length * Math.PI);
-                const x = RADIUSX * Math.sin(a) * Math.cos(b);
-                const y = RADIUSY * Math.sin(a) * Math.sin(b);
-                const z = RADIUSX * Math.cos(a);
-                const singleEle = {
-                    x,
-                    y,
-                    z,
-                    style: {}
-                };
-                this.contentEle.push(singleEle);
-            }
-            this.animate();
-        },
-        animate() {
-            this.rotateX();
-            this.rotateY();
-            this.move();
-            this.animateID = window.requestAnimationFrame(this.animate);
-        },
-        rotateX() {
-            const angleX = ['-1', '1'].includes(this.direction)
-                ? Math.PI / Infinity
-                : Math.PI / ((Number(this.direction) / 2) * Number(this.speed));
-            const cos = Math.cos(angleX);
-            const sin = Math.sin(angleX);
-
-            this.contentEle = this.contentEle.map((t) => {
-                const y1 = t.y * cos - t.z * sin;
-                const z1 = t.z * cos + t.y * sin;
-                return {
-                    ...t,
-                    y: y1,
-                    z: z1
-                };
-            });
-        },
-        rotateY() {
-            const angleY = ['-2', '2'].includes(this.direction)
-                ? Math.PI / Infinity
-                : Math.PI / (Number(this.direction) * Number(this.speed));
-            const cos = Math.cos(angleY);
-            const sin = Math.sin(angleY);
-            this.contentEle = this.contentEle.map((t) => {
-                const x1 = t.x * cos - t.z * sin;
-                const z1 = t.z * cos + t.x * sin;
-                return {
-                    ...t,
-                    x: x1,
-                    z: z1
-                };
-            });
-        },
-        move() {
-            const CX = this.width / 2;
-            const CY = this.height / 2;
-            this.contentEle = this.contentEle.map((singleEle) => {
-                const { x, y, z } = singleEle;
-                const fallLength = 500;
-                const RADIUS = (this.width - 50) / 2;
-                const scale = fallLength / (fallLength - z);
-                const alpha = (z + RADIUS) / (2 * RADIUS);
-                const left = `${x + CX - 15}px`;
-                const top = `${y + CY - 15}px`;
-                const transform = `translate(${left}, ${top}) scale(${scale})`;
-                const style = {
-                    ...singleEle.style,
-                    opacity: alpha + 0.5,
-                    zIndex: parseInt(scale * 100, 10),
-                    transform
-                };
-                return {
-                    x,
-                    y,
-                    z,
-                    style
-                };
-            });
-        },
-        // 鼠标移入暂停
-        stop() {
-            window.cancelAnimationFrame(this.animateID);
-        },
-        // 鼠标离开恢复
-        start() {
-            this.animate();
-        }
+    // 测试数据
+    cloudData: {
+      type: String,
+      default: ''
     }
-};
-</script>
-   
-   
-<style  scoped>
-@media screen and (max-width: 1280px) {
-    .dialog_diy3>>>.el-dialog {
-        width: 100% !important;
+  },
+  data() {
+    return {
+        chartObj:"",
+        loading:false
     }
-}
+  },
 
-.dialog_diy>>>.el-dialog {
-    margin-top: 10vh !important;
-}
+  mounted() {
+    this.addNephogram();
+  },
+  methods: {
+    //添加云图
+    addNephogram() {
+        this.loading=true
+      const _msg = `NOTICE
+        Language: Please use the same language as the user requirement, if the user speaks Chinese, the specific text of your answer should also be in Chinese.
+        ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
+        Instruction: Based on the context, follow "Format example", write content.
 
-.dialog_diy>>>.el-dialog__header {
-    background: #454545 !important;
-    padding: 15px 20px;
-}
+        ## 任务
 
-.dialog_diy>>>.el-dialog__title,
-.dialog_diy1>>>.el-dialog__title {
-    color: #fff;
-}
+        请基于以下学生回答,提炼出10-20个答案,用于绘制词云图。
 
-.dialog_diy>>>.el-dialog__headerbtn {
-    top: 19px;
-}
+        ## 要求
 
-.dialog_diy>>>.el-dialog__headerbtn .el-dialog__close {
-    color: #fff;
-}
+        1. **提取关键词**:从提供的答案文本中提取出10-20个最具代表性的答案。
+        2. **词频统计**:计算每个关键字在文本中出现的频率。
+        3. **词汇大小**:根据词频数量,确定每个关键字在词云图中的大小。词频越高,词汇大小数值越大,数值范围1-100。
+        4. **输出格式**:输出结果应包含每个关键字、对应的词频数量以及词汇大小数值。
 
-.dialog_diy>>>.el-dialog__headerbtn .el-dialog__close:hover {
-    color: #fff;
-}
+        ## 输出格式
 
-.dialog_diy>>>.el-dialog__body {
-    overflow:hidden;
-}
+        ### 输出格式
 
-.dialog_diy>>>.el-dialog__body,
-.dialog_diy>>>.el-dialog__footer {
-    background: #fafafa;
-    
-}
+        [
+            {"value":1,"name":"氯化钠","textStyle":{"color":"#ee7959"}},
+            {"value":2,"name":"溶液","textStyle":{"color":"#db9b34"}},
+            {"value":1,"name":"实验","textStyle":{"color":"#9d9d82"}},
+            {"value":3,"name":"质量分数","textStyle":{"color":"#ea5514"}},
+            {"value":1,"name":"溶质","textStyle":{"color":"#c8161d"}},
+            {"value":2,"name":"氢氧化钠","textStyle":{"color":"#e60012"}},
+            {"value":1,"name":"溶解度","textStyle":{"color":"#1e2732"}},
+            {"value":4,"name":"饱和溶液","textStyle":{"color":"#e3adb9"}}
+        ]
 
-button {
-    margin: 20px;
-}
+        请仅仅输出表头,输出关键词和相应的内容,无需其它任何说明文字。
+        冒号、逗号等符号均使用英文字符。
 
-.wordCloud__tagBall {
-    margin: 0px auto;
-    position: relative;
-}
+        ### 输出示例
 
-.wordCloud__tag {
-    display: block;
-    position: absolute;
-    left: 0px;
-    top: 0px;
-    color: green;
-    text-decoration: none;
-    font-size: 15px;
-    font-family: '微软雅黑';
-    font-weight: bold;
-}
+        [
+            {"value":1,"name":"氯化钠","textStyle":{"color":"#ee7959"}},
+            {"value":2,"name":"溶液","textStyle":{"color":"#db9b34"}},
+            {"value":1,"name":"实验","textStyle":{"color":"#9d9d82"}},
+            {"value":3,"name":"质量分数","textStyle":{"color":"#ea5514"}},
+            {"value":1,"name":"溶质","textStyle":{"color":"#c8161d"}},
+            {"value":2,"name":"氢氧化钠","textStyle":{"color":"#e60012"}},
+            {"value":1,"name":"溶解度","textStyle":{"color":"#1e2732"}},
+            {"value":4,"name":"饱和溶液","textStyle":{"color":"#e3adb9"}}
+        ]
 
-.wordCloud__tag :hover {
-    color: red;
-}
+        ## 课堂实录 
+        ${this.cloudData ? this.cloudData : ""}
+        `;
+      const _uuid = uuidv4();
+      let params = {
+        temperature: 0,
+        max_tokens: 4096,
+        top_p: 1,
+        frequency_penalty: 0,
+        presence_penalty: 0,
+        messages: [{ role: "user", content: _msg }],
+        uid: _uuid,
+        mind_map_question: "",
+        stream: false,
+        model: "gpt-4o-2024-11-20"
+      };
+      this.ajax
+        .post("https://gpt4.cocorobo.cn/chat", params)
+        .then(res => {
+          let _data = res.data.FunctionResponse.choices[0];
+          let _jsonData = _data.message.content;
+          _jsonData = _jsonData.replaceAll("```json", "").replaceAll("```", "");
+          let _result = JSON.parse(_jsonData);
+          console.log('_result',_result);
 
-.wordCloud__home {
-    display: flex;
-    justify-content: center;
-}
+          let poi = {
+            tooltip: {
+              show: false
+            },
+            series: [
+              {
+                type: "wordCloud",
+                sizeRange: [14, 38],
+                rotationRange: [0, 0],
+                keepAspect: false,
+                shape: "circle",
+                left: "center",
+                top: "center",
+                right: null,
+                bottom: null,
+                width: "90%",
+                height: "90%",
+                rotationRange: [-90, 90],
+                rotationStep: 45,
+                data: _result
+              }
+            ]
+          }
+          console.log('poi',poi);
+          this.getChartData(poi)
+        //   this.saveData(poi)
+        })
+        .catch(e => {
+          console.log(e);
+          this.$message.error("生成词云图失败");
+        })
+        .finally(_ => {
+        });
+    },
+   
+    getChartData(poi) {	
+        this.chartObj = echarts.init(this.$refs.chartRef);
+        this.chartObj.setOption(poi);
+        this.loading=false
+        window.addEventListener("resize", () => {
+                this.chartObj.resize();
+        });
+	},
+  }
+};
+</script>
 
-.noneBox{
-    height:500px;
-    width:100%;
-    display:flex;
-    align-items:center;
-    justify-content:center;
+<style scoped>
+.chart {
+	width: 100%;
+	height: 500px;
+	background-color: #fff;
 }
-</style>
+
+</style>

+ 22 - 36
src/components/components/choseWorksDetailDialog.vue

@@ -128,8 +128,8 @@
 
 								<div v-if="[15].includes(toolType)" class="s_b_m_b_i_m_question">
 									<div class="s_b_m_b_i_m_c_title">
-                    <span>{{1 }}</span>
-                    <svg
+                     <span></span>
+                   <!-- <svg
                       width="16"
                       height="16"
                       viewBox="0 0 16 16"
@@ -140,9 +140,9 @@
                         d="M15.3536 8.35355C15.5488 8.15829 15.5488 7.84171 15.3536 7.64645L12.1716 4.46447C11.9763 4.2692 11.6597 4.2692 11.4645 4.46447C11.2692 4.65973 11.2692 4.97631 11.4645 5.17157L14.2929 8L11.4645 10.8284C11.2692 11.0237 11.2692 11.3403 11.4645 11.5355C11.6597 11.7308 11.9763 11.7308 12.1716 11.5355L15.3536 8.35355ZM1 8.5H15V7.5H1V8.5Z"
                         fill="#3681FC"
                       />
-                    </svg>
-
-                    <span v-if="testJson && testJson.answerTitle">提问:</span>
+                    </svg> -->
+                
+                    <span>提问:{{ testData.answerQ }}</span>
                   </div>
                   <!-- v-if="testJsonCopy && testJsonCopy.answer"  -->
 									<span style="padding: 10px;">
@@ -266,7 +266,6 @@
                     <!-- <div class="cont" v-if="testData && testData.tableJson && testData.tableJson.text" v-html="testData.tableJson.text"></div>                 -->
                 </div>
                 <div v-if="[49].includes(toolType)" class="s_b_m_b_i_m_evaluation">
-                  <!-- {{ testData.groupJson }} -->
                   <div>
                     <div
                       class="g_d_box"
@@ -379,13 +378,14 @@
 								</div>
 								
 								<div class="s_b_m_b_i_e_charts_bottom">
-									<span v-if="accuracyRateData" v-for="(item,index) in accuracyRateData.series[0].data">第{{ index+1 }}题 {{ item }}%</span>
+									<span style="cursor: pointer;" v-if="accuracyRateData" @click="jumpTo(index)" v-for="(item,index) in accuracyRateData.series[0].data">第{{ index+1 }}题 {{ item }}%</span>
 								</div>
 							</div>
 
               <div class="s_b_m_b_i_table">
                 <div
                   class="s_b_m_b_i_m_choseList"
+                  :id="index+'JP'"
                   v-for="(item, index) in tableData"
                 >
                   <div class="s_b_m_b_i_m_c_title">
@@ -435,11 +435,12 @@
                       </el-table-column>
                     </el-table>
                   </div>
+
                 </div>
               </div>
               </div>
 							<div v-if="toolType == 15">
-                <choseWordCloud :data="cy" :dialogVisibleWordCloud="dialogVisibleWordCloud"></choseWordCloud>
+                <choseWordCloud :cloudData="cy" :dialogVisibleWordCloud="dialogVisibleWordCloud"></choseWordCloud>
               </div>
               
 
@@ -657,9 +658,9 @@ export default {
         worksPreview: false
       },
       dialogTypeList: [
-        { label: "作业详细", value: 0,showType:[45,15,41,47,40,48,1,49,7], loading: false },
+        { label: "作业详细", value: 0,showType:[1,7,15,40,41,45,47,48,49,52], loading: false },
         { label: "题目统计", value: 1,showType:[45,15], loading: false },
-        { label: "学生统计", value: 2,showType:[45,15,41,47,40,7,52,48,1], loading: false }
+        { label: "学生统计", value: 2,showType:[1,7,15,40,41,45,47,48,52], loading: false }
       ],
 			toolList:[
 				{label:"选择题",value:45,img:require("../../assets/icon/thirdToolList/choose.png")},
@@ -875,12 +876,11 @@ export default {
 			}
 		},
     cy(){
-      let _result = []
+      let _result = ''
       if(this.toolType===15){
-        let array = this.worksStudent.map(e=>{
-        return {name: JSON.parse(e.works)[0].answer}
-      });
-      _result = array;
+        this.worksStudent.forEach(e=>{
+          _result += JSON.parse(e.works)[0].answer+','
+        })
       }
 
       return _result;
@@ -952,6 +952,13 @@ export default {
     }
   },
   methods: {
+    jumpTo(val){
+      let a = document.getElementById(val+"JP");
+      a.scrollIntoView({
+        behavior: "smooth" // 平滑滚动效果
+      });
+      
+    },
     open(data) {
       if (this.show) return;
       this.show = true;
@@ -964,27 +971,6 @@ export default {
       this.setData();
     },
     openWordCloud() {
-
-      // let array = this.worksStudent.map(e=>{
-      //   return {name: JSON.parse(e.works)[0].answer}
-      // });
-      // console.log('array',array);
-      
-      // for (var i = 0; i < this.worksStudent.length; i++) {
-      //   let works = JSON.parse(this.worksStudent[i].works)[0].answer;
-      //   array.push({ name: works });
-      // }
-      // if (this.isGroup) {
-      //   for (var i = 0; i < this.courseGroup.group.length; i++) {
-      //     let works = this.courseGroup.group[i].works[toolindex];
-      //     for (var j = 0; j < works.length; j++) {
-      //       let answer = JSON.parse(works[j].works)[0].answer;
-      //       array.push({ name: answer });
-      //     }
-      //   }
-      // }
-
-      // this.wordCloudData = array;
       this.dialogVisibleWordCloud = true
     },
     StudentWork(val){

+ 1 - 1
src/components/easy2/studyStudent.vue

@@ -14704,7 +14704,7 @@
           <!-- <el-input v-model="groupJson.number" placeholder="2-10人以内"
             style="width: 150px; margin: 10px 10px 0 0"></el-input> -->
           <el-input
-            v-model="groupJson.number"
+            v-model="groupJson2.number"
             style="width: 150px"
             placeholder="请输入2-10的数字"
             @change="numberPan"

+ 1 - 1
src/components/easy3/studyStudent.vue

@@ -11525,7 +11525,7 @@
           <!-- <el-input v-model="groupJson.number" placeholder="2-10人以内"
             style="width: 150px; margin: 10px 10px 0 0"></el-input> -->
           <el-input
-            v-model="groupJson.number"
+            v-model="groupJson2.number"
             style="width: 150px"
             placeholder="请输入2-10的数字"
             @change="numberPan"

+ 1 - 1
src/components/studyStudent.vue

@@ -11470,7 +11470,7 @@
           <!-- <el-input v-model="groupJson.number" placeholder="2-10人以内"
             style="width: 150px; margin: 10px 10px 0 0"></el-input> -->
           <el-input
-            v-model="groupJson.number"
+            v-model="groupJson2.number"
             style="width: 150px"
             placeholder="请输入2-10的数字"
             @change="numberPan"

+ 1 - 1
src/components/studySutdentClass/studyStudent.vue

@@ -14465,7 +14465,7 @@
           <!-- <el-input v-model="groupJson.number" placeholder="2-10人以内"
             style="width: 150px; margin: 10px 10px 0 0"></el-input> -->
           <el-input
-            v-model="groupJson.number"
+            v-model="groupJson2.number"
             style="width: 150px"
             placeholder="请输入2-10的数字"
             @change="numberPan"