lsc 8 месяцев назад
Родитель
Сommit
d7f4a8afdd

+ 1 - 1
dist/index.html

@@ -27,7 +27,7 @@
     html,
     body{
       font-family: '黑体';
-    }</style><link href=./static/css/app.fb73f7e9e83e8bd78f18de631ec261a2.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.3ad1d5771e9b13dbdad2.js></script><script type=text/javascript src=./static/js/vendor.264e3d6e7c524117db80.js></script><script type=text/javascript src=./static/js/app.3c3b1402510d1312f06c.js></script></body></html><script>function stopSafari() {
+    }</style><link href=./static/css/app.1d3a43724b14043b9e6236a19c1555d9.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.3ad1d5771e9b13dbdad2.js></script><script type=text/javascript src=./static/js/vendor.264e3d6e7c524117db80.js></script><script type=text/javascript src=./static/js/app.311f22d965d1a60a504d.js></script></body></html><script>function stopSafari() {
     //阻止safari浏览器双击放大功能
     let lastTouchEnd = 0  //更新手指弹起的时间
     document.documentElement.addEventListener("touchstart", function (event) {

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/css/app.1d3a43724b14043b9e6236a19c1555d9.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/css/app.1d3a43724b14043b9e6236a19c1555d9.css.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/css/app.fb73f7e9e83e8bd78f18de631ec261a2.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/css/app.fb73f7e9e83e8bd78f18de631ec261a2.css.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/app.311f22d965d1a60a504d.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/app.311f22d965d1a60a504d.js.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/manifest.3ad1d5771e9b13dbdad2.js.map


+ 136 - 1
src/components/classRoomHelper/component/reviewArea.vue

@@ -162,6 +162,43 @@
           确定
         </div>
       </div>
+    </div>
+		<div
+      v-if="replyDialogVisible == true"
+      class="addDialogCss"
+      v-el-drag-dialog
+    >
+      <div class="pzTop">
+        <div class="teacherPz">
+          <div class="teacherPzImg">
+            <img src="../../../assets/icon/teacherPz.png" alt="" />
+          </div>
+          <div style="margin-left: 10px; height: 25px">添加回复</div>
+        </div>
+        <div @click="replyDialogVisible = false">
+          <img src="../../../assets/close1.png" class="pzClose" alt="" />
+        </div>
+      </div>
+      <div class="addPzBox">
+        <!-- <div class="addPzCheck">
+          <span :class="{ isChooseActive: pzType == 1 }" @click="pzType = 1"
+            >文本</span
+          >
+          <span :class="{ isChooseActive: pzType == 2 }" @click="pzType = 2"
+            >音频</span
+          >
+        </div> -->
+        <div style="height: calc(100% - 50px)">
+          <editor-bar
+            class="binfo_input pzConText"
+            style="width: 100% !important; margin: 0 auto"
+            placeholder="请输入回复描述"
+            v-model="reply"
+            @change="change"
+          ></editor-bar>
+        </div>
+        <div class="addTextCss" @click="addHf">确定</div>
+      </div>
     </div>
   </div>
 </template>
@@ -209,13 +246,83 @@ export default {
 			addPzDialog:false,
 			pzType:0,
 			pzConText:"",
+			reply:"",
 			scoreList:{
 				datalist:[],
 				isScoreList:[]
 			},
+			replyIndex: 0,
+      replyPid: "",
+			replyDialogVisible: false,
     };
   },
   methods: {
+		deleteReply(id) {
+      this.$confirm("确定删除此回复吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          let params = [
+            {
+              id: id,
+            },
+          ];
+          this.ajax
+            .post(this.$store.state.api + "deleteReply", params)
+            .then((res) => {
+              this.$message({
+                message: "删除成功",
+                type: "success",
+              });
+              this.selectPz();
+            })
+            .catch((err) => {
+              this.$message.error("网络异常");
+              console.error(err);
+            });
+        })
+        .catch(() => {});
+    },
+		addHf() {
+      if (this.reply == "") {
+        this.$message.error("回复不能为空!");
+        return;
+      }
+      let params = [
+        {
+          cid: this.id,
+          uid: this.userid,
+          s: this.courseType,
+          t: this.taskCount,
+          type: "1",
+          ct: 2,
+          pid: this.replyPid,
+          c: this.reply,
+        },
+      ];
+      this.ajax
+        .post(this.$store.state.api + "addHf", params)
+        .then((res) => {
+          this.reply = "";
+          this.$message({
+            message: "回复成功",
+            type: "success",
+          });
+          this.replyDialogVisible = false;
+          this.selectPz();
+        })
+        .catch((err) => {
+          this.$message.error("回复失败");
+          console.error(err);
+        });
+    },
+		setReplyIndex(id, i) {
+      this.replyIndex = i;
+      this.replyPid = id;
+      this.replyDialogVisible = true;
+    },
 		insertMemorandum(_html) {
       //保存行为操作
       //variable
@@ -323,7 +430,35 @@ export default {
     },
 		change(val){
 			console.log(val);
-		}
+		},
+		deletePz(id) {
+      this.$confirm("确定删除此评论吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          let params = [
+            {
+              id: id,
+            },
+          ];
+          this.ajax
+            .post(this.$store.state.api + "deletePz", params)
+            .then((res) => {
+              this.$message({
+                message: "删除成功",
+                type: "success",
+              });
+              this.selectPz();
+            })
+            .catch((err) => {
+              this.$message.error("网络异常");
+              console.error(err);
+            });
+        })
+        .catch(() => {});
+    },
   },
 	mounted() {
 		this.selectPz();

+ 331 - 0
src/components/classRoomHelper/component/uploadFile.vue

@@ -0,0 +1,331 @@
+<template>
+	<div class="uploadBox"></div>
+</template>
+
+<script>
+import "../../../common/aws-sdk-2.235.1.min.js";
+export default {
+	props:{
+		index:{
+			type:String,
+			default:"0"
+		},
+	},
+	data() {
+		return {
+			bucket: "", //aws上传接口
+			bucketname: "ccrb", //桶
+			uploadid: "",
+			partsize: 10 * 1024 * 1024, //10MB  分片
+			filestate: {
+				status: "", //有 error(直接报错) 和 fail(上传的时候报错) 和 success(上传成功) 和 processing(上传中)
+				percent: "", //(0-100的进度)
+			},
+			file: null,
+			flag:true,
+		};
+	},
+	watch: {
+		filestate: {
+			handler(newValue) {
+				this.$emit("progressUpdate", {index:this.index,...newValue});
+			},
+			immediate: true,
+			deep: true,
+		},
+	},
+	methods: {
+		//--------------------------分断上传保证稳定性
+		//初始化上传
+		// async init(){
+		// 	const credentials = {
+		// 	    accessKeyId: "AKIATLPEDU37QV5CHLMH",
+		// 	    secretAccessKey: "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",
+		// 	}; //秘钥形式的登录上传
+		// 	window.AWS.config.update(credentials);
+		// 	window.AWS.config.region = "cn-northwest-1"; //设置区域
+		// 	//桶的设置
+		// 	bucket = new window.AWS.S3({
+		// 	    params: {
+		// 	        Bucket: this.bucketname
+		// 	    }
+		// 	});
+		// 	return bucket;
+		// },
+		// 初始化上传入口
+		async initMultipartUpload(key, file) {
+			console.log(file)
+			const params = {
+				Bucket: this.bucketname,
+				Key: key,
+				ContentType: file.type,
+				ACL: "public-read",
+			};
+			//创建一个续传通道
+			const data = await this.bucket.createMultipartUpload(params).promise();
+			return data.UploadId;
+		},
+		// 上传文件的某一部分
+		async uploadPart(file, keyname, uploadid, pn, start, end) {
+			//key可以设置为桶的相对路径,Body为文件, ACL最好要设置
+			if(!this.flag)return;
+			var params = {
+				Bucket: this.bucketname,
+				Key: keyname,
+				// ContentType: file.type,
+				PartNumber: pn,
+				UploadId: uploadid,
+				Body: file.slice(start, end),
+				// "Access-Control-Allow-Credentials": "*",
+				// ACL: "public-read",
+			};
+			const result = await this.bucket.uploadPart(params).promise();
+			return { ETag: result.ETag, PartNumber: pn };
+		},
+		//完成分块上传
+		async completeMultipartUpload(parts, keyname, uploadid) {
+			if(!this.flag)return;
+			const params = {
+				Bucket: this.bucketname,
+				Key: keyname,
+				MultipartUpload: { Parts: parts },
+				UploadId: uploadid,
+			};
+			return await this.bucket.completeMultipartUpload(params).promise();
+		},
+		async abortMultipartUpload(key, uploadid) {
+			const params = {
+				Bucket: this.bucketname,
+				Key: key,
+				UploadId: uploadid,
+			};
+			let data = await this.bucket.abortMultipartUpload(params).promise();
+			this.$emit("delUpload",{index:this.index})
+			
+		},
+		//--------------------------------下面支持断点续传
+
+		//初始化亚马逊参数
+		async init() {
+			//秘钥形式的登录上传
+			const credentials = {
+				accessKeyId: "AKIATLPEDU37QV5CHLMH",
+				secretAccessKey: "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",
+				region: "cn-northwest-1",
+			};
+			window.AWS.config.update(credentials);
+			// window.AWS.config.region = "cn-northwest-1"; //设置区域
+			//桶的设置
+			this.bucket = new window.AWS.S3({
+				params: {
+					Bucket: this.bucketname,
+				},
+			});
+			return this.bucket;
+		},
+
+		//获取当前文件是否有已上传断点信息
+		async getawscheckpoint(key) {
+			let partsinfo;
+			try {
+				const result = await this.bucket
+					.listMultipartUploads({ Bucket: this.bucketname, Prefix: key })
+					.promise();
+				//获取具体分片信息
+				if (result.Uploads.length) {
+					this.uploadid = result.Uploads[result.Uploads.length - 1].UploadId;
+					partsinfo = await this.bucket
+						.listParts({
+							Bucket: this.bucketname,
+							Key: key,
+							UploadId: this.uploadid,
+						})
+						.promise();
+				}
+			} catch (err) {
+				console.log(err);
+			}
+			return { uploadid: this.uploadid, partsinfo };
+		},
+
+		//分段上传
+		async awsuploadpart(filestate, file, uploadid, parts, key) {
+			var partarr = []; //已完成的数组
+			//已完成的分片,转化成提交格式
+			const completeparts = parts.map((_) => {
+				partarr.push(_.PartNumber);
+				return { PartNumber: _.PartNumber, ETag: _.ETag };
+			});
+			// 分块上传文件
+			// parts = [];
+			let uploadpart;
+			let start = 0;
+			let end = 0;
+			let len = Math.ceil(file.size / this.partsize); //循环的长度
+			if (partarr.length) {
+				this.filestate.status = "processing";
+				this.filestate.percent = parseInt((completeparts.length * 100) / len);
+			}
+			//循环上传
+			for (let i = 0; i < len; i++) {
+				if(!this.flag)break;
+				start = i * this.partsize;
+				end = (i + 1) * this.partsize;
+				if (!partarr.includes(i+1)) {
+
+					uploadpart = await this.uploadPart(
+						file,
+						key,
+						uploadid,
+						i + 1,
+						start,
+						end
+					);
+					if (uploadpart.ETag != null) {
+						completeparts.push(uploadpart);
+						partarr.push(uploadpart.PartNumber);
+						this.filestate.status = "processing";
+						this.filestate.percent = parseInt(
+							(completeparts.length * 100) / len
+						);
+					} else {
+						this.filestate.status = "fail";
+						this.stopUpload();
+						return;
+					}
+				}
+			}
+			//提交上传成功信息
+			if(this.flag){
+					let data = await this.completeMultipartUpload(
+					completeparts,
+					key,
+					uploadid
+				);
+				this.filestate.status = "success";
+				return data;
+			}
+		},
+
+		//上传的接口
+		async awsupload({ file = this.file, keyName, folderName }) {
+			if (!file) return this.$message.error("请上传文件");
+			this.init(); //初始化桶
+			// const key = (folderid || uuidv4()) + "/" + file.name; //需要上传的文件名
+			let key = "";
+			if (keyName) {
+				key = keyName;
+			} else {
+				if (folderName) {
+					key = `${folderName}/${file.name}`;
+				} else {
+					key = `default/${file.name.split(".")[0] +
+							new Date().getTime() +
+							"." +
+							file.name.split(".")[file.name.split(".").length - 1]}`;
+				}
+			}
+			console.log(key);
+			// key = key.replace(/\s/g, "");
+			// key = encodeURIComponent(key);
+			this.filestate = {
+				percent: 0,
+				status: "start",
+			};
+			this.filestate.percent = 0;
+			this.filestate.status = "start";
+			this.file = file;
+			//上传的参数
+			var params = {
+				Bucket: this.bucketname,
+				Key: key,
+			};
+			this.flag = true;
+			//设置桶上传文件
+			try {
+				//检查文件是否已上传
+				this.bucket.headObject(params, async (err, data) => {
+					// 没有上传成功,head方法会返回失败
+					if (err) {
+						//检查是否部分上传
+						const { uploadid, partsinfo } = await this.getawscheckpoint(
+							key,
+							this.bucket
+						);
+						//如果已经部分存在,那么直接在节点续传
+						if (uploadid) {
+							//断点续传
+							this.$emit("startUpload", { index:this.index,key, uploadid });
+							this.filestate.key = key;
+							this.filestate.uploadid = uploadid;
+							this.flag = true;
+							let data = await this.awsuploadpart(
+								this.filestate,
+								file,
+								uploadid,
+								partsinfo.Parts,
+								key
+							);
+							if(this.flag || this.filestate.percent==100)return this.$emit("success", {index:this.index, data, key, uploadid });
+							// return {data,key,uploadid}
+						}
+						//不存在,上传新的
+						else {
+							const uploadid = await this.initMultipartUpload(key, file); //初始化文件上传
+							this.$emit("startUpload", { index:this.index,key, uploadid });
+							this.filestate.key = key;
+							this.filestate.uploadid = uploadid;
+							this.flag = true;
+							let data = await this.awsuploadpart(
+								this.filestate,
+								file,
+								uploadid,
+								[],
+								key
+							);
+							if(this.flag || this.filestate.percent==100)return this.$emit("success", {index:this.index, data, key, uploadid });
+							// return {data,key,uploadid}
+						}
+					}
+					//如果已经上传成功了,那么直接返回状态百分百
+					else if (data) {
+						//data存在,上传成功
+						this.filestate.percent = 100;
+						this.filestate.status = "success";
+						let url = `https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/${key}`
+						this.file = null;
+						if(this.flag)return this.$emit("success", { index:this.index,data:{
+							Key:key,
+							Location:url,
+							ETag:data.ETag,
+							size:data.ContentLength,
+							ServerSideEncryption:data.ServerSideEncryption,
+							Bucket:this.bucketname
+							} });
+						// return {data,key,uploadid}
+					}
+				});
+			} catch (err) {
+				this.filestate.status = "error";
+				this.stopUpload();
+				console.log(err);
+			}
+		},
+		// 停止上传
+		stopUpload(){
+			this.filestate.status = "stop";
+			this.flag = false;
+		}
+	},
+	mounted() {
+		this.bucket = "";
+		this.file = null;
+	},
+};
+</script>
+
+<style scoped>
+.uploadBox {
+	display: none;
+}
+</style>

Разница между файлами не показана из-за своего большого размера
+ 32 - 4
src/components/classRoomHelper/index.vue


+ 1242 - 0
src/components/components/choseWorksDetailDialog.vue

@@ -0,0 +1,1242 @@
+<template>
+  <div class="choseWorksDetailDialog">
+    <el-dialog
+      :visible.sync="show"
+      width="100%"
+      height="100%"
+      fullscreen
+      :modal="true"
+      :close-on-click-modal="false"
+      :show-close="false"
+    >
+      <div class="s_box">
+        <div class="s_b_main">
+          <div class="s_b_m_top">
+            <div class="s_b_m_t_left">
+              <span
+                v-for="item in dialogTypeList"
+                :key="item.value"
+                :class="{ s_b_m_t_l_active: showType === item.value }"
+                @click="changeShowType(item.value)"
+                >{{ item.label }}</span
+              >
+            </div>
+            <div class="s_b_m_t_right">
+              <span @click="close">关闭</span>
+            </div>
+          </div>
+          <div class="s_b_m_bottom">
+            <div class="s_b_m_b_item" v-if="showType === 0">
+              <div class="s_b_m_b_i_main">
+                <div class="s_b_m_b_i_m_title" v-if="testData">
+                  <div>
+                    <svg
+                      t="1731461684123"
+                      class="icon"
+                      viewBox="0 0 1024 1024"
+                      version="1.1"
+                      xmlns="http://www.w3.org/2000/svg"
+                      p-id="4452"
+                      width="200"
+                      height="200"
+                    >
+                      <path
+                        d="M361.425 318.506h389.4v427.6h-389.4z"
+                        fill="#CFD5F8"
+                        p-id="4453"
+                      ></path>
+                      <path
+                        d="M773.825 514.306h-293.3v-48.1h293.3v48.1z m0-216.4h-293.3v48.1h293.3v-48.1z m0 336.7h-293.3v48.1h293.3v-48.1z m-415.5-168.4c-13.3 0.2-23.9 11.2-23.7 24.4 0.2 13.3 11.2 23.9 24.4 23.7 13.1-0.2 23.7-10.9 23.7-24 0-13.3-10.8-24.1-24-24.1h-0.4m0-48.1c39.8 0.6 71.6 33.5 71 73.3s-33.5 71.6-73.3 71c-39.4-0.6-71-32.7-71-72.2 0-39.9 32.3-72.2 72.2-72.2 0.3 0.1 0.7 0.1 1.1 0.1z m0-120.2c-13.3 0.2-23.9 11.2-23.7 24.4 0.2 13.3 11.2 23.9 24.4 23.7 13.1-0.2 23.7-10.9 23.7-24 0-13.3-10.8-24.1-24.1-24.1h-0.3m0-48.1c39.8 0.6 71.6 33.5 71 73.3s-33.5 71.6-73.3 71c-39.4-0.6-71-32.8-71-72.2 0-39.9 32.3-72.2 72.1-72.2 0.4 0 0.8 0 1.2 0.1z m0 384.8c-13.3 0.2-23.9 11.2-23.7 24.4 0.2 13.3 11.2 23.9 24.4 23.7 13.1-0.2 23.7-10.9 23.7-24 0-13.3-10.8-24.1-24-24.1h-0.4m0-48.2c39.8 0.6 71.6 33.5 71 73.3-0.6 39.8-33.5 71.6-73.3 71-39.4-0.6-71-32.7-71-72.2 0-39.9 32.3-72.2 72.2-72.2 0.3 0.1 0.7 0.1 1.1 0.1z"
+                        fill="#486EFF"
+                        p-id="4454"
+                      ></path>
+                    </svg>
+                    <span>选择题</span>
+                  </div>
+                  <span v-if="testData.toolDetail">{{ testData.toolDetail }}</span>
+                </div>
+
+                <span>题目内容</span>
+
+                <div
+                  class="s_b_m_b_i_m_choseList"
+                  v-for="(item, index) in testJson"
+                >
+                  <div class="s_b_m_b_i_m_c_title">
+                    <span>{{ index + 1 }}</span>
+                    <svg
+                      width="16"
+                      height="16"
+                      viewBox="0 0 16 16"
+                      fill="none"
+                      xmlns="http://www.w3.org/2000/svg"
+                    >
+                      <path
+                        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
+                      >{{
+                        typeof item.answer === "number"
+                          ? "单选题:"
+                          : "多选题:"
+                      }}{{ item.teststitle }}</span
+                    >
+                  </div>
+
+                  <div
+                    class="s_b_m_b_i_m_c_options"
+                    v-for="(item2, index2) in item.checkList"
+                    :class="{
+                      s_b_m_b_i_m_c_o_right:
+                        typeof item.answer === 'number'
+                          ? item.answer === index2
+                          : item.answer.includes(index2)
+                    }"
+                  >
+                    <div class="s_b_m_b_i_m_c_o_btn">
+                      <span
+                        class="s_b_m_b_i_m_c_o_btn1"
+                        v-if="typeof item.answer === 'number'"
+                      >
+                        <span v-if="item.answer === index2"></span>
+                      </span>
+                      <span class="s_b_m_b_i_m_c_o_btn2" v-else>
+                        <span v-if="item.answer.includes(index2)">
+                          <svg
+                            width="8"
+                            height="6"
+                            viewBox="0 0 8 6"
+                            fill="none"
+                            xmlns="http://www.w3.org/2000/svg"
+                          >
+                            <path
+                              fill-rule="evenodd"
+                              clip-rule="evenodd"
+                              d="M7.44194 0.558058C7.68602 0.802136 7.68602 1.19786 7.44194 1.44194L3.44194 5.44194C3.19786 5.68602 2.80214 5.68602 2.55806 5.44194L0.558058 3.44194C0.313981 3.19786 0.313981 2.80214 0.558058 2.55806C0.802136 2.31398 1.19786 2.31398 1.44194 2.55806L3 4.11612L6.55806 0.558058C6.80214 0.313981 7.19786 0.313981 7.44194 0.558058Z"
+                              fill="white"
+                            />
+                          </svg>
+                        </span>
+                      </span>
+                    </div>
+                    <span>
+                      <img
+                        v-if="item2.imgType && item2.imgType === 1"
+                        :src="item2.src"
+                        alt=""
+                        @click="$hevueImgPreview(item2.src)"
+                      />
+                      <span v-else>{{ item2 }}</span>
+                    </span>
+                  </div>
+                </div>
+              </div>
+            </div>
+            <div class="s_b_m_b_item" v-if="showType === 1">
+
+							<div class="s_b_m_b_i_eChartsArea">
+								<div class="s_b_m_b_i_e_title">
+									<span v-for="item in statisticsTypeList" :key="item.value" :class="{'s_b_m_b_i_e_t_active':showStatisticsType===item.value}" @click="changeShowStatisticsType(item.value)">{{item.label}}</span>
+								</div>
+								
+								<div class="s_b_m_b_i_e_charts">
+									<eChartsView1 v-if="showStatisticsType===0 && accuracyRateData" :data="accuracyRateData"/>
+									<eChartsView2 v-if="showStatisticsType===1 && optionSummaryData" :data="optionSummaryData"/>
+								</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>
+								</div>
+							</div>
+
+              <div class="s_b_m_b_i_table">
+                <div
+                  class="s_b_m_b_i_m_choseList"
+                  v-for="(item, index) in tableData"
+                >
+                  <div class="s_b_m_b_i_m_c_title">
+                    <span>{{ index + 1 }}</span>
+                    <svg
+                      width="16"
+                      height="16"
+                      viewBox="0 0 16 16"
+                      fill="none"
+                      xmlns="http://www.w3.org/2000/svg"
+                    >
+                      <path
+                        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
+                      >{{
+                        typeof item.answer === "number"
+                          ? "单选题:"
+                          : "多选题:"
+                      }}{{ item.title }}</span
+                    >
+                  </div>
+
+									<div class="s_b_m_b_i_m_c_accuracyRate">
+										<span>准确率:{{ item.accuracyRate }}%</span>
+									</div>
+
+                  <div class="s_b_m_b_i_m_c_table">
+                    <el-table :data="item.optionsList" style="width: 800px">
+                      <el-table-column prop="label" label="选项">
+												<template slot-scope="scope">
+													<img  @click.stop="$hevueImgPreview(scope.row.label.src)" class="tableImage" v-if="scope.row.label.imgType && scope.row.label.imgType === 1" :src="scope.row.label.src"></img>
+													<span v-else>{{ scope.row.label }}</span>
+												</template>
+                      </el-table-column>
+                      <el-table-column prop="count" align="center" label="小计" width="60">
+                      </el-table-column>
+                      <el-table-column prop="scale" label="比例" width="300">
+												<template slot-scope="scope">
+													<div class="tableProgress">
+														<el-progress :percentage="scope.row.scale"></el-progress>
+													</div>
+												</template>
+                      </el-table-column>
+                    </el-table>
+                  </div>
+                </div>
+              </div>
+            </div>
+            <div class="s_b_m_b_item s_b_m_b_worksSubmit" v-if="showType === 2">
+              <div class="s_b_b_i_noSubmit">
+                <div class="s_b_b_i_ws_top">
+                  <div class="s_b_b_i_ws_t_left">
+                    <div @click="foldList.noSubmit = !foldList.noSubmit">
+                      <span>未提交</span>
+                      <span> ({{ noWorksStudent.length }}) </span>
+                      <svg
+                        :style="{
+                          transform: foldList.noSubmit
+                            ? 'rotate(-180deg)'
+                            : 'rotate(0deg)'
+                        }"
+                        width="16"
+                        height="16"
+                        viewBox="0 0 16 16"
+                        xmlns="http://www.w3.org/2000/svg"
+                      >
+                        <path
+                          d="M3.54028 6.45964L4.45952 5.54041L7.9999 9.08079L11.5403 5.54041L12.4595 6.45964L7.9999 10.9193L3.54028 6.45964Z"
+                        />
+                      </svg>
+                    </div>
+                  </div>
+                  <div class="s_b_b_i_ws_t_right"></div>
+                </div>
+                <div class="s_b_b_i_ws_bottom" v-show="!foldList.noSubmit">
+                  <div
+                    class="s_b_b_i_ws_b_noSubmitItem"
+                    v-if="noWorksStudent.length > 0"
+                    v-for="item in noWorksStudent"
+                    :key="item.userid"
+                  >
+                    {{ item.student }}
+                  </div>
+                  <span v-if="noWorksStudent.length === 0"
+                    >无未提交学生...</span
+                  >
+                </div>
+              </div>
+              <div class="s_b_b_i_worksPreview">
+                <div class="s_b_b_i_ws_top">
+                  <div class="s_b_b_i_ws_t_left">
+                    <div
+                      @click="foldList.worksPreview = !foldList.worksPreview"
+                    >
+                      <span>作业预览</span>
+                      <span> ({{ worksStudent.length }}) </span>
+                      <svg
+                        :style="{
+                          transform: foldList.worksPreview
+                            ? 'rotate(-180deg)'
+                            : 'rotate(0deg)'
+                        }"
+                        width="16"
+                        height="16"
+                        viewBox="0 0 16 16"
+                        xmlns="http://www.w3.org/2000/svg"
+                      >
+                        <path
+                          d="M3.54028 6.45964L4.45952 5.54041L7.9999 9.08079L11.5403 5.54041L12.4595 6.45964L7.9999 10.9193L3.54028 6.45964Z"
+                        />
+                      </svg>
+                    </div>
+                  </div>
+                  <div class="s_b_b_i_ws_t_right"></div>
+                </div>
+                <div class="s_b_b_i_ws_bottom" v-show="!foldList.worksPreview">
+                  <div
+                    class="s_b_b_i_ws_b_isSubmitItem"
+                    v-if="worksStudent.length > 0"
+                    v-for="item in worksStudent"
+                    :key="item.userid"
+                  >
+                    <div class="s_b_b_i_ws_b_i_s_i_t_top" @click="openTools(item)">
+                      <div
+                        class="s_b_b_i_ws_b_i_s_i_t_t_delIcon"
+                        @click.stop="deleteWorks(item.wid)"
+                      >
+                        <img src="../../assets/deleteworks.png" alt="" />
+                      </div>
+
+											<div class="s_b_b_i_ws_b_i_s_i_t_t_answer">
+												
+												<span v-for="(answer,answerIndex) in worksCheckAnswer(item)" :key="item.userid+'-'+answerIndex+'-'+answer.index">
+													<span v-if="answer.type===1" v-for="item2 in answer.label" :key="answer.index+'-'+item.userid+'-1'">
+														<span :class="`${item2.right?'answerRight':'answerWrong'}`">{{ item2.label }}</span>
+													</span>
+													<span v-if="answer.type===2" class="answer2" :class="`${answer.isRight?'answerRightLine':'answerWrongLine'}`" v-for="item3 in answer.label" :key="answer.index+'-'+item.userid+'-2'">
+														<span :class="`${item3.right?'answerRight':'answerWrong'}`">{{ item3.label }}</span>
+													</span>
+												</span>
+
+												<!-- <span>{{ worksCheckAnswer(item) }}</span> -->
+											</div>
+                    </div>
+                    <div class="s_b_b_i_ws_b_i_s_i_t_bottom">
+                      <el-tooltip
+                        class="item"
+                        effect="dark"
+                        :content="item.sName"
+                        placement="top"
+                      >
+                        <span>{{ item.sName }}</span>
+                      </el-tooltip>
+
+                      <span>{{ item.time }}</span>
+                    </div>
+                  </div>
+                  <span v-if="worksStudent.length === 0">暂无提交学生...</span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import eChartsView from './eChartsView.vue'
+export default {
+	components:{
+		eChartsView1:eChartsView,
+		eChartsView2:eChartsView
+	},
+  props: {
+    worksStudentData: {
+      type: Array,
+      default: () => []
+    },
+    noWorksSData: {
+      type: Array,
+      default: () => []
+    },
+    chapInfoListData: {
+      type: Array,
+      default: () => []
+    },
+    courseType: {
+      type: String,
+      default: ""
+    },
+    taskCount: {
+      type: Number,
+      default: 0
+    }
+  },
+  data() {
+    return {
+      show: false,
+      showType: 0,
+			showStatisticsType:0,
+      data: null,
+      testJson: null,
+      testData: null,
+      toolIndex: null,
+      worksStudent: [],
+      noWorksStudent: [],
+      foldList: {
+        noSubmit: false,
+        worksPreview: false
+      },
+      dialogTypeList: [
+        { label: "作业详细", value: 0, loading: false },
+        { label: "题目统计", value: 1, loading: false },
+        { label: "学生统计", value: 2, loading: false }
+      ],
+			statisticsTypeList:[
+				{label:"准确率",value:0},
+				{label:"选项汇总",value:1}
+			],
+			optionTypeList:['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
+    };
+  },
+  computed: {
+    tableData() {
+      let _result = [];
+      if (this.show && this.toolIndex !== null) {
+        let worksJson = [];
+        if (this.testJson) {
+          worksJson = JSON.parse(JSON.stringify(this.testJson));
+        } else if (this.worksStudent.length > 0) {
+          worksJson = JSON.parse(this.worksStudent[0].works)[0].testJson
+            .testJson;
+        }
+
+        let isWorksData = [];
+        let pushData = [];
+
+        isWorksData = this.worksStudent.map(i => JSON.parse(i.works)[0].anwer);
+
+        pushData = worksJson.map((item, index) => {
+          return {
+            title: item.teststitle,
+            answer: item.answer,
+            accuracyRate: 0,
+            accuracyCount: 0,
+            choseCount: 0,
+            optionsList: item.checkList.map((item2, index2) => {
+              return { label: item2, count: 0, scale: 0 };
+            })
+          };
+        });
+        isWorksData.forEach(i => {
+          i.forEach((item, index) => {
+            pushData[index].choseCount++; //做了这道题的人数+1
+            if (typeof item === "number") {
+              //单选题
+              pushData[index].optionsList[item].count += 1; //选了这选项的次数+1
+              if (pushData[index].answer === item) {
+                pushData[index].accuracyCount += 1; //选对了的人数+1
+              }
+            } else {
+              //多选题
+              item.forEach(i2 => {
+                pushData[index].optionsList[i2].count += 1; //选了这选项的次数+1
+              });
+              if (JSON.stringify(item.sort()) === JSON.stringify(pushData[index].answer.sort())) {
+                pushData[index].accuracyCount += 1; //选对了的人数+1
+              }
+            }
+          });
+        });
+
+        pushData.forEach(i => {
+          i.accuracyRate = parseFloat(((i.accuracyCount / i.choseCount) * 100).toFixed(2));
+          i.optionsList.forEach(i2 => {
+            i2.scale = parseFloat(((i2.count / i.choseCount) * 100).toFixed(2));
+          });
+        });
+
+        _result = pushData;
+      }
+      return _result;
+    },
+		accuracyRateData(){
+			let _result = null;
+			if(this.tableData.length>0){
+				let eChartsData = {
+    		  xAxis: {
+    		    type: 'category',
+    		    data: []
+    		  },
+    		  yAxis: {
+    		    type: 'value'  // y 轴的值类型
+    		  },
+    		  series: [
+    		    {
+    		      name: '准确率',
+    		      type: 'bar',
+    		      data: [], 
+    		      itemStyle: {
+    		        color: '#5c87ef'  // 设置条形图的颜色
+    		      }
+    		    }
+    		  ],
+    		  // 设置条形图的间隔
+    		  barCategoryGap: '50%', 
+    		}
+
+				this.tableData.forEach((item,index)=>{
+					eChartsData.xAxis.data.push(`第${index+1}题`);
+					eChartsData.series[0].data.push(item.accuracyRate);
+				})
+
+				_result = eChartsData;
+				// eChartsData.xAxis.data = this.tableData.
+			}
+
+			return _result;
+		},
+		optionSummaryData(){
+			let _result = null;
+
+			if(this.tableData.length>0){
+				let eChartsData = {
+				  legend: {},
+				  tooltip: {},
+				  dataset: {
+				    source: [
+				      ['选项'],
+				      // ['Matcha Latte', 43.3,0, 93.7,90],
+				      // ['Milk Tea', 83.1, 73.4, 55.1],
+				      // ['Cheese Cocoa', 86.4, 65.2, 82.5],
+				      // ['Walnut Brownie', 72.4, 53.9, 39.1]
+				    ]
+				  },
+				  xAxis: { type: 'category' },
+				  yAxis: {},
+				  // Declare several bar series, each will be mapped
+				  // to a column of dataset.source by default.
+				  series: [
+						// { type: 'bar' },
+					]
+				};
+
+				let maxChoseLength = this.tableData.reduce((max,item)=>{
+					return Math.max(max,item.optionsList.length)
+				},0)
+
+				for(let i=0;i<maxChoseLength;i++){
+					eChartsData.dataset.source[0].push(`选项${i+1}`)
+					eChartsData.series.push({type:'bar'})//,label: { show: true, position: 'top' }
+				}
+
+				this.tableData.forEach((item,index)=>{
+					eChartsData.dataset.source.push([`第${index+1}题`])
+					item.optionsList.forEach((item2,index2)=>{
+						eChartsData.dataset.source[index+1].push(item2.count)
+					})
+				})
+
+				_result = eChartsData;
+			}
+			return _result;
+		},
+		worksCheckAnswer(){
+			return data=>{
+				let _result = [];
+				let works = JSON.parse(data.works);
+				let testJson = works[0].testJson.testJson;
+				let worksAnswer = works[0].anwer;
+
+				let answerList = [];
+
+
+				worksAnswer.forEach((item,index)=>{
+					let _workAnswer = testJson[index].answer;
+					if(typeof item === "number"){//单选题
+						if(item===_workAnswer){
+							answerList.push({type:1,index:index,label:[{right:true,label:this.optionTypeList[item]}]})
+						}else{
+							answerList.push({type:1,index:index,label:[{right:false,label:this.optionTypeList[item]}],})
+						}
+					}else{//多选题
+						let _item = item.sort();
+						let _workAnswer2 = _workAnswer.sort();
+						let _obj = {type:2,isRight:JSON.stringify(_item)===JSON.stringify(_workAnswer2),index:index,label:[]};
+						_item.forEach((item2,index2)=>{
+							if(_workAnswer2.includes(item2)){
+								_obj.label.push({right:true,label:this.optionTypeList[item2]})
+							}else{
+								_obj.label.push({right:false,label:this.optionTypeList[item2]})
+							}
+						})
+						answerList.push(_obj);
+					}
+				})
+
+				_result = answerList;
+				// _result = works[0].anwer;
+
+
+
+				return _result;
+			}
+		}
+  },
+  watch: {
+    worksStudentData: {
+      handler(newValue) {
+        if (
+          this.show &&
+          this.toolIndex !== null &&
+          JSON.stringify(this.worksStudent) !==
+            JSON.stringify(newValue[this.toolIndex])
+        ) {
+          this.worksStudent = JSON.parse(
+            JSON.stringify(newValue[this.toolIndex])
+          );
+          this.dialogTypeList[2].loading = false;
+        }
+      },
+      deep: true
+    },
+    noWorksSData: {
+      handler(newValue) {
+        if (
+          this.show &&
+          this.toolIndex !== null &&
+          JSON.stringify(this.noWorksStudent) !==
+            JSON.stringify(newValue[this.toolIndex])
+        ) {
+          this.noWorksStudent = JSON.parse(
+            JSON.stringify(newValue[this.toolIndex])
+          );
+          this.dialogTypeList[2].loading = false;
+        }
+      },
+      deep: true
+    }
+  },
+
+  methods: {
+    open(data) {
+      if (this.show) return;
+      this.show = true;
+      this.data = data;
+      this.toolIndex = data.toolIndex;
+      this.setData();
+    },
+    setData() {
+      if (this.show && this.toolIndex !== null) {
+        this.worksStudent = JSON.parse(
+          JSON.stringify(this.worksStudentData[this.toolIndex])
+        );
+        this.noWorksStudent = JSON.parse(
+          JSON.stringify(this.noWorksSData[this.toolIndex])
+        );
+        let _tempData = this.chapInfoListData[this.courseType].chapterInfo[0]
+          .taskJson[this.taskCount].toolChoose[this.toolIndex];
+        this.testData = _tempData ? _tempData : null;
+        this.testJson = this.testData.testJson
+          ? this.testData.testJson.testJson
+          : null;
+      }
+    },
+    close() {
+      this.show = false;
+      this.init();
+			this.$emit("changeSplitScreenBehavior",{code:99})
+    },
+    init() {
+      this.data = null;
+      this.showType = 0;
+			this.showStatisticsType = 0;
+      this.testJson = null;
+      this.worksStudent = [];
+      this.noWorksStudent = [];
+      this.toolIndex = null;
+      this.testData = null;
+      this.foldList = {
+        noSubmit: false,
+        worksPreview: false
+      };
+    },
+    changeShowType(type) {
+      this.showType = type;
+			this.$emit("changeSplitScreenBehavior",{code: 1,
+        form: {
+          toolIndex: this.toolIndex,
+          courseType: this.courseType,
+          taskCount: this.taskCount,
+          type: this.showType,
+					showStatisticsType:this.showStatisticsType
+        }})
+    },
+    deleteWorks(wid) {
+      this.$emit("deleteWorks", wid);
+      this.dialogTypeList[2].loading = true;
+    },
+		openTools(data){
+			this.$emit("openTools",45,this.toolIndex,this.taskCount,data.works,data.sName)
+		},
+		changeShowStatisticsType(type){
+			this.showStatisticsType = type;
+			this.$emit("changeSplitScreenBehavior",{code: 1,
+        form: {
+          toolIndex: this.toolIndex,
+          courseType: this.courseType,
+          taskCount: this.taskCount,
+          type: this.showType,
+					showStatisticsType:this.showStatisticsType
+        }})
+		},
+		splitScreenFn(data){
+			console.log("splitScreenFn",data)
+			if(data.type!==undefined){
+				this.showType = data.type;
+			}
+			if(data.showStatisticsType!==undefined){
+				this.showStatisticsType = data.showStatisticsType;
+			}
+		}
+  }
+};
+</script>
+
+<style scoped>
+.choseWorksDetailDialog {
+  width: 100vw;
+  height: 100vh;
+}
+
+.choseWorksDetailDialog >>> .el-dialog__header,
+.choseWorksDetailDialog >>> .el-dialog__footer {
+  display: none; /* 隐藏头部和底部 */
+}
+
+.choseWorksDetailDialog >>> .el-dialog__body {
+  padding: 0;
+  margin: 0;
+  height: 100vh;
+  width: 100vw;
+  overflow: auto;
+}
+
+.s_box {
+  width: 100%;
+  height: 100%;
+  box-sizing: border-box;
+  padding: 25px;
+  background-color: #f3f7fd;
+}
+
+.s_b_main {
+  width: 100%;
+  height: 100%;
+  background-color: #fff;
+  border-radius: 10px;
+}
+
+.s_b_m_top {
+  width: 100%;
+  height: 70px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.s_b_m_t_left {
+  width: auto;
+  height: 100%;
+  box-sizing: border-box;
+  padding-left: 30px;
+  display: flex;
+  align-items: center;
+  overflow: auto;
+  white-space: nowrap;
+}
+
+.s_b_m_t_left > span {
+  font-size: 20px;
+  /* font-weight: bold; */
+  cursor: pointer;
+  margin-right: 40px;
+  position: relative;
+  transition: 0.3s;
+}
+
+.s_b_m_t_left > span.s_b_m_t_l_active {
+  color: #3681fc;
+}
+
+.s_b_m_t_l_active::after {
+  content: "";
+  display: inline-block;
+  width: 100%;
+  height: 4px;
+  background-color: #3681fc;
+  position: absolute;
+  bottom: -15px;
+  left: 0;
+  border-radius: 2px;
+}
+
+.s_b_m_t_right {
+  width: 100px;
+  margin-right: 30px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.s_b_m_t_right > span {
+  font-size: 18px;
+  cursor: pointer;
+}
+
+.s_b_m_bottom {
+  width: 100%;
+  height: calc(100% - 70px);
+}
+
+.s_b_m_b_item {
+  width: 100%;
+  height: 100%;
+  overflow: auto;
+}
+
+.s_b_m_b_i_main {
+  width: 70%;
+  margin: 0 auto;
+  min-width: 1000px;
+  padding: 10px 0 30px 0;
+}
+
+.s_b_m_b_i_main > span {
+  font-size: 26px;
+  font-weight: bold;
+  display: block;
+  margin: 30px 0 40px 20px;
+}
+
+.s_b_m_b_i_m_title {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.s_b_m_b_i_m_title > div {
+  display: flex;
+  align-items: center;
+}
+
+.s_b_m_b_i_m_title > div > svg {
+  width: 60px;
+  height: 60px;
+  margin-right: 5px;
+}
+
+.s_b_m_b_i_m_title > div > span {
+  font-size: 20px;
+  font-weight: bold;
+}
+
+.s_b_m_b_i_m_title > span {
+  width: calc(100% - 50px);
+  padding: 20px;
+  display: block;
+  margin: 0 10px;
+  background-color: #f3f7fd;
+  border-radius: 5px;
+  font-size: 16px;
+}
+
+.s_b_m_b_i_m_choseList {
+  box-sizing: border-box;
+  padding: 0 0 0 20px;
+  margin-bottom: 30px;
+}
+
+.s_b_m_b_i_m_c_title {
+  display: flex;
+  align-items: center;
+}
+
+.s_b_m_b_i_m_c_title > span:nth-of-type(1) {
+  font-size: 30px;
+  font-weight: bold;
+  color: #3681fc;
+}
+
+.s_b_m_b_i_m_c_title > svg {
+  width: 30px;
+  height: 30px;
+  margin: 0 20px 0 5px;
+}
+
+.s_b_m_b_i_m_c_title > span:nth-of-type(2) {
+  font-size: 20px;
+  font-weight: bold;
+}
+
+.s_b_m_b_i_m_c_options {
+  width: 100%;
+  height: auto;
+  padding: 15px 15px 15px 15px;
+  display: flex;
+  flex-wrap: wrap;
+  background-color: #f3f7fd;
+  border-radius: 30px;
+  margin: 10px 0 10px 0px;
+  box-sizing: border-box;
+}
+
+.s_b_m_b_i_m_c_o_right {
+  border: solid 1px #3681fc;
+}
+
+.s_b_m_b_i_m_c_o_btn {
+  width: 20px;
+  height: 100%;
+  min-height: 20px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  margin-right: 10px;
+}
+
+.s_b_m_b_i_m_c_o_btn > span {
+  width: 20px;
+  height: 20px;
+  display: block;
+  box-sizing: border-box;
+  border: solid 1px #3681fc;
+  overflow: hidden;
+}
+
+.s_b_m_b_i_m_c_o_btn > span > span {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background-color: #3681fc;
+  position: relative;
+}
+
+.s_b_m_b_i_m_c_o_btn1 {
+  border-radius: 50%;
+}
+
+.s_b_m_b_i_m_c_o_btn1 > span::after {
+  content: "";
+  width: 8px;
+  height: 8px;
+  position: absolute;
+  background-color: #fff;
+  border-radius: 50%;
+}
+
+.s_b_m_b_i_m_c_o_btn2 {
+  border-radius: 2px;
+}
+
+.s_b_m_b_i_m_c_o_btn2 > span > svg {
+  width: 12px;
+  height: 12px;
+}
+
+.s_b_m_b_i_m_c_options > span > img {
+  max-height: 150px;
+  border-radius: 2px;
+  cursor: pointer;
+}
+
+.s_b_m_b_i_m_c_options > span {
+  font-size: 16px;
+  display: block;
+  width: calc(100% - 30px);
+}
+
+.s_b_m_b_worksSubmit > div {
+  width: 100%;
+  height: auto;
+  box-sizing: border-box;
+  padding: 20px 20px 20px 30px;
+  margin-bottom: 0px;
+}
+
+.s_b_b_i_ws_top {
+  width: 100%;
+  height: 50px;
+  display: flex;
+  align-items: center;
+}
+
+.s_b_b_i_ws_t_left {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  align-items: center;
+}
+
+.s_b_b_i_ws_t_left > div {
+  width: auto;
+  height: auto;
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+}
+
+.s_b_b_i_ws_t_left > div > span {
+  font-size: 20px;
+  font-weight: bold;
+  margin-right: 10px;
+  color: #000;
+}
+
+.s_b_b_i_ws_t_left > div > svg {
+  width: 24px;
+  height: 24px;
+  transition: 0.3s;
+  fill: #000;
+}
+
+.s_b_b_i_ws_bottom {
+  width: 100%;
+  height: auto;
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.s_b_b_i_ws_bottom > span {
+  margin-top: 10px;
+  font-size: 16px;
+}
+
+.s_b_b_i_ws_b_noSubmitItem {
+  padding: 10px 15px 10px 15px;
+  border-radius: 4px;
+  background-color: #f3f7fd;
+  margin-left: 10px;
+  margin-bottom: 10px;
+  color: #00000099;
+  cursor: default;
+}
+
+.s_b_b_i_ws_b_isSubmitItem {
+  width: 250px;
+  height: 180px;
+  border-radius: 8px;
+  background-color: #f3f7fd;
+  margin-left: 10px;
+  margin-bottom: 10px;
+  border: solid 1px #e7e7e7;
+  overflow: hidden;
+}
+
+.s_b_b_i_ws_b_i_s_i_t_top {
+  width: 100%;
+  height: calc(100% - 50px);
+  box-sizing: border-box;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  padding: 10px;
+  flex-wrap: wrap;
+  background-image: linear-gradient(
+    45deg,
+    #e3eeff 0%,
+    #dbe9fd 99%,
+    #e3eeff 100%
+  );
+  position: relative;
+	cursor: pointer;
+	overflow: auto;
+}
+
+.s_b_b_i_ws_b_i_s_i_t_t_delIcon {
+  width: 25px;
+  height: 25px;
+  position: absolute;
+  right: 10px;
+  top: 10px;
+  cursor: pointer;
+}
+
+.s_b_b_i_ws_b_i_s_i_t_t_delIcon > img {
+  width: 100%;
+  height: 100%;
+}
+
+.s_b_b_i_ws_b_i_s_i_t_bottom {
+  width: 100%;
+  height: 50px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  box-sizing: border-box;
+  padding: 0 10px;
+  font-size: 16px;
+  font-weight: bold;
+  color: #000;
+  background-color: #fff;
+}
+
+.s_b_b_i_ws_b_i_s_i_t_bottom > span:nth-of-type(1) {
+  /* 溢出显示省略 */
+  width: 80px;
+  display: block;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.s_b_b_i_ws_b_i_s_i_t_bottom > span:nth-of-type(2) {
+  font-size: 14px;
+  color: #00000099;
+}
+
+.s_b_m_b_i_table {
+  width: 100%;
+  height: auto;
+  box-sizing: border-box;
+  padding-left: 30px;
+  margin-bottom: 30px;
+}
+
+.s_b_m_b_i_m_c_accuracyRate{
+	margin-top: 20px;
+	margin-bottom: 10px;
+	font-size: 18px;
+	color: #00000099;
+}
+
+.tableImage{
+	width: auto;
+	max-height: 150px;
+	border-radius: 2px;
+	cursor: pointer;
+}
+
+.tableProgress>>>.el-progress-bar>.el-progress-bar__outer{
+	height: 10px !important;
+}
+
+.tableProgress>>>.el-progress__text{
+	font-size: 16px;
+	color: #3681FC;
+}
+
+.s_b_m_b_i_m_c_table>>>.el-table{
+	border: solid 1px #EBEEF5;
+	border-bottom: none
+}
+
+.s_b_m_b_i_m_c_table>>>.el-table>.el-table__header-wrapper th{
+	background-color: #F9FAFB;
+	color: #000;
+}
+
+.s_b_b_i_ws_b_i_s_i_t_t_answer>span{
+	font-size: 18px;
+	font-weight: bold;
+	margin: 2px 4px;
+	display: block;
+	float: left;
+}
+
+.s_b_b_i_ws_b_i_s_i_t_t_answer>span>span{
+	position: relative;
+}
+
+.answer2>span{
+	margin:0 1px;
+}
+
+.answerWrongLine::after{
+	content: '';
+	width: 100%;
+	height: 2px;
+	background-color: #EE3E3E;
+	position: absolute;
+	bottom: -2px;
+	left: 0;
+}
+
+.answerRightLine::after{
+	content: '';
+	width: 100%;
+	height: 2px;
+	background-color: #5E9AFC;
+	position: absolute;
+	bottom: -2px;
+	left: 0;
+}
+
+.answerRight{
+	color: #5E9AFC !important;
+}
+
+.answerWrong{
+	color: #EE3E3E !important;
+}
+
+
+
+
+.s_b_m_b_i_eChartsArea{
+	width: 100%;
+	height: auto;
+	box-sizing: border-box;
+	padding-left: 30px;
+	margin-bottom: 100px;
+}
+
+.s_b_m_b_i_e_title{
+	width: 100%;
+	height: 30px;
+	display: flex;
+	align-items: center;
+	justify-content: flex-end;
+}
+
+.s_b_m_b_i_e_title>span{
+	font-size: 18px;
+	margin-right: 20px;
+	color: #000;
+	cursor: pointer;
+}
+
+.s_b_m_b_i_e_t_active{
+	color: #3681FC !important;
+	text-decoration: underline !important;
+}
+
+.s_b_m_b_i_e_charts{
+	width: auto;
+	height: 600px;
+}
+
+.s_b_m_b_i_e_charts_bottom{
+	width: 100%;
+	display: flex;
+	align-items: center;
+	flex-wrap: wrap;
+	box-sizing: border-box;
+	padding-left: 30px;
+}
+
+.s_b_m_b_i_e_charts_bottom>span{
+	padding: 10px 15px;
+	background-color: #F3F7FD;
+	border-radius: 4px;
+	margin-right: 10px;
+	margin-bottom: 10px;
+	font-size: 18px;
+	border-radius: 4px;
+}
+
+
+
+/* F9FAFB */
+
+/* .s_b_b_i_noSubmit {
+  width: 100%;
+  height: auto;
+  box-sizing: border-box;
+  padding: 20px;
+  background-color: red;
+}
+
+.s_b_b_i_worksPreview {
+  width: 100%;
+  height: auto;
+  box-sizing: border-box;
+  padding: 20px;
+  background-color: blue;
+} */
+</style>

+ 50 - 0
src/components/components/eChartsView.vue

@@ -0,0 +1,50 @@
+<template>
+  <div class="chart" id="charts_canvas" ref="chartRef"></div>
+</template>
+
+<script>
+import * as echarts from "echarts";
+// import "echarts-wordcloud";
+export default {
+  props: {
+    data: {
+      type: Object,
+      default: () => {}
+    }
+  },
+  data() {
+    return {
+      chartObj: null,
+      chartData: null
+    };
+  },
+  watch: {
+    data() {
+      this.getChartData();
+    }
+  },
+  methods: {
+    getChartData() {
+      if (this.chartObj === null) {
+        this.chartObj = echarts.init(this.$refs.chartRef);
+      }
+      this.chartObj.setOption(this.data);
+      window.addEventListener("resize", () => {
+        this.chartObj.resize();
+      });
+    }
+  },
+  mounted() {
+    this.getChartData();
+  }
+};
+</script>
+
+<style scoped>
+.chart {
+  max-width: 100%;
+  width: 100%;
+  height: 100%;
+  background-color: #fff;
+}
+</style>

+ 808 - 0
src/components/components/statisticalAnalysis.vue

@@ -0,0 +1,808 @@
+<template>
+  <div class="statisticalAnalysis">
+    <el-dialog
+      :visible.sync="show"
+      width="100%"
+      height="100%"
+      fullscreen
+      :modal="true"
+      :close-on-click-modal="false"
+      :show-close="false"
+    >
+      <div class="s_box">
+        <div class="s_b_top">
+          <div class="s_b_t_left">
+            <img src="../../assets/icon/thirdToolList/ask.png" slt="图片"/>
+            <div class="s_b_t_l_detail">
+              <div>{{ askData.title }}</div>
+              <span>{{ askData.describe }}</span>
+            </div>
+          </div>
+          <div class="s_b_t_right" @click="close">
+            <svg
+              t="1730691027130"
+              class="icon"
+              viewBox="0 0 1024 1024"
+              version="1.1"
+              xmlns="http://www.w3.org/2000/svg"
+              p-id="4288"
+              width="200"
+              height="200"
+            >
+              <path
+                d="M632.117978 513.833356l361.805812 361.735298a85.462608 85.462608 0 1 1-121.001515 120.789974L511.116463 634.552816 146.913186 998.756094a86.026718 86.026718 0 0 1-121.706652-121.706652L389.480325 512.775651 27.674513 150.969839A85.392095 85.392095 0 0 1 148.393973 30.250379L510.199785 392.056191l366.671258-366.671258a86.026718 86.026718 0 0 1 121.706652 121.706652z"
+                p-id="4289"
+              ></path>
+            </svg>
+            <span>退出</span>
+          </div>
+        </div>
+        <div class="s_b_bottom">
+          <div class="s_b_b_left">
+            <span
+              @click="changeShowType(0)"
+              :class="{ s_b_b_l_active: showType === 0 }"
+              >题目情况</span
+            >
+            <span
+              @click="changeShowType(1)"
+              :class="{ s_b_b_l_active: showType === 1 }"
+              >学生汇总</span
+            >
+            <span
+              @click="changeShowType(2)"
+              :class="{ s_b_b_l_active: showType === 2 }"
+              >班级汇总</span
+            >
+          </div>
+          <div class="s_b_b_right">
+						<div class=s_b_b_r_btnArea>
+							<div class="s_b_b_r_primaryBtn" @click="refresh">刷新</div>
+						</div>
+            <div class="s_b_b_r_item" v-if="showType === 0">
+              <div class="itemBox">
+                <div class="ib_title">数据统计图</div>
+                <div class="ib_echarts" style="width:60%;height: 600px;min-width: 600px;">
+                  <eChartsView
+										id="problemSituationData"
+                    v-if="problemSituationData.eChartsOption && show "
+                    :data="problemSituationData.eChartsOption"
+                  />
+                </div>
+              </div>
+
+              <div class="itemBox">
+                <div class="ib_title">数据详情</div>
+                <el-table
+                  v-if="problemSituationData.tableData.length > 0"
+                  :data="problemSituationData.tableData"
+                  border
+                  style="width: 100%"
+                >
+                  <el-table-column
+                    type="index"
+                    width="50"
+                    align="center"
+                  ></el-table-column>
+                  <el-table-column
+                    prop="label"
+                    width="100"
+                    align="center"
+                  ></el-table-column>
+                  <el-table-column
+                    v-for="(item, index) in problemSituationData.tableData[0]
+                      .options"
+                    width="70"
+                    :key="index"
+                    :label="`选项${index + 1}`"
+                    align="center"
+                  >
+                    <template slot-scope="scope">
+                      <div>
+                        {{ scope.row.options[index] }}
+                      </div>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+            <div class="s_b_b_r_item" v-if="showType === 1">
+              <div class="itemBox">
+                <div class="ib_title">数据统计图</div>
+                <div class="ib_echarts" style="width:60%;height: 600px;min-width: 600px;">
+                  <eChartsView2
+										id="studentSummaryData"
+                    v-if="studentSummary.eChartsOption && show"
+                    :data="studentSummary.eChartsOption"
+                  />
+                </div>
+              </div>
+
+              <div class="itemBox">
+                <div class="ib_title">数据详情</div>
+                <el-table
+                  v-if="studentSummary.tableData.length > 0"
+                  :data="studentSummary.tableData"
+                  border
+                  style="width: 100%"
+                >
+                  <el-table-column
+                    type="index"
+                    width="50"
+                    align="center"
+                  ></el-table-column>
+                  <el-table-column
+                    prop="label"
+                    width="100"
+                    align="center"
+                  ></el-table-column>
+                  <el-table-column
+                    v-for="(item, index) in studentSummary.tableData[0].options"
+                    width="70"
+                    :key="index"
+                    :label="`选项${index + 1}`"
+                    align="center"
+                  >
+                    <template slot-scope="scope">
+                      <div>
+                        {{ scope.row.options[index] }}
+                      </div>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+
+            <div class="s_b_b_r_item" v-if="showType === 2">
+              <div class="itemBox">
+                <div class="ib_title">数据统计图</div>
+                <div class="ib_echarts" style="width:800px;height: 600px">
+                  <eChartsView3
+										id="classSummaryData"
+                    v-if="classSummary.eChartsOption && show"
+                    :data="classSummary.eChartsOption"
+                  />
+                </div>
+              </div>
+
+              <div class="itemBox">
+                <div class="ib_title">数据详情</div>
+                <el-table
+                  v-if="classSummary.tableData.length > 0"
+                  :data="classSummary.tableData"
+                  border
+                  style="width: 100%"
+                >
+                  <el-table-column
+                    type="index"
+                    :index="indexMethod"
+                    width="50"
+                    align="center"
+                  ></el-table-column>
+                  <el-table-column
+                    prop="label"
+                    width="100"
+                    align="center"
+                  ></el-table-column>
+                  <el-table-column
+                    v-for="(item, index) in classSummary.tableData[0].options"
+                    width="70"
+                    :key="index"
+                    :label="`选项${index + 1}`"
+                    align="center"
+                  >
+                    <template slot-scope="scope">
+                      <div>
+                        {{ scope.row.options[index] }}
+                      </div>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import eChartsView from "./eChartsView.vue";
+import eChartsView2 from "./eChartsView.vue";
+import eChartsView3 from "./eChartsView.vue";
+export default {
+  components: {
+    eChartsView,
+    eChartsView2,
+    eChartsView3
+  },
+  data() {
+    return {
+      show: false,
+      showType: 0,
+      data: null,
+      tType: null,
+      worksData: null,
+      worksStudent: null,
+			toolIndex:null,
+      askData: {
+        title: "",
+        describe: ""
+      }
+    };
+  },
+  methods: {
+    open(data) {
+			console.log(data)
+      this.show = true;
+      this.data = data;
+      this.worksStudent = data.worksStudent;
+			this.toolIndex = data.toolIndex;
+      if (data.worksStudent.length > 0) {
+        let works = data.worksStudent[0].works
+          ? JSON.parse(data.worksStudent[0].works)
+          : null;
+        if (works) {
+          works = works[0].askJson;
+          this.worksData = works.askJson;
+          this.askData.title = works.askTitle;
+        } else {
+          this.worksData = [];
+        }
+      } else {
+        this.worksData = [];
+      }
+    },
+    close() {
+      this.show = false;
+      this.init();
+    },
+    init() {
+      this.data = null;
+      this.showType = 0;
+      this.tType = null;
+      this.worksData = null;
+			this.toolIndex = null;
+      this.askData = {
+        title: "",
+        describe: ""
+      };
+    },
+    changeShowType(type) {
+      this.showType = type;
+			this.$forceUpdate()
+    },
+    indexMethod(index) {
+      if (index === 0) {
+        return "";
+      } else {
+        return index;
+      }
+    },
+		refresh(){
+			this.$emit("refresh",this.toolIndex)
+		},
+		refreshData(data){
+			console.log(data)
+			this.data = data;
+      this.worksStudent = data.worksStudent;
+			this.toolIndex = data.toolIndex;
+      if (data.worksStudent.length > 0) {
+        let works = data.worksStudent[0].works
+          ? JSON.parse(data.worksStudent[0].works)
+          : null;
+        if (works) {
+          works = works[0].askJson;
+          this.worksData = works.askJson;
+          this.askData.title = works.askTitle;
+        } else {
+          this.worksData = [];
+        }
+      } else {
+        this.worksData = [];
+      }
+		},
+  },
+  computed: {
+    // 题目情况
+    problemSituationData() {
+      let result = {
+        eChartsOption: {
+          legend: {
+            selectedMode: false
+          },
+          grid: {
+            left: 100,
+            right: 100,
+            top: 50,
+            bottom: 50
+          },
+          yAxis: {
+            type: "category",
+            data: []
+          },
+          xAxis: {
+            type: "value",
+            axisLabel: {
+              formatter: function(value) {
+                return value * 100 + "%"; // 将值转换为百分比
+              }
+            }
+          },
+          series: {}
+        },
+        tableData: []
+      };
+
+      if (this.worksData === null || this.worksData.length === 0) {
+        return result;
+      }
+
+      // 获取题目选项最多的长度
+      let optionsLength = 0;
+
+      this.worksData.forEach((item, index) => {
+        if (item.checkList.length > optionsLength) {
+          optionsLength = item.checkList.length;
+        }
+        let itemObj = {
+          label: `题目${index + 1}`,
+          question: item.askTitle,
+          options: []
+        };
+
+        result.tableData.push(itemObj);
+      });
+
+      //填充选项次数
+      result.tableData.forEach(item => {
+        item.options = new Array(optionsLength).fill(0);
+      });
+
+      this.worksStudent.forEach((item, index) => {
+        let works = item.works ? JSON.parse(item.works) : null;
+        if (works) {
+          let answer = works[0].anwer;
+          answer.forEach((item2, index2) => {
+            if (Array.isArray(item2)) {
+              item2.forEach(item3 => result.tableData[index2].options[item3]++);
+            } else if (typeof item2 === "number") {
+              result.tableData[index2].options[item2]++;
+            }
+          });
+        }
+      });
+
+      result.eChartsOption.yAxis.data = result.tableData
+        .map(item => item.label)
+        .reverse();
+
+      let optionsDataList = result.tableData.map(i => i.options).reverse();
+
+      let totalData = [];
+      let endwaysData = [];
+
+      optionsDataList.forEach((item, index) => {
+        totalData.push(item.reduce((a, b) => a + b, 0));
+
+        for (let i = 0; i < item.length; i++) {
+          if (!endwaysData[i]) {
+            endwaysData[i] = [];
+          }
+          endwaysData[i].push(item[i]);
+        }
+      });
+
+      let series = result.tableData[0].options.map((item, index) => {
+        return {
+          name: `选项${index + 1}`,
+          type: "bar",
+          stack: "total",
+          barWidth: "60%",
+          label: {
+            show: true,
+            formatter: params => {
+              let data = Math.round(params.value * 1000) / 10;
+              if (data === 0) {
+                return "";
+              } else {
+                return data + "%";
+              }
+            }
+          },
+          data: endwaysData[index].map((d, did) => {
+            return totalData[did] <= 0 ? 0 : d / totalData[did];
+          })
+        };
+      });
+
+      result.eChartsOption.series = series;
+
+      return result;
+    },
+    //学生汇总
+    studentSummary() {
+      let result = {
+        eChartsOption: {
+          legend: {
+            selectedMode: false
+          },
+          grid: {
+            left: 100,
+            right: 100,
+            top: 50,
+            bottom: 50
+          },
+          yAxis: {
+            type: "category",
+            data: []
+          },
+          xAxis: {
+            type: "value",
+            axisLabel: {
+              formatter: function(value) {
+                return value * 100 + "%"; // 将值转换为百分比
+              }
+            }
+          },
+          series: {}
+        },
+        tableData: []
+      };
+
+      if (this.worksData === null || this.worksData.length === 0) {
+        return result;
+      }
+
+      // 获取题目选项最多的长度
+      let optionsLength = 0;
+
+      this.worksData.forEach((item, index) => {
+        if (item.checkList.length > optionsLength) {
+          optionsLength = item.checkList.length;
+        }
+      });
+
+      this.worksStudent.forEach((item, index) => {
+        let works = item.works ? JSON.parse(item.works) : null;
+        let obj = {
+          label: `${item.sName}`,
+          index: index,
+          options: new Array(optionsLength).fill(0)
+        };
+        if (works) {
+          let answer = works[0].anwer;
+          answer.forEach((item2, index2) => {
+            if (Array.isArray(item2)) {
+              item2.forEach(item3 => obj.options[item3]++);
+              // item2.forEach(item3 => result.tableData[index2].options[item3]++);
+            } else if (typeof item2 === "number") {
+              obj.options[item2]++;
+              // result.tableData[index2].options[item2]++;
+            }
+          });
+          result.tableData.push(obj);
+        }
+      });
+
+      result.eChartsOption.yAxis.data = result.tableData
+        .map(item => item.label)
+        .reverse();
+
+      let optionsDataList = result.tableData.map(i => i.options).reverse();
+
+      let totalData = [];
+      let endwaysData = [];
+
+      optionsDataList.forEach((item, index) => {
+        totalData.push(item.reduce((a, b) => a + b, 0));
+
+        for (let i = 0; i < item.length; i++) {
+          if (!endwaysData[i]) {
+            endwaysData[i] = [];
+          }
+          endwaysData[i].push(item[i]);
+        }
+      });
+
+      let series = result.tableData[0].options.map((item, index) => {
+        return {
+          name: `选项${index + 1}`,
+          type: "bar",
+          stack: "total",
+          barWidth: "60%",
+          label: {
+            show: true,
+            formatter: params => {
+              let data = Math.round(params.value * 1000) / 10;
+              if (data === 0) {
+                return "";
+              } else {
+                return data + "%";
+              }
+            }
+          },
+          data: endwaysData[index].map((d, did) => {
+            return totalData[did] <= 0 ? 0 : d / totalData[did];
+          })
+        };
+      });
+
+      result.eChartsOption.series = series;
+
+      return result;
+    },
+    //班级汇总
+    classSummary() {
+      let result = {
+        eChartsOption: {
+          tooltip: {
+            trigger: "item"
+          },
+          legend: {
+            top: "5%",
+            left: "center"
+          },
+          series: [
+            {
+              type: "pie",
+              radius: ["40%", "70%"],
+              name: "班级汇总",
+              avoidLabelOverlap: false,
+              padAngle: 0,
+              itemStyle: {
+                borderRadius: 10
+              },
+              label: {
+                formatter: "{b}:{c}人",
+                fontSize: 30
+              },
+              labelLine: {
+                show: true
+              },
+              data: []
+            }
+          ]
+        },
+        tableData: []
+      };
+
+      // 获取题目选项最多的长度
+      let optionsLength = 0;
+
+      this.worksData.forEach((item, index) => {
+        if (item.checkList.length > optionsLength) {
+          optionsLength = item.checkList.length;
+        }
+        let itemObj = {
+          label: `题目${index + 1}`,
+          question: item.askTitle,
+          options: []
+        };
+
+        result.tableData.push(itemObj);
+      });
+
+      //填充选项次数
+      result.tableData.forEach(item => {
+        item.options = new Array(optionsLength).fill(0);
+      });
+
+      this.worksStudent.forEach((item, index) => {
+        let works = item.works ? JSON.parse(item.works) : null;
+        if (works) {
+          let answer = works[0].anwer;
+          answer.forEach((item2, index2) => {
+            if (Array.isArray(item2)) {
+              item2.forEach(item3 => result.tableData[index2].options[item3]++);
+            } else if (typeof item2 === "number") {
+              result.tableData[index2].options[item2]++;
+            }
+          });
+        }
+      });
+
+      let totalData = {
+        label: "总计",
+        question: "总计",
+        options: new Array(optionsLength).fill(0)
+      };
+
+      result.tableData.forEach(i => {
+        i.options.forEach((i2, index2) => {
+          totalData.options[index2] += i2;
+        });
+      });
+
+      result.tableData.unshift(totalData);
+
+
+			totalData.options.forEach((item,index)=>{
+				let obj = {
+					value:item,
+					name:`选项${index+1}`
+				}
+				result.eChartsOption.series[0].data.push(obj)
+			})
+			
+			
+
+      return result;
+    }
+  }
+};
+</script>
+
+<style scoped>
+.statisticalAnalysis {
+  width: 100vw;
+  height: 100vh;
+}
+
+.statisticalAnalysis >>> .el-dialog__header,
+.statisticalAnalysis >>> .el-dialog__footer {
+  display: none; /* 隐藏头部和底部 */
+}
+
+.statisticalAnalysis >>> .el-dialog__body {
+  padding: 0;
+  margin: 0;
+  height: 100vh;
+  width: 100vw;
+  overflow: auto;
+}
+
+.s_box {
+  width: 100%;
+  height: 100%;
+}
+
+.s_b_top {
+  width: 100%;
+  height: 100px;
+  display: flex;
+  justify-content: space-between;
+  align-self: center;
+  box-sizing: border-box;
+  border-bottom: 1px solid #dee0e3;
+}
+
+.s_b_t_left {
+  flex: 1;
+  height: 100%;
+  display: flex;
+  align-items: center;
+}
+
+.s_b_t_left > img {
+  width: 80px;
+  height: 80px;
+  margin-left: 20px;
+}
+
+.s_b_t_l_detail {
+  width: 100%;
+  height: 70px;
+  box-sizing: border-box;
+  padding: 10px 20px;
+}
+
+.s_b_t_l_detail > div {
+  font-size: 18px;
+  font-weight: bold;
+}
+
+.s_b_t_l_detail > span {
+  font-size: 16px;
+  color: #beb4b4;
+  display: block;
+  margin-top: 5px;
+}
+
+.s_b_t_right {
+  width: 100px;
+  height: 50px;
+  margin: auto;
+  margin-right: 40px;
+  margin-left: 20px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+}
+
+.s_b_t_right > svg {
+  width: 18px;
+  height: 18px;
+  margin-right: 10px;
+  fill: #000;
+  cursor: pointer;
+}
+
+.s_b_t_right > span {
+  font-size: 20px;
+  font-weight: bold;
+  color: #000;
+  cursor: pointer;
+}
+
+.s_b_bottom {
+  width: 100%;
+  height: calc(100% - 100px);
+  display: flex;
+}
+
+.s_b_b_left {
+  width: 300px;
+  height: 100%;
+  box-sizing: border-box;
+  border-right: 1px solid #beb4b4;
+  padding-top: 20px;
+}
+
+.s_b_b_left > span {
+  width: 100%;
+  height: 50px;
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+  font-size: 22px;
+  margin-top: 20px;
+  box-sizing: border-box;
+  padding-left: 50px;
+}
+
+.s_b_b_l_active {
+  font-weight: bold;
+}
+
+.s_b_b_right {
+  width: calc(100% - 300px);
+  height: 100%;
+	position: relative;
+}
+
+.s_b_b_r_btnArea{
+	width: auto;
+	height: auto;
+	position: absolute;
+	right: 30px;
+	top: 30px;
+}
+
+.s_b_b_r_primaryBtn{
+	width: auto;
+	height: auto;
+	background-color: #007AFF;
+	
+	color: #fff;
+	font-size: 16px;
+	padding: 10px 30px;
+	border-radius: 25px;
+	cursor: pointer;
+	box-shadow: 0px 2px 5px 0px #1D398314;
+
+box-shadow: 0.5px 0.5px 10px 2px #1D39830D;
+
+}
+
+.s_b_b_r_item {
+  width: 100%;
+  height: 100%;
+  box-sizing: border-box;
+  padding: 20px;
+}
+
+.itemBox {
+  width: 100%;
+  height: auto;
+  margin-bottom: 40px;
+}
+
+.ib_title {
+  font-size: 24px;
+  /* font-weight: bold; */
+  margin-bottom: 20px;
+}
+</style>

+ 103 - 11
src/components/easy2/commpont/markDialog.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="markDialog" v-loading="vLoading">
     <div
-      style="overflow: auto;overflow-x: hidden;width: 315px;box-sizing: content-box;border-right: 1px rgba(231, 231, 231, 1) solid;"
+      style="width: 315px;box-sizing: content-box;border-right: 1px rgba(231, 231, 231, 1) solid;"
     >
       <div class="left">
         <div v-loading="ScLoading">
@@ -38,7 +38,19 @@
                       {{ e.detail }}
                     </div>
                   </el-tooltip>
-                  <el-rate :disabled="tType == 2" disabled-void-color @change="submit" v-model="e.cog"></el-rate>
+
+                  <div
+                    class="starB"
+                    @contextmenu.prevent="handleRightClick(index, $event)"
+                  >
+                    <div class="hangBlock">右键清空分数</div>
+                    <el-rate
+                      :disabled="tType == 2"
+                      disabled-void-color
+                      @change="submit"
+                      v-model="e.cog"
+                    ></el-rate>
+                  </div>
                 </div>
               </div>
               <div
@@ -63,7 +75,19 @@
                       {{ e.detail }}
                     </div>
                   </el-tooltip>
-                  <el-rate :disabled="tType == 2" disabled-void-color @change="submit" v-model="e.cog"></el-rate>
+
+                  <div
+                    class="starB"
+                    @contextmenu.prevent="handleRightClick(index, $event)"
+                  >
+                    <div class="hangBlock">右键清空分数</div>
+                    <el-rate
+                      :disabled="tType == 2"
+                      disabled-void-color
+                      @change="submit"
+                      v-model="e.cog"
+                    ></el-rate>
+                  </div>
                 </div>
               </div>
             </div>
@@ -86,7 +110,7 @@
           <div class="AreaCss">
             <el-input
               type="textarea"
-              :placeholder="tType == 1 ?'您可在此输入评语':'暂无评语'"
+              :placeholder="tType == 1 ? '您可在此输入评语' : '暂无评语'"
               v-model="textarea"
               @blur="submit"
               :disabled="tType == 2"
@@ -98,7 +122,8 @@
                   currentUid.type == 10 ||
                   currentUid.type == 13 ||
                   isMarkCom == 1) &&
-                  !isMarkSco && tType == 1
+                  !isMarkSco &&
+                  tType == 1
               "
               class="anewC"
               @click="anewEva"
@@ -594,10 +619,11 @@ export default {
     this.selectSWorksData();
   },
   methods: {
-    setZero(index){
+    setZero(index) {
       console.log(index);
-      console.log('scoTitList',this.scoTitList);
+      console.log("scoTitList", this.scoTitList);
     },
+    // 重新生成
     async anewEva() {
       this.ScLoading = true;
 
@@ -760,7 +786,8 @@ export default {
             console.log("dArray", dArray);
             this.textarea = dArray[0].comment;
           }
-          this.submit()
+          // 上传评语
+          this.submit();
           this.$message.success("重新生成完成");
 
           this.ScLoading = false;
@@ -806,7 +833,47 @@ export default {
         }
       });
     },
+    // 评分点击右键
+    handleRightClick(val, event) {
+      // 阻止默认的右键菜单弹出
+      event.preventDefault();
+
+      this.scoTitList[val].cog = 0;
+
+      let data = this.scoTitList.map(e => {
+        return e.detail + ":" + e.cog;
+      });
+
+      const processedData = {};
+
+      data.forEach(item => {
+        const [key, value] = item.split(":");
+        processedData[key] = Number(value) ? Number(value) : 0;
+      });
+
+      processedData.content = this.textarea;
+      // console.log(processedData);
+      let params = {
+        cid: this.cid,
+        s: this.stage,
+        t: this.task,
+        tool: this.toolIndex ? this.toolIndex : "",
+        rate: JSON.stringify(processedData),
+        uid: this.DgUid
+      };
+      // return console.log(params);
+      this.ajax
+        .get(this.$store.state.api + "updateWorksEvaTwo", params)
+        .then(res => {
+          this.ScLoading = false;
+        })
+        .catch(err => {
+          this.$message.error("评价失败");
+          console.error(err);
+        });
 
+      // 在这里执行右键点击后的操作,使用传递的参数
+    },
     // 老师提交评分
     submit() {
       let data = this.scoTitList.map(e => {
@@ -1040,7 +1107,7 @@ export default {
 
     // ai打分
     aiGet2(messages, _fileid, work) {
-      if (!this.markScoreVisible) return console.log('弹框关闭了');
+      if (!this.markScoreVisible) return console.log("弹框关闭了");
 
       let _this = this;
 
@@ -1056,7 +1123,7 @@ export default {
         userId: this.cUserid,
         file_ids: _fileid ? [_fileid] : [],
         isImage: work.type == 1 ? true : "",
-        model: _fileid ? "gpt-4o-2024-08-06"  : "gpt-4o-2024-08-06"
+        model: _fileid ? "gpt-4o-2024-08-06" : "gpt-4o-2024-08-06"
       };
       this.ajax
         .post("https://gpt4.cocorobo.cn/ai_agent_park_chat", params)
@@ -1672,6 +1739,7 @@ export default {
 .AreaCss >>> .el-textarea__inner {
   min-height: 150px !important;
   /* max-height: 150px; */
+  color: #606266;
   padding-bottom: 20px;
 }
 .AreaBtn {
@@ -1931,9 +1999,33 @@ export default {
   background-color: #fff;
   bottom: 3px;
   right: 22px;
-  color: #3681FC;
+  color: #3681fc;
   cursor: pointer;
   font-size: 14px;
   transform: translate(0px, 2px);
 }
+
+.starB {
+  position: relative;
+}
+
+.starB:hover .hangBlock {
+  display: block;
+}
+
+.hangBlock {
+  display: none;
+  position: absolute;
+  right: 0%;
+  top: 50%;
+  color: rgba(0, 0, 0, 0.9);
+  font-family: PingFang SC;
+  padding: 5px 10px;
+  font-size: 12px;
+  box-sizing: border-box;
+  transform: translate(100%, -50%);
+  background-color: #fff;
+  border-radius: 6px;
+  box-shadow: 0px 5px 7px 0px rgba(0, 0, 0, 0.3);
+}
 </style>

Разница между файлами не показана из-за своего большого размера
+ 418 - 177
src/components/easy2/studyStudent.vue


+ 288 - 6
src/components/easy3/studyStudent.vue

@@ -1028,6 +1028,10 @@
                               alt
                             />
                             <div style="margin: 5px 0">问卷调查</div>
+														<div class="upload_toolBtn" v-if="tType==='1'" @click="openStatisticalAnalysis(tooC,toolIndex,taskCount)"
+                              style="position: absolute;right: 33px;top: -30px;">
+                              统计分析
+                            </div>
                           </div>
                           <div v-if="tooC == 45">
                             <img
@@ -1036,6 +1040,11 @@
                               alt
                             />
                             <div style="margin: 5px 0">选择题</div>
+
+														<div class="upload_toolBtn" v-if="tType==='1' && worksStudent[toolIndex].length>0" @click="openChoseWorksDetailDialog(tooC,toolIndex,taskCount)"
+                              style="position: absolute;right: 33px;top: -30px;">
+                              作业详细
+                            </div>
                           </div>
                           <!-- <div v-if="tooC == 5">
                             <img
@@ -8112,7 +8121,7 @@
       </div>
     </div>
 				<!-- v-show="org == '1973f6c7-1561-11ee-91d8-005056b86db5' || org == '777559d2-7239-11ee-b98c-005056b86db5' || org == '884c5665-a453-46f3-b7b6-01d575290aa9'" -->
-		<classRoomHelper v-if="!['2'].includes(tType)" :videoStart="videoStart" @startRecording="startRecording" @stopRecording="stopRecording" :fileList="vChapterData[taskCount]" :worksStudent="worksStudent" :courseType="parseInt(courseType)" :taskCount="taskCount" :tcid="tcid" :navList="navList" v-show="orgArray.includes(org) || oidArray.includes(oid)" ref="classRoomHelperRef" :courseDetail="courseDetail" :tType="tType" @setWidth="setClassRoomHelperWidth" @refresh="refreshCourse" @goStep="nextOrpreSteps" @authority="juriVisible = true" @review="setPz" @backPage="goTo(
+		<classRoomHelper v-if="!['2'].includes(tType)" @studentFreePreview="studentFreePreview" @OpenJobPreview="OpenJobPreview" :videoStart="videoStart" :IsFollow="IsFollow" :sIsOpen="sIsOpen" :IsLookOpen="IsLookOpen" :splitScreenData="splitScreenData" @splitScreenBehavior="splitScreenBehavior" @startRecording="startRecording" @stopRecording="stopRecording" :fileList="vChapterData[taskCount]" :worksStudent="worksStudent" :courseType="parseInt(courseType)" :taskCount="taskCount" :tcid="tcid" :navList="navList" v-show="orgArray.includes(org) || oidArray.includes(oid)" ref="classRoomHelperRef" :courseDetail="courseDetail" :tType="tType" @setWidth="setClassRoomHelperWidth" @refresh="refreshCourse" @goStep="nextOrpreSteps" @authority="juriVisible = true" @review="setPz" @backPage="goTo(
                     '/courseDetail?userid=' +
                       userid +
                       '&oid=' +
@@ -9978,7 +9987,7 @@
       <div slot="title" class="header-title">
         <div style="color: #fff">查看文档</div>
         <div
-          @click="fullDialogVisible = false"
+          @click="()=>{fullDialogVisible = false,changeSplitScreenBehavior({code:99})}"
           style="
             cursor: pointer;
             position: absolute;
@@ -11943,6 +11952,18 @@
     :scoreDetail="scoreDetail"
     @selectSWorks="selectSWorks" 
     @selectStudent="selectStudent"></checkEnglishVoice>
+		<statisticalAnalysis ref="statisticalAnalysisRef" @refresh="statisticalAnalysisRefresh"/>
+		<choseWorksDetailDialog
+      ref="choseWorksDetailDialogRef"
+      :worksStudentData="this.worksStudent"
+      :noWorksSData="noWorksS"
+      :chapInfoListData="chapInfoList"
+      :courseType="courseType"
+      :taskCount="taskCount"
+      @deleteWorks="deleteWorks"
+      @openTools="openTools"
+      @changeSplitScreenBehavior="changeSplitScreenBehavior"
+    />
   </div>
 </template>
 
@@ -11981,6 +12002,9 @@ import scoreItem from '../scoreList/scoreItem.vue'
 import scoreZong from '../scoreZong/index.vue'
 import classRoomHelper from '../classRoomHelper/index.vue'
 import MarkdownIt from "markdown-it";
+import statisticalAnalysis from '../components/statisticalAnalysis.vue'
+import choseWorksDetailDialog from '../components/choseWorksDetailDialog.vue'
+import { v4 as uuidv4 } from "uuid";
 
 const getFile = (url) => {
   return new Promise((resolve, reject) => {
@@ -12056,7 +12080,9 @@ export default {
 		correctText,
 		scoreItem,
 		classRoomHelper,
-    scoreZong
+    scoreZong,
+		statisticalAnalysis,
+		choseWorksDetailDialog
   },
   data() {
     return {
@@ -12424,7 +12450,15 @@ export default {
 			},
 			classRoomHelperWidth: '85px',
 			orgArray:[],
-      oidArray:[]
+      oidArray:[],
+			splitScreenData:{
+			isOpen:false,
+			userId:"",
+			uid:"",
+			myUid:"",
+			loading:false,
+			behavior:null,
+		}
     };
   },
   methods: {
@@ -14523,12 +14557,16 @@ export default {
                   ) {
                     continue;
                   }
+                  let _classId = this.arrayToArray(
+                      this.courseDetail.juri ? this.courseDetail.juri.split(",") : [],
+                      this.classId ? this.classId.split(",") : []
+                    )
                   if (gA == f[g].group && f[g].tool == i && (this.arrayToArray(
                       (f[g].classid ? f[g].classid.split(",") : []),
                       this.tcid.split(",")
                     ).length !== 0 || this.arrayToArray(
                       (f[g].classid ? f[g].classid.split(",") : []),
-                      this.classId ? this.classId.split(",") : []
+                      _classId
                     ).length !== 0 || (!this.tcid && this.tType == '1') || (this.courseDetail.juri === '') || f[g].ttype == 1)) {
                     this.groupStudent[i][gA].push(f[g]);
                     this.groupStudentUid[i][gA].push(f[g].userid);
@@ -16811,6 +16849,7 @@ export default {
           _this.selectStudent();
           _this.selectSLook();
           _this.getPick();
+					
           if (_this.courseDetail.userid == _this.userid && _this.IsFollow) {
             _this.setCTask();
           }
@@ -16836,6 +16875,7 @@ export default {
             _this.selectStudent();
             _this.selectSLook();
             _this.getPick();
+						_this.getSplitScreenData();//获取分屏数据
             if (_this.courseDetail.userid == _this.userid && _this.IsFollow) {
               _this.setCTask();
             }
@@ -17256,7 +17296,7 @@ export default {
             this.getCourseState(1);
           }
 
-          if (this.IsFollow && this.tType == 2) {
+          if ((this.IsFollow && this.tType == 2) || (this.splitScreenData.isOpen && this.splitScreenData.uid != this.splitScreenData.myUid)) {
             this.setContent2(false);
             let _followC = res.data[0][0].followC.split("-");
             if (
@@ -18904,6 +18944,7 @@ export default {
         this.fullUrl =
           "https://view.officeapps.live.com/op/view.aspx?src=" + encodeURIComponent(_uuurl);
       }
+			this.changeSplitScreenBehavior({code:0,form:[t,f]})
     },
     openSname(n, id, i, uid) {
       this.snameWid = id;
@@ -19321,6 +19362,9 @@ export default {
           }
         );
         let downloadUrl = URL.createObjectURL(videoFile);
+				if(this.$refs.classRoomHelperRef){
+					this.$refs.classRoomHelperRef.checkUploadFile(videoFile)
+				}
         document.body.appendChild(a);
         a.style.display = "none";
         a.href = url;
@@ -20055,6 +20099,240 @@ export default {
 		},
 		setClassRoomHelperWidth(width){
       this.classRoomHelperWidth = width
+    },
+		openStatisticalAnalysis(tooC,toolIndex,taskCount){
+			this.$refs.statisticalAnalysisRef.open({worksStudent:this.worksStudent[toolIndex],tType:this.tType,toolIndex:toolIndex})
+		},
+    openChoseWorksDetailDialog(tooC, toolIndex, taskCount) {
+      this.$refs.choseWorksDetailDialogRef.open({
+        tType: this.tType,
+        toolIndex: toolIndex
+      });
+      this.changeSplitScreenBehavior({
+        code: 1,
+        form: {
+          toolIndex: toolIndex,
+          courseType: this.courseType,
+          taskCount: this.taskCount,
+          type: 0
+        }
+      });
+    },
+    openStatisticalAnalysis(tooC, toolIndex, taskCount) {
+      this.$refs.statisticalAnalysisRef.open({
+        worksStudent: this.worksStudent[toolIndex],
+        tType: this.tType,
+        toolIndex: toolIndex
+      });
+    },
+    statisticalAnalysisRefresh(toolIndex) {
+      this.$refs.statisticalAnalysisRef.refreshData({
+        worksStudent: this.worksStudent[toolIndex],
+        tType: this.tType,
+        toolIndex: toolIndex
+      });
+    },
+    async splitScreenBehavior(type = 0) {
+      // return;
+      if (this.splitScreenData.loading)
+        return this.$message.info("操作过快,请稍等");
+      if (type == 0) {
+        //关闭分屏
+        this.splitScreenData.isOpen = false;
+        // this.splitScreenData.userId = "";
+        // this.splitScreenData.uid = "";
+        this.splitScreenData.behavior = null;
+        await this.updateSplitScreenData(1);
+        this.$message.success("已关闭分屏模式");
+        this.studentFreePreview(false);
+        this.OpenJobPreview(false);
+        this.followingMode(false);
+      } else if (type == 1) {
+        //开启分屏
+        this.splitScreenData.isOpen = true;
+        this.splitScreenData.userId = this.userid;
+        this.splitScreenData.uid = this.splitScreenData.myUid;
+        this.splitScreenData.behavior = null;
+        let status = await this.updateSplitScreenData(0);
+
+        if (status == 1) {
+          this.$message.success("已开启分屏");
+          this.studentFreePreview(true);
+          this.OpenJobPreview(true);
+          this.followingMode(true);
+        } else {
+          this.splitScreenData.isOpen = false;
+          this.splitScreenData.userId = "";
+          this.splitScreenData.uid = "";
+          this.splitScreenData.behavior = null;
+          this.$message.success("分屏开启失败");
+        }
+      }
+    },
+    getSplitScreenData() {
+      // return;
+      if (this.tType != 1) return;
+      let params = {
+        cid: this.id
+      };
+      this.ajax
+        .get(this.$store.state.api + "select_courseSplitScreenData", params)
+        .then(async res => {
+          let data = res.data[0][0]["splitScreenData"];
+          console.log("获取了分屏数:", data);
+          if (data) {
+            data = JSON.parse(data);
+            if (
+              !this.splitScreenData.isOpen &&
+              data.isOpen &&
+              this.splitScreenData.myUid == data.uid
+            ) {
+              this.splitScreenData.isOpen = false;
+              this.splitScreenData.userId = "";
+              this.splitScreenData.uid = "";
+              this.splitScreenData.behavior = null;
+              await this.updateSplitScreenData(1);
+            } else if (!this.splitScreenData.isOpen && data.isOpen) {
+              this.splitScreenData.isOpen = true;
+              this.splitScreenData.uid = data.uid;
+              this.splitScreenData.userId = data.userId;
+              this.splitScreenData.behavior = data.behavior;
+              this.$message.success("分屏模式已开启");
+            } else if (this.splitScreenData.isOpen && !data.isOpen) {
+              this.splitScreenData.isOpen = false;
+              this.splitScreenData.userId = "";
+              this.splitScreenData.uid = "";
+              this.splitScreenData.behavior = null;
+              this.$message.error("已结束分屏模式");
+            } else if (this.splitScreenData.isOpen && data.isOpen) {
+              this.splitScreenData.isOpen = true;
+              this.splitScreenData.uid = data.uid;
+              this.splitScreenData.userId = data.userId;
+              this.splitScreenData.behavior = data.behavior;
+            }
+
+            this.doSplitScreenBehavior();
+          } else {
+            if (this.splitScreenData.isOpen) {
+              this.splitScreenData.isOpen = false;
+              this.splitScreenData.userId = "";
+              this.splitScreenData.uid = "";
+              this.splitScreenData.behavior = null;
+              this.$message.error("已结束分屏模式");
+            }
+          }
+        })
+        .catch(e => {
+          console.log("获取分屏数出错:", e);
+        });
+    },
+    doSplitScreenBehavior() {
+      if (
+        this.splitScreenData.isOpen &&
+        this.splitScreenData.uid != this.splitScreenData.myUid
+      ) {
+        let behavior = this.splitScreenData.behavior;
+        if (behavior) {
+          if (behavior.code === 99) {
+            //初始化
+            this.fullDialogVisible = false;
+						if(this.$refs.choseWorksDetailDialogRef.show){
+							this.$refs.choseWorksDetailDialogRef.close();
+						}
+          } else if (behavior.code === 0) {
+            //开启内容列表弹窗
+            this.checkFileFull1(behavior.form[0], behavior.form[1]);
+          } else if (behavior.code === 1) {
+            //关于选择题的作业详细的操作
+            // toolIndex:toolIndex,courseType:this.courseType,taskCount:this.taskCount,type:0
+            this.courseType = behavior.form.courseType;
+            this.taskCount = behavior.form.taskCount;
+            this.$nextTick(() => {
+              if (this.$refs.choseWorksDetailDialogRef.show) {
+                //已经打开了
+								this.$refs.choseWorksDetailDialogRef.splitScreenFn({type:behavior.form.type,showStatisticsType:behavior.form.showStatisticsType})
+              } else {
+								this.$refs.choseWorksDetailDialogRef.open({toolIndex:behavior.form.toolIndex,tType: this.tType,})
+              }
+            });
+          }
+        } else {
+        }
+      }
+    },
+    updateSplitScreenData(empty = 0) {
+      // return
+      return new Promise(resolve => {
+				if(this.userid!==this.courseDetail.userid)return;
+        if (
+          this.splitScreenData.uid == this.splitScreenData.myUid &&
+          this.splitScreenData.userId == this.userid
+        ) {
+          this.splitScreenData.loading = true;
+          let params = [
+            {
+              cid: this.id,
+              nData: empty === 1 ? "" : JSON.stringify(this.splitScreenData)
+            }
+          ];
+
+          this.ajax
+            .post(
+              this.$store.state.api + "update_courseSplitScreenData",
+              params
+            )
+            .then(res => {
+              this.splitScreenData.loading = false;
+              if (res.data == 1) {
+                resolve(1);
+                console.log("修改分屏数据成功");
+              }
+            })
+            .catch(e => {
+              this.splitScreenData.loading = false;
+              console.log("修改分屏数据失败", e);
+              resoleve(0);
+            });
+        } else if (empty == 2 && this.tType == 1) {
+          let params = [
+            {
+              cid: this.id,
+              nData: ""
+            }
+          ];
+
+          return this.ajax
+            .post(
+              this.$store.state.api + "update_courseSplitScreenData",
+              params
+            )
+            .then(_ => resolve(1))
+            .catch(_ => resolve(0));
+        } else {
+          return resolve(0);
+        }
+      });
+    },
+    changeSplitScreenBehavior(newValue) {
+      if (
+        this.splitScreenData.isOpen &&
+        this.splitScreenData.uid == this.splitScreenData.myUid
+      ) {
+        this.splitScreenData.behavior = newValue;
+        this.updateSplitScreenData(0);
+      }
+    },
+    studentFreePreview(flag) {
+      this.IsLookOpen = flag;
+      this.updateLookOpen();
+    },
+    OpenJobPreview(flag) {
+      this.sIsOpen = flag;
+      this.updateSLook();
+    },
+    followingMode(flag) {
+      this.IsFollow = flag;
+      this.updateFollow();
     }
   },
   directives: {
@@ -20099,6 +20377,7 @@ export default {
     this.timer = null;
     clearInterval(this.opertimer);
     this.opertimer = null;
+		this.updateSplitScreenData(1); 
   },
   computed: {
     getHeight(){
@@ -20231,6 +20510,7 @@ export default {
         return c;
       };
     },
+
   },
   mounted() {
     document.body.addEventListener("click", (e) => {
@@ -20260,6 +20540,8 @@ export default {
     }
 		// 获取评分列表
 		this.getScoreList()
+		this.updateSplitScreenData(2);
+		this.splitScreenData.myUid = uuidv4();
     document.scrollingElement.scrollTop = 0;
     window.addEventListener("resize", () => {
       var a = document.getElementsByClassName("box_course")[0].offsetHeight;

+ 32 - 9
src/components/index.vue

@@ -61,7 +61,8 @@
       </div>
       <div class="body_student" v-loading="loading">
         <div class="typeCheck">
-          <el-switch v-model="typeCheck"></el-switch><span>分类显示</span>
+          <div><el-switch v-model="orderBy"></el-switch><span>按名字排序</span></div>
+          <div><el-switch v-model="typeCheck"></el-switch><span>分类显示</span></div>
         </div>
         <div>
           <div class="main_box">
@@ -261,6 +262,7 @@ export default {
       typeE: [],
       loading: "",
       typeCheck: false,
+      orderBy: false,
       CourseType3: [],
       pTypeCheck:[],
       pTypeCheckName: [],
@@ -275,7 +277,16 @@ export default {
         this.page = 1
         this.selectAll2()
       }
-    }
+    },
+    orderBy(newValue, oldValue) {
+      this.loading = true
+      if (this.typeCheck) {
+        this.selectAll()
+      } else {
+        this.page = 1
+        this.selectAll2()
+      }
+    },
   },
   methods: {
     search(){
@@ -543,9 +554,10 @@ export default {
         classid: this.classId,
         org: this.org,
         page: this.page,
+        orderBy: this.orderBy ? '2' : '1'
       };
       this.ajax
-        .get(this.$store.state.api + "selectTypeCourse2Mode", params)
+        .get(this.$store.state.api + "selectTypeCourse2Mode2", params)
         .then((res) => {
           this.loading = false;
           this.isListAjax = false;
@@ -619,10 +631,11 @@ export default {
         classid: this.classId,
         org: this.org,
         page: this.page,
-        pageSize:this.pageSize
+        pageSize:this.pageSize,
+        orderBy: this.orderBy ? '2' : '1'
       };
       this.ajax
-        .get(this.$store.state.api + "selectTypeCourse2", params)
+        .get(this.$store.state.api + "selectTypeCourse22", params)
         .then((res) => {
           this.loading = false;
           this.isListAjax = false;
@@ -1053,7 +1066,7 @@ export default {
 }
 
 .textOverflow > .utitle{
-  max-width: calc(100% - 100px);
+  max-width: calc(100%);
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
@@ -1061,7 +1074,7 @@ export default {
   display: block;
 }
 .textOverflow > .uname{
-  max-width: 90px;
+  min-width: fit-content;
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
@@ -1099,7 +1112,7 @@ export default {
 }
 
 .all_choose>span {
-  min-width: 80px;
+  min-width: 85px;
   display: block;
   letter-spacing: 14px;
 }
@@ -1267,6 +1280,10 @@ export default {
   font-weight: 700;
 }
 
+.typeCheck > div + div{
+  margin-left: 10px;
+}
+
 .typeCheck {
   display: flex;
   align-items: center;
@@ -1274,7 +1291,13 @@ export default {
   margin-bottom: 10px;
 }
 
-.typeCheck>span {
+.typeCheck > div{
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+}
+
+.typeCheck > div >span {
   margin-left: 10px;
 }
 

+ 294 - 7
src/components/studyStudent.vue

@@ -997,6 +997,11 @@
                               alt
                             />
                             <div style="margin: 5px 0">问卷调查</div>
+														<div class="upload_toolBtn" v-if="tType==='1'" @click="openStatisticalAnalysis(tooC,toolIndex,taskCount)"
+                              style="position: absolute;right: 33px;top: -30px;">
+                              统计分析
+                            </div>
+														
                           </div>
                           <div v-if="tooC == 45">
                             <img
@@ -1005,6 +1010,11 @@
                               alt
                             />
                             <div style="margin: 5px 0">选择题</div>
+
+														<div class="upload_toolBtn" v-if="tType==='1'" @click="openChoseWorksDetailDialog(tooC,toolIndex,taskCount)"
+                              style="position: absolute;right: 33px;top: -30px;">
+                              作业详细
+                            </div>
                           </div>
                           <!-- <div v-if="tooC == 5">
                             <img
@@ -8080,7 +8090,7 @@
         </el-dialog>
       </div>
 			<!-- v-show="org == '1973f6c7-1561-11ee-91d8-005056b86db5' || org == '777559d2-7239-11ee-b98c-005056b86db5' || org == '884c5665-a453-46f3-b7b6-01d575290aa9'" -->
-      <classRoomHelper v-if="!['2'].includes(tType)" :videoStart="videoStart" @startRecording="startRecording" @stopRecording="stopRecording" :fileList="vChapterData[taskCount]" :worksStudent="worksStudent" :courseType="parseInt(courseType)" :taskCount="taskCount" :tcid="tcid" :navList="navList" v-show="orgArray.includes(org) || oidArray.includes(oid)"  ref="classRoomHelperRef" :courseDetail="courseDetail" :tType="tType" @setWidth="setClassRoomHelperWidth" @refresh="refreshCourse" @goStep="nextOrpreSteps" @authority="juriVisible = true" @review="setPz" @backPage="goTo(
+      <classRoomHelper v-if="!['2'].includes(tType)" @studentFreePreview="studentFreePreview" @OpenJobPreview="OpenJobPreview" :videoStart="videoStart" :splitScreenData="splitScreenData" @splitScreenBehavior="splitScreenBehavior" @startRecording="startRecording" @stopRecording="stopRecording" :fileList="vChapterData[taskCount]" :worksStudent="worksStudent" :courseType="parseInt(courseType)" :taskCount="taskCount" :tcid="tcid" :navList="navList" v-show="orgArray.includes(org) || oidArray.includes(oid)"  ref="classRoomHelperRef" :courseDetail="courseDetail" :tType="tType" @setWidth="setClassRoomHelperWidth" @refresh="refreshCourse" @goStep="nextOrpreSteps" @authority="juriVisible = true" @review="setPz" @backPage="goTo(
                     '/courseDetail?userid=' +
                       userid +
                       '&oid=' +
@@ -9923,7 +9933,7 @@
       <div slot="title" class="header-title">
         <div style="color: #fff">查看文档</div>
         <div
-          @click="fullDialogVisible = false"
+          @click="()=>{fullDialogVisible = false,changeSplitScreenBehavior({code:99})}"
           style="
             cursor: pointer;
             position: absolute;
@@ -11884,6 +11894,18 @@
     :scoreDetail="scoreDetail"
     @selectSWorks="selectSWorks" 
     @selectStudent="selectStudent"></checkEnglishVoice>
+		<statisticalAnalysis ref="statisticalAnalysisRef" @refresh="statisticalAnalysisRefresh"/>
+		<choseWorksDetailDialog
+      ref="choseWorksDetailDialogRef"
+      :worksStudentData="this.worksStudent"
+      :noWorksSData="noWorksS"
+      :chapInfoListData="chapInfoList"
+      :courseType="courseType"
+      :taskCount="taskCount"
+      @deleteWorks="deleteWorks"
+      @openTools="openTools"
+      @changeSplitScreenBehavior="changeSplitScreenBehavior"
+    />
   </div>
 </template>
 
@@ -11921,6 +11943,9 @@ import correctText from './components/correctText.vue'
 import scoreItem from './scoreList/scoreItem.vue'
 import scoreZong from './scoreZong/index.vue'
 import classRoomHelper from './classRoomHelper/index.vue'
+import statisticalAnalysis from "./components/statisticalAnalysis.vue";
+import choseWorksDetailDialog from './components/choseWorksDetailDialog.vue';
+import { v4 as uuidv4 } from "uuid";
 
 const getFile = (url) => {
   return new Promise((resolve, reject) => {
@@ -11996,7 +12021,9 @@ export default {
 		correctText,
 		scoreItem,
     classRoomHelper,
-    scoreZong
+    scoreZong,
+		statisticalAnalysis,
+		choseWorksDetailDialog
   },
   data() {
     return {
@@ -12402,7 +12429,15 @@ export default {
     26: "课程设计",
     62: "交互视频",
     71: "AI智能体"
-}
+},
+		splitScreenData:{
+			isOpen:false,
+			userId:"",
+			uid:"",
+			myUid:"",
+			loading:false,
+			behavior:null,
+		}
     };
   },
   methods: {
@@ -14506,12 +14541,16 @@ export default {
                   ) {
                     continue;
                   }
+                  let _classId = this.arrayToArray(
+                      this.courseDetail.juri ? this.courseDetail.juri.split(",") : [],
+                      this.classId ? this.classId.split(",") : []
+                    )
                   if (gA == f[g].group && f[g].tool == i && (this.arrayToArray(
                       (f[g].classid ? f[g].classid.split(",") : []),
                       this.tcid.split(",")
                     ).length !== 0 || this.arrayToArray(
                       (f[g].classid ? f[g].classid.split(",") : []),
-                      this.classId ? this.classId.split(",") : []
+                      _classId
                     ).length !== 0 || (!this.tcid && this.tType == '1') || (this.courseDetail.juri === '') || f[g].ttype == 1)) {
                     this.groupStudent[i][gA].push(f[g]);
                     this.groupStudentUid[i][gA].push(f[g].userid);
@@ -16826,6 +16865,8 @@ export default {
             _this.selectStudent();
             _this.selectSLook();
             _this.getPick();
+						_this.getSplitScreenData();
+
             if (_this.courseDetail.userid == _this.userid && _this.IsFollow) {
               _this.setCTask();
             }
@@ -17247,7 +17288,7 @@ export default {
             this.getCourseState(1);
           }
 
-          if (this.IsFollow && this.tType == 2) {
+          if ((this.IsFollow && this.tType == 2) || this.splitScreenData.isOpen) {
             this.setContent2(false);
             let _followC = res.data[0][0].followC.split("-");
             if (
@@ -18873,6 +18914,9 @@ export default {
       this.fullUrl = url;
     },
     async checkFileFull1(t, f) {
+
+			
+
       this.fullDialogVisible = true;
       if (t == 6) {
         this.fulltype = 1;
@@ -18893,7 +18937,8 @@ export default {
         this.fullUrl =
           "https://view.officeapps.live.com/op/view.aspx?src=" + encodeURIComponent(_uuurl);
       }
-    },
+			this.changeSplitScreenBehavior({code:0,form:[t,f]})
+		},
     openSname(n, id, i, uid) {
       this.snameWid = id;
       this.worksSName = n;
@@ -19306,6 +19351,9 @@ export default {
           }
         );
         let downloadUrl = URL.createObjectURL(videoFile);
+				if(this.$refs.classRoomHelperRef){
+					this.$refs.classRoomHelperRef.checkUploadFile(videoFile)
+				}
         document.body.appendChild(a);
         a.style.display = "none";
         a.href = url;
@@ -20041,6 +20089,240 @@ export default {
 		},
     setClassRoomHelperWidth(width){
       this.classRoomHelperWidth = width
+    },
+		openStatisticalAnalysis(tooC,toolIndex,taskCount){
+			this.$refs.statisticalAnalysisRef.open({worksStudent:this.worksStudent[toolIndex],tType:this.tType,toolIndex:toolIndex})
+		},
+    openChoseWorksDetailDialog(tooC, toolIndex, taskCount) {
+      this.$refs.choseWorksDetailDialogRef.open({
+        tType: this.tType,
+        toolIndex: toolIndex
+      });
+      this.changeSplitScreenBehavior({
+        code: 1,
+        form: {
+          toolIndex: toolIndex,
+          courseType: this.courseType,
+          taskCount: this.taskCount,
+          type: 0
+        }
+      });
+    },
+    openStatisticalAnalysis(tooC, toolIndex, taskCount) {
+      this.$refs.statisticalAnalysisRef.open({
+        worksStudent: this.worksStudent[toolIndex],
+        tType: this.tType,
+        toolIndex: toolIndex
+      });
+    },
+    statisticalAnalysisRefresh(toolIndex) {
+      this.$refs.statisticalAnalysisRef.refreshData({
+        worksStudent: this.worksStudent[toolIndex],
+        tType: this.tType,
+        toolIndex: toolIndex
+      });
+    },
+    async splitScreenBehavior(type = 0) {
+      // return;
+      if (this.splitScreenData.loading)
+        return this.$message.info("操作过快,请稍等");
+      if (type == 0) {
+        //关闭分屏
+        this.splitScreenData.isOpen = false;
+        // this.splitScreenData.userId = "";
+        // this.splitScreenData.uid = "";
+        this.splitScreenData.behavior = null;
+        await this.updateSplitScreenData(1);
+        this.$message.success("已关闭分屏模式");
+        this.studentFreePreview(false);
+        this.OpenJobPreview(false);
+        this.followingMode(false);
+      } else if (type == 1) {
+        //开启分屏
+        this.splitScreenData.isOpen = true;
+        this.splitScreenData.userId = this.userid;
+        this.splitScreenData.uid = this.splitScreenData.myUid;
+        this.splitScreenData.behavior = null;
+        let status = await this.updateSplitScreenData(0);
+
+        if (status == 1) {
+          this.$message.success("已开启分屏");
+          this.studentFreePreview(true);
+          this.OpenJobPreview(true);
+          this.followingMode(true);
+        } else {
+          this.splitScreenData.isOpen = false;
+          this.splitScreenData.userId = "";
+          this.splitScreenData.uid = "";
+          this.splitScreenData.behavior = null;
+          this.$message.success("分屏开启失败");
+        }
+      }
+    },
+    getSplitScreenData() {
+      // return;
+      if (this.tType != 1) return;
+      let params = {
+        cid: this.id
+      };
+      this.ajax
+        .get(this.$store.state.api + "select_courseSplitScreenData", params)
+        .then(async res => {
+          let data = res.data[0][0]["splitScreenData"];
+          console.log("获取了分屏数:", data);
+          if (data) {
+            data = JSON.parse(data);
+            if (
+              !this.splitScreenData.isOpen &&
+              data.isOpen &&
+              this.splitScreenData.myUid == data.uid
+            ) {
+              this.splitScreenData.isOpen = false;
+              this.splitScreenData.userId = "";
+              this.splitScreenData.uid = "";
+              this.splitScreenData.behavior = null;
+              await this.updateSplitScreenData(1);
+            } else if (!this.splitScreenData.isOpen && data.isOpen) {
+              this.splitScreenData.isOpen = true;
+              this.splitScreenData.uid = data.uid;
+              this.splitScreenData.userId = data.userId;
+              this.splitScreenData.behavior = data.behavior;
+              this.$message.success("分屏模式已开启");
+            } else if (this.splitScreenData.isOpen && !data.isOpen) {
+              this.splitScreenData.isOpen = false;
+              this.splitScreenData.userId = "";
+              this.splitScreenData.uid = "";
+              this.splitScreenData.behavior = null;
+              this.$message.error("已结束分屏模式");
+            } else if (this.splitScreenData.isOpen && data.isOpen) {
+              this.splitScreenData.isOpen = true;
+              this.splitScreenData.uid = data.uid;
+              this.splitScreenData.userId = data.userId;
+              this.splitScreenData.behavior = data.behavior;
+            }
+
+            this.doSplitScreenBehavior();
+          } else {
+            if (this.splitScreenData.isOpen) {
+              this.splitScreenData.isOpen = false;
+              this.splitScreenData.userId = "";
+              this.splitScreenData.uid = "";
+              this.splitScreenData.behavior = null;
+              this.$message.error("已结束分屏模式");
+            }
+          }
+        })
+        .catch(e => {
+          console.log("获取分屏数出错:", e);
+        });
+    },
+    doSplitScreenBehavior() {
+      if (
+        this.splitScreenData.isOpen &&
+        this.splitScreenData.uid != this.splitScreenData.myUid
+      ) {
+        let behavior = this.splitScreenData.behavior;
+        if (behavior) {
+          if (behavior.code === 99) {
+            //初始化
+            this.fullDialogVisible = false;
+						if(this.$refs.choseWorksDetailDialogRef.show){
+							this.$refs.choseWorksDetailDialogRef.close();
+						}
+          } else if (behavior.code === 0) {
+            //开启内容列表弹窗
+            this.checkFileFull1(behavior.form[0], behavior.form[1]);
+          } else if (behavior.code === 1) {
+            //关于选择题的作业详细的操作
+            // toolIndex:toolIndex,courseType:this.courseType,taskCount:this.taskCount,type:0
+            this.courseType = behavior.form.courseType;
+            this.taskCount = behavior.form.taskCount;
+            this.$nextTick(() => {
+              if (this.$refs.choseWorksDetailDialogRef.show) {
+                //已经打开了
+								this.$refs.choseWorksDetailDialogRef.splitScreenFn({type:behavior.form.type,showStatisticsType:behavior.form.showStatisticsType})
+              } else {
+								this.$refs.choseWorksDetailDialogRef.open({toolIndex:behavior.form.toolIndex,tType: this.tType,})
+              }
+            });
+          }
+        } else {
+        }
+      }
+    },
+    updateSplitScreenData(empty = 0) {
+      // return
+      return new Promise(resolve => {
+				if(this.userid!==this.courseDetail.userid)return;
+        if (
+          this.splitScreenData.uid == this.splitScreenData.myUid &&
+          this.splitScreenData.userId == this.userid
+        ) {
+          this.splitScreenData.loading = true;
+          let params = [
+            {
+              cid: this.id,
+              nData: empty === 1 ? "" : JSON.stringify(this.splitScreenData)
+            }
+          ];
+
+          this.ajax
+            .post(
+              this.$store.state.api + "update_courseSplitScreenData",
+              params
+            )
+            .then(res => {
+              this.splitScreenData.loading = false;
+              if (res.data == 1) {
+                resolve(1);
+                console.log("修改分屏数据成功");
+              }
+            })
+            .catch(e => {
+              this.splitScreenData.loading = false;
+              console.log("修改分屏数据失败", e);
+              resoleve(0);
+            });
+        } else if (empty == 2 && this.tType == 1) {
+          let params = [
+            {
+              cid: this.id,
+              nData: ""
+            }
+          ];
+
+          return this.ajax
+            .post(
+              this.$store.state.api + "update_courseSplitScreenData",
+              params
+            )
+            .then(_ => resolve(1))
+            .catch(_ => resolve(0));
+        } else {
+          return resolve(0);
+        }
+      });
+    },
+    changeSplitScreenBehavior(newValue) {
+      if (
+        this.splitScreenData.isOpen &&
+        this.splitScreenData.uid == this.splitScreenData.myUid
+      ) {
+        this.splitScreenData.behavior = newValue;
+        this.updateSplitScreenData(0);
+      }
+    },
+    studentFreePreview(flag) {
+      this.IsLookOpen = flag;
+      this.updateLookOpen();
+    },
+    OpenJobPreview(flag) {
+      this.sIsOpen = flag;
+      this.updateSLook();
+    },
+    followingMode(flag) {
+      this.IsFollow = flag;
+      this.updateFollow();
     }
   },
   directives: {
@@ -20085,6 +20367,7 @@ export default {
     this.timer = null;
     clearInterval(this.opertimer);
     this.opertimer = null;
+		this.updateSplitScreenData(1); 
   },
   computed: {
     contentConvent() {
@@ -20228,6 +20511,10 @@ export default {
     this.getHomeWork();
     this.selectUser();
 		this.getAIJ();
+
+		this.updateSplitScreenData(2);
+		this.splitScreenData.myUid = uuidv4();
+
     this.contentDialog = true;
     this.setContent2(true);
     if (this.tType == 4) {

Некоторые файлы не были показаны из-за большого количества измененных файлов