|
@@ -0,0 +1,1581 @@
|
|
|
+<template>
|
|
|
+ <div class="pbl">
|
|
|
+ <!-- <button @click="lookPage">导出</button> -->
|
|
|
+ <!-- <el-dialog
|
|
|
+ title="导出作业集"
|
|
|
+ :visible.sync="worksDialog"
|
|
|
+ :before-close="handleClose"
|
|
|
+ class="full_diy"
|
|
|
+ :append-to-body="true"
|
|
|
+ > -->
|
|
|
+ <!-- :style="{ backgroundColor: schoolImg.bkColor, position: 'relative' }" -->
|
|
|
+ <div ref="reportPdf" v-loading="loading">
|
|
|
+ <div
|
|
|
+ class="coverPage"
|
|
|
+ :style="{
|
|
|
+ backgroundColor: schoolImg.bkColor ? schoolImg.bkColor : '#E5EFFE'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <div class="coverPageLogo">
|
|
|
+ <img :src="schoolImg.logo ? schoolImg.logo : ''" alt="" />
|
|
|
+ </div>
|
|
|
+ <div class="coverPageFrom" style="z-index: 10;">
|
|
|
+ <div class="coverPageFromTit">
|
|
|
+ <img src="../../../assets/icon/exportPdfworks/title.png" alt="" />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="fromCss">
|
|
|
+ <div>
|
|
|
+ <span>姓名:</span>
|
|
|
+ <div class="txt">{{ worksDialogCon2.sName }}</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <span>班级:</span>
|
|
|
+ <div class="txt">{{ worksDialogCon2.class }}</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <span>学校:</span>
|
|
|
+ <div class="txt">{{ worksDialogCon2.schName }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="coverPageFrom">
|
|
|
+ <img
|
|
|
+ style="z-index: 10;"
|
|
|
+ src="../../../assets/icon/exportPdfworks/cocoroboCon.svg"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="coverPageCon">
|
|
|
+ <div
|
|
|
+ style="
|
|
|
+ text-align: center;
|
|
|
+ font-weight: 600;
|
|
|
+ font-size: 26px;
|
|
|
+ margin: 10px 0;
|
|
|
+ color: rgba(58, 59, 152, 1);
|
|
|
+ "
|
|
|
+ >
|
|
|
+ {{ courseTit }}
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ style="font-weight: 600; font-size: 16px; color: rgba(0, 0, 0, 0.9);margin: 10px 0;"
|
|
|
+ >
|
|
|
+ <li>学习总览</li>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ style="
|
|
|
+ text-align: center;
|
|
|
+ font-weight: 600;
|
|
|
+ font-size: 14px;
|
|
|
+ color: rgba(0, 0, 0, 0.9);
|
|
|
+ margin: 10px 0;
|
|
|
+ "
|
|
|
+ >
|
|
|
+ 综合表现
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div style="display: flex; justify-content: space-between">
|
|
|
+ <div class="zhBlock">
|
|
|
+ <div class="zhBlockTit">
|
|
|
+ <span style="margin-right: 5px">登录时长</span
|
|
|
+ ><img
|
|
|
+ src="../../../assets/icon/exportPdfworks/infocircle.svg"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="zhBlockCon">{{ loginTime }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="zhBlock">
|
|
|
+ <div class="zhBlockTit">
|
|
|
+ <span style="margin-right: 5px">学习时长</span
|
|
|
+ ><img
|
|
|
+ src="../../../assets/icon/exportPdfworks/infocircle.svg"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="zhBlockCon">{{ studyTime }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="zhBlock">
|
|
|
+ <div class="zhBlockTit">
|
|
|
+ <span style="margin-right: 5px">学习成绩</span
|
|
|
+ ><img
|
|
|
+ src="../../../assets/icon/exportPdfworks/infocircle.svg"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="zhBlockCon">
|
|
|
+ <div class="zhBlockCon">{{ star }} / 5.0</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="zhBlock">
|
|
|
+ <div class="zhBlockTit">
|
|
|
+ <span style="margin-right: 5px">包含学科</span
|
|
|
+ ><img
|
|
|
+ src="../../../assets/icon/exportPdfworks/infocircle.svg"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="zhBlockCon2">
|
|
|
+ <div>
|
|
|
+ <span v-for="(i,index) in subject" :key="index">{{ i }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ style="display: flex;justify-content: space-between; height: 310px;margin-bottom: 30px"
|
|
|
+ >
|
|
|
+ <div class="zxt" style="width: 49%">
|
|
|
+ <div ref="chart" style="width: 100%; height: 300px"></div>
|
|
|
+ </div>
|
|
|
+ <div class="zxt" style="width: 49%">
|
|
|
+ <div ref="ringChart" style="height: 300px; width: 100%"></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 作业提交率 -->
|
|
|
+ <div class="zxt">
|
|
|
+ <div style="height: 350px; width: 100%" ref="toolSubEcharts"></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 分组工具使用数量 -->
|
|
|
+ <div class="zxt">
|
|
|
+ <div style="height: 350px; width: 100%" ref="groupingEcharts"></div>
|
|
|
+ </div>
|
|
|
+ <!-- 师生互动次数 -->
|
|
|
+ <div class="zxt">
|
|
|
+ <div
|
|
|
+ style="height: 350px; width: 100%"
|
|
|
+ ref="interactionEcharts"
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+ <!-- 互动次数主动 -->
|
|
|
+ <div class="zxt">
|
|
|
+ <div
|
|
|
+ style="height: 350px; width: 100%"
|
|
|
+ ref="stuInteractZdEcharts"
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+ <!-- 互动次数主动 -->
|
|
|
+ <div class="zxt">
|
|
|
+ <div
|
|
|
+ style="height: 350px; width: 100%"
|
|
|
+ ref="bdStuInteractZdEcharts"
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+ <!-- 课程得分 -->
|
|
|
+ <div class="zxt">
|
|
|
+ <div style="height: 350px; width: 100%" ref="cScoEcharts"></div>
|
|
|
+ </div>
|
|
|
+ <div style="display: flex;justify-content: flex-end;">
|
|
|
+ <img :src="schoolImg.bjLogo ? schoolImg.bjLogo : ''" alt="" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- </el-dialog> -->
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import html2canvas from "html2canvas";
|
|
|
+import jspdf from "jspdf";
|
|
|
+import JSZip from "jszip";
|
|
|
+import * as echarts from "echarts";
|
|
|
+
|
|
|
+export default {
|
|
|
+ props: [
|
|
|
+ "multipleSelection",
|
|
|
+ "cid",
|
|
|
+ "worksDialog",
|
|
|
+ "worksDialogCon",
|
|
|
+ "digNum"
|
|
|
+ ],
|
|
|
+
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ star: 0,
|
|
|
+ // 课程类型
|
|
|
+ cState: "",
|
|
|
+ // 课程名称
|
|
|
+ courseTit: "",
|
|
|
+ // 学习时长
|
|
|
+ studyTime: "",
|
|
|
+ // 登录时长
|
|
|
+ loginTime: "",
|
|
|
+
|
|
|
+ // 五边形图开始
|
|
|
+ chartData: [
|
|
|
+ [1, 2, 3, 4, 5],
|
|
|
+ [2, 3, 4, 3, 2]
|
|
|
+ ],
|
|
|
+ categories: ["A", "B", "C", "D", "E"],
|
|
|
+ // 五边形图结束
|
|
|
+
|
|
|
+ // 环形图数据开始
|
|
|
+ toolData: [[], [], [], [], [], [], []],
|
|
|
+ toolRatio: [
|
|
|
+ { name: "互动类", value: 0 },
|
|
|
+ { name: "思维类", value: 0 },
|
|
|
+ { name: "协作类", value: 0 },
|
|
|
+ { name: "测评类", value: 0 },
|
|
|
+ { name: "评价类", value: 0 },
|
|
|
+ { name: "编程类", value: 0 },
|
|
|
+ { name: "学科类", value: 0 }
|
|
|
+ ],
|
|
|
+ // 环形图数据结束
|
|
|
+
|
|
|
+ // 作业提交率折线图开始
|
|
|
+ stageList: [], // 阶段
|
|
|
+ stageListPer: [], // 阶段所占百分比
|
|
|
+ toolPercentage: [], // 每个阶段有的工具
|
|
|
+ // 作业提交率折线图结束
|
|
|
+
|
|
|
+ // 作业得分折线图开始
|
|
|
+ taskList: [], //每个阶段下有几个任务
|
|
|
+ scoFoldLineData: [], //课程得分图数据
|
|
|
+ // 作业得分折线图结束
|
|
|
+
|
|
|
+ // 分数工具柱状图开始
|
|
|
+ columnData: [],
|
|
|
+ // 分数工具柱状图结束
|
|
|
+
|
|
|
+ // 师生在线互动次数开始
|
|
|
+ interact: [], //每个阶段下师生互动工具
|
|
|
+ interactWork: [], //每个工具下提交的作业
|
|
|
+ // 师生在线互动次数结束
|
|
|
+
|
|
|
+ // 生生互动主动开始
|
|
|
+ stuInterAllWork: [],
|
|
|
+ stuInterAllLike: [],
|
|
|
+
|
|
|
+ // 生生互动主动结束
|
|
|
+
|
|
|
+ // 生生互动被动开始
|
|
|
+ bdStuInterAllWork: [],
|
|
|
+ bdStuInterAllLike: [],
|
|
|
+ // 生生互动被动结束
|
|
|
+
|
|
|
+ // 工具类大分类
|
|
|
+ hd: [10, 65],
|
|
|
+ sw: [7, 1, 52, 3, 52],
|
|
|
+ xz: [49],
|
|
|
+ cp: [4, 45, 15, 16, 50, 41, 47],
|
|
|
+ pj: [40],
|
|
|
+ bc: [18, 21, 23, 24, 32, 57, 63, 71],
|
|
|
+ xk: [28, 31, 39, 66, , 68, 69, 70],
|
|
|
+ // 师生互动工具list
|
|
|
+ TeaStuInt: [7, 1, 52, 3, 48, 15, 16, 50, 57],
|
|
|
+ // 处理过的分组
|
|
|
+ TeaStuInt2: [1, 3, 5, 4, 10, 13, 15],
|
|
|
+
|
|
|
+ subject:[],
|
|
|
+
|
|
|
+ data3: [],
|
|
|
+ data4: [],
|
|
|
+ data5: [],
|
|
|
+ data6: [],
|
|
|
+ data7: [],
|
|
|
+ data8: [],
|
|
|
+ data9: [],
|
|
|
+ oid: this.$route.query.oid,
|
|
|
+ org: this.$route.query.org,
|
|
|
+ uid2: "",
|
|
|
+ worksDialogCon2: "",
|
|
|
+
|
|
|
+ loading: false,
|
|
|
+ userInfo: "",
|
|
|
+ tableData: [],
|
|
|
+ courseName: "",
|
|
|
+ imgList: [
|
|
|
+ {
|
|
|
+ schoolId: "45facc0a-1211-11ec-80ad-005056b86db5",
|
|
|
+ logo: require("../../../assets/icon/exportPdfworks/cocoroboLogo.svg"),
|
|
|
+ conImg: require("../../../assets/icon/exportPdfworks/cocoroboCon.svg"),
|
|
|
+ bjLogo: require("../../../assets/icon/exportPdfworks/logo2.svg"),
|
|
|
+ bkColor: "#E5EFFE"
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ schoolImg: {}
|
|
|
+ };
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ if (this.digNum == 0) {
|
|
|
+ this.downPdf();
|
|
|
+ } else {
|
|
|
+ this.getWorks1();
|
|
|
+ }
|
|
|
+ // this.getCourseDetail();
|
|
|
+ },
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ // 下载单个文件
|
|
|
+ async downPdf() {
|
|
|
+ this.loading = true;
|
|
|
+ this.tableData = this.multipleSelection;
|
|
|
+ if (!this.tableData.length) {
|
|
|
+ this.loading = false;
|
|
|
+ return this.$message.info("请选择数据后,再进行导出");
|
|
|
+ }
|
|
|
+ if (this.tableData.length == 1) {
|
|
|
+ this.uid2 = this.tableData[0].userid;
|
|
|
+ this.worksDialogCon2 = this.tableData[0];
|
|
|
+ await this.getData();
|
|
|
+ await this.getPdf();
|
|
|
+ } else {
|
|
|
+ this.circulatePdf();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 下载pdf文件
|
|
|
+ async getPdf() {
|
|
|
+ let domHeight = this.$refs.reportPdf.offsetHeight;
|
|
|
+ // console.log('this.$refs.reportPdf',this.$refs.reportPdf.offsetHeight);
|
|
|
+ let maxHeight = 64257;
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ html2canvas(this.$refs.reportPdf, {
|
|
|
+ useCORS: true, // 如果截图的内容里有图片,可能会有跨域的情况,加上这个参数,解决文件跨域问题
|
|
|
+ scale: maxHeight / domHeight > 1 ? 1 : maxHeight / domHeight
|
|
|
+ })
|
|
|
+ .then(canvas => {
|
|
|
+ const contentWidth = canvas.width;
|
|
|
+ const contentHeight = canvas.height;
|
|
|
+
|
|
|
+ var pageData = canvas.toDataURL("image/jpeg", 1.0);
|
|
|
+
|
|
|
+ var pdf = new jspdf("", "pt", [contentWidth, contentHeight]);
|
|
|
+
|
|
|
+ //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
|
|
|
+ //当内容未超过pdf一页显示的范围,无需分页
|
|
|
+ // if (leftHeight < pageHeight) {
|
|
|
+ pdf.addImage(pageData, "JPEG", 0, 0, contentWidth, contentHeight);
|
|
|
+
|
|
|
+ pdf.save(
|
|
|
+ this.worksDialogCon2.course +
|
|
|
+ "-作业集-" +
|
|
|
+ this.worksDialogCon2.sName +
|
|
|
+ ".pdf"
|
|
|
+ );
|
|
|
+ return resolve();
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ console.log(err);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 获取所有作业然后一键打包压缩包
|
|
|
+ getWorks1() {
|
|
|
+ this.loading = true;
|
|
|
+
|
|
|
+ let params = {
|
|
|
+ cid: this.cid,
|
|
|
+ uname: "",
|
|
|
+ choseClass: "",
|
|
|
+ stage: "",
|
|
|
+ task: ""
|
|
|
+ };
|
|
|
+
|
|
|
+ this.ajax
|
|
|
+ .get(this.$store.state.api + "getCourseWorks6", params) //getCourseWorks4
|
|
|
+ .then(res => {
|
|
|
+ this.tableData = res.data[0];
|
|
|
+
|
|
|
+ if (!this.tableData.length) {
|
|
|
+ this.loading = false;
|
|
|
+ return this.$message.info("课程下未有提交作业");
|
|
|
+ }
|
|
|
+ this.courseName = this.tableData[0].course;
|
|
|
+ this.circulatePdf();
|
|
|
+ // console.log(res.data[0]);
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ this.isLoading = false;
|
|
|
+ console.error(err);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 一键打包所有作业
|
|
|
+ async circulatePdf() {
|
|
|
+ let _this = this;
|
|
|
+ var zip = new JSZip();
|
|
|
+ let pdfList = [];
|
|
|
+ for (let i = 0; i < this.tableData.length; i++) {
|
|
|
+ this.loading = true;
|
|
|
+
|
|
|
+ this.toolRatio = [
|
|
|
+ { name: "互动类", value: 0 },
|
|
|
+ { name: "思维类", value: 0 },
|
|
|
+ { name: "协作类", value: 0 },
|
|
|
+ { name: "测评类", value: 0 },
|
|
|
+ { name: "评价类", value: 0 },
|
|
|
+ { name: "编程类", value: 0 },
|
|
|
+ { name: "学科类", value: 0 }
|
|
|
+ ];
|
|
|
+ this.uid2 = this.tableData[i].userid;
|
|
|
+ this.worksDialogCon2 = this.tableData[i];
|
|
|
+ await this.getData();
|
|
|
+ let a = await this.getPdf2();
|
|
|
+ pdfList.push(a);
|
|
|
+ }
|
|
|
+
|
|
|
+ pdfList.forEach((e, index) => {
|
|
|
+ zip.file(e.pdfName, e.pdfCon);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成压缩包并提供下载链接
|
|
|
+ zip.generateAsync({ type: "blob" }).then(function(content) {
|
|
|
+ // 使用FileSaver保存压缩包
|
|
|
+ saveAs(content, _this.courseTit + "-学生报告汇总.zip");
|
|
|
+ });
|
|
|
+
|
|
|
+ this.$emit("update:worksDialog", false);
|
|
|
+ // this.worksDialog = false;
|
|
|
+ },
|
|
|
+ // 压缩pdf
|
|
|
+ async getPdf2() {
|
|
|
+ let domHeight = this.$refs.reportPdf.offsetHeight;
|
|
|
+ // console.log('this.$refs.reportPdf',this.$refs.reportPdf.offsetHeight);
|
|
|
+ let maxHeight = 64257;
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ html2canvas(this.$refs.reportPdf, {
|
|
|
+ useCORS: true, // 如果截图的内容里有图片,可能会有跨域的情况,加上这个参数,解决文件跨域问题
|
|
|
+ scale: maxHeight / domHeight > 1 ? 1 : maxHeight / domHeight
|
|
|
+ })
|
|
|
+ .then(canvas => {
|
|
|
+ const contentWidth = canvas.width;
|
|
|
+ const contentHeight = canvas.height;
|
|
|
+
|
|
|
+ var pageData = canvas.toDataURL("image/jpeg", 1.0);
|
|
|
+
|
|
|
+ var pdf = new jspdf("", "pt", [contentWidth, contentHeight]);
|
|
|
+
|
|
|
+ //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
|
|
|
+ //当内容未超过pdf一页显示的范围,无需分页
|
|
|
+ // if (leftHeight < pageHeight) {
|
|
|
+ pdf.addImage(pageData, "JPEG", 0, 0, contentWidth, contentHeight);
|
|
|
+
|
|
|
+ var pdfData = {
|
|
|
+ pdfName:
|
|
|
+ this.worksDialogCon2.course +
|
|
|
+ "-作业集-" +
|
|
|
+ this.worksDialogCon2.sName +
|
|
|
+ ".pdf",
|
|
|
+ pdfCon: pdf.output("blob")
|
|
|
+ };
|
|
|
+ // pdfArray.push(pdfData);
|
|
|
+
|
|
|
+ return resolve(pdfData);
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ console.log(err);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ async getData() {
|
|
|
+ this.subject=[]
|
|
|
+ let params = {
|
|
|
+ cid: this.cid,
|
|
|
+ uid: this.worksDialogCon2.userid,
|
|
|
+ cla: ""
|
|
|
+ };
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ this.ajax
|
|
|
+ .get(this.$store.state.api + "selectStuCourseReportPdf", params) //getCourseWorksReport
|
|
|
+ .then(res => {
|
|
|
+ this.cState = res.data[0][0].state;
|
|
|
+ this.courseTit = res.data[0][0].title;
|
|
|
+
|
|
|
+ let sub = res.data[9][0].subject
|
|
|
+ this.subject = sub.split(',')
|
|
|
+
|
|
|
+ this.imgList.forEach(e => {
|
|
|
+ if (e.schoolId == this.oid) {
|
|
|
+ this.schoolImg = e;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 0 课程信息
|
|
|
+ // 1获取登录时长
|
|
|
+ // 3获取学习时长
|
|
|
+ // 4获取学生提交作业
|
|
|
+ // 5获取单个学生作业分数
|
|
|
+ // 6获取教师评价作业
|
|
|
+ // 7获取所有学生提交作业
|
|
|
+ // 8学生点赞评论次数
|
|
|
+ // 9学生被点赞评论次数
|
|
|
+ let oneTime = 0;
|
|
|
+ res.data[1].forEach(e => {
|
|
|
+ oneTime += e.text * 1;
|
|
|
+ });
|
|
|
+ this.loginTime = this.secondsToDhms(oneTime);
|
|
|
+
|
|
|
+ let twoTime = 0;
|
|
|
+ res.data[2].forEach(e => {
|
|
|
+ twoTime += e.text * 1;
|
|
|
+ });
|
|
|
+ this.studyTime = this.secondsToDhms(twoTime);
|
|
|
+
|
|
|
+ this.data3 = res.data[3];
|
|
|
+ this.data4 = res.data[4];
|
|
|
+ this.data5 = res.data[5];
|
|
|
+ this.data6 = res.data[6];
|
|
|
+ this.data7 = res.data[7];
|
|
|
+ this.data8 = res.data[8];
|
|
|
+ this.data9 = res.data[9];
|
|
|
+
|
|
|
+ // 处理这个课程下的工具分类
|
|
|
+ let data = JSON.parse(res.data[0][0].chapters);
|
|
|
+
|
|
|
+
|
|
|
+ if (this.cState == 1) {
|
|
|
+ this.getDataStageMode(data);
|
|
|
+ } else {
|
|
|
+ this.getDataAiMode(data);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 将课程的所有工具进行分类,然后装在变量里 , 获取所有折线图阶段
|
|
|
+ // console.log("data", data);
|
|
|
+ this.loading = false;
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ return resolve();
|
|
|
+ }, 1500);
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ console.error(err);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // ai模式处理数据
|
|
|
+ getDataAiMode(data) {
|
|
|
+ this.toolData = [[], [], [], [], [], [], []];
|
|
|
+ this.taskList = []; //每个阶段下有几个任务
|
|
|
+ this.toolPercentage = [];
|
|
|
+ this.interact = [];
|
|
|
+ this.interactWork = [];
|
|
|
+ this.stuInterAllWork = [];
|
|
|
+ this.stuInterAllLike = [];
|
|
|
+ this.bdStuInterAllWork = [];
|
|
|
+ this.bdStuInterAllLike = [];
|
|
|
+ this.stageList = [];
|
|
|
+ this.stageListPer = [];
|
|
|
+ data.forEach((e, eInd) => {
|
|
|
+ let toolList = e.chapterInfo[0].taskJson;
|
|
|
+ toolList.forEach((i, iInd) => {
|
|
|
+ this.stageList.push("任务" + (iInd * 1 + 1));
|
|
|
+ this.toolPercentage[iInd] = []; // 每个任务有的工具
|
|
|
+ this.stageListPer.push(0); // 作业提交率基础数据折线图
|
|
|
+ // 课程阶段下互动数据工具
|
|
|
+ this.interact[iInd] = [];
|
|
|
+
|
|
|
+ this.interactWork[iInd] = []; //每个工具下提交的作业
|
|
|
+
|
|
|
+ this.stuInterAllWork[iInd] = []; // 生生互动阶段作业分类
|
|
|
+ this.stuInterAllLike[iInd] = []; // 生生互动阶段点赞评论分类
|
|
|
+
|
|
|
+ this.bdStuInterAllWork[iInd] = []; // 生生互动阶段被动作业分类
|
|
|
+ this.bdStuInterAllLike[iInd] = []; // 生生互动阶段被动点赞评论分类
|
|
|
+
|
|
|
+ i.toolChoose.forEach(k => {
|
|
|
+ if (k.tool[0]) {
|
|
|
+ this.toolPercentage[iInd].push(k.tool[0]);
|
|
|
+ if (this.TeaStuInt.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.interact[iInd].push(k.tool[0]);
|
|
|
+ }
|
|
|
+ if (this.hd.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[0].push(k);
|
|
|
+ }
|
|
|
+ if (this.sw.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[1].push(k);
|
|
|
+ }
|
|
|
+ if (this.xz.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[2].push(k);
|
|
|
+ }
|
|
|
+ if (this.cp.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[3].push(k);
|
|
|
+ }
|
|
|
+ if (this.pj.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[4].push(k);
|
|
|
+ }
|
|
|
+ if (this.bc.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[5].push(k);
|
|
|
+ }
|
|
|
+ if (this.xk.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[6].push(k);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ // console.log("this.toolData", this.toolData);
|
|
|
+
|
|
|
+ // 环形图占比
|
|
|
+ this.toolRatio[0].value = this.toolData[0].length;
|
|
|
+ this.toolRatio[1].value = this.toolData[1].length;
|
|
|
+ this.toolRatio[2].value = this.toolData[2].length;
|
|
|
+ this.toolRatio[3].value = this.toolData[3].length;
|
|
|
+ this.toolRatio[4].value = this.toolData[4].length;
|
|
|
+ this.toolRatio[5].value = this.toolData[5].length;
|
|
|
+ this.toolRatio[6].value = this.toolData[6].length;
|
|
|
+ this.toolRatio = this.toolRatio.filter(e => {
|
|
|
+ return e.value != 0;
|
|
|
+ });
|
|
|
+ // console.log("this.toolRatio[0]", this.toolRatio);
|
|
|
+ // 作业提交率折线图
|
|
|
+ let repeatWork = this.newArrFn(this.data3);
|
|
|
+ // console.log("repeatWork", repeatWork);
|
|
|
+
|
|
|
+ this.getFoldLineDataAi(repeatWork);
|
|
|
+
|
|
|
+ // 计算任务得分
|
|
|
+ this.getFoldLineSCoDataAi(this.data4);
|
|
|
+
|
|
|
+ // 计算分组工具使用比例
|
|
|
+ this.getColumnData();
|
|
|
+
|
|
|
+ // 师生互动数据
|
|
|
+ let TeaStuHdData = [];
|
|
|
+ repeatWork.forEach(e => {
|
|
|
+ if (this.TeaStuInt2.indexOf(e.type) != -1) {
|
|
|
+ TeaStuHdData.push(e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.getTeaStuHdAi(TeaStuHdData);
|
|
|
+
|
|
|
+ // 生生互动主动
|
|
|
+ this.getStuInterAllWorkAi(this.data6, this.data7);
|
|
|
+
|
|
|
+ // // 生生互动被动
|
|
|
+ this.getBdStuInterAllWorkAi(this.data6, this.data8);
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ this.renderChart();
|
|
|
+ this.renderChart2();
|
|
|
+ this.initChart();
|
|
|
+ this.initChart2();
|
|
|
+ this.initChart3();
|
|
|
+ this.initChart4();
|
|
|
+ this.initChart5();
|
|
|
+ this.initChart6();
|
|
|
+ }, 500);
|
|
|
+ },
|
|
|
+ // 阶段模式处理数据
|
|
|
+ getDataStageMode(data) {
|
|
|
+ this.toolData = [[], [], [], [], [], [], []];
|
|
|
+ this.taskList = []; //每个阶段下有几个任务
|
|
|
+ this.toolPercentage = [];
|
|
|
+ this.interact = [];
|
|
|
+ this.interactWork = [];
|
|
|
+ this.stuInterAllWork = [];
|
|
|
+ this.stuInterAllLike = [];
|
|
|
+ this.bdStuInterAllWork = [];
|
|
|
+ this.bdStuInterAllLike = [];
|
|
|
+ this.stageList = [];
|
|
|
+ this.stageListPer = [];
|
|
|
+
|
|
|
+ data.forEach((e, eInd) => {
|
|
|
+ let toolList = e.chapterInfo[0].taskJson;
|
|
|
+ this.toolPercentage[eInd] = []; // 每个任务有的工具
|
|
|
+ // X轴数据
|
|
|
+ this.stageList.push("阶段" + (eInd * 1 + 1));
|
|
|
+ // 作业提交率基础数据
|
|
|
+ this.stageListPer.push(0);
|
|
|
+
|
|
|
+ // 课程阶段下互动数据工具
|
|
|
+ this.interact[eInd] = [];
|
|
|
+ //每个工具下提交的作业
|
|
|
+ this.interactWork[eInd] = [];
|
|
|
+
|
|
|
+ this.stuInterAllWork[eInd] = []; // 生生互动阶段作业分类
|
|
|
+ this.stuInterAllLike[eInd] = []; // 生生互动阶段点赞评论分类
|
|
|
+
|
|
|
+ this.bdStuInterAllWork[eInd] = []; // 生生互动阶段被动作业分类
|
|
|
+ this.bdStuInterAllLike[eInd] = []; // 生生互动阶段被动点赞评论分类
|
|
|
+
|
|
|
+ // 每个阶段下有多少个任务
|
|
|
+ console.log("toolList", JSON.parse(JSON.stringify(toolList)));
|
|
|
+
|
|
|
+ this.taskList[eInd] = toolList;
|
|
|
+
|
|
|
+ toolList.forEach(i => {
|
|
|
+ i.toolChoose.forEach(k => {
|
|
|
+ if (k.tool[0]) {
|
|
|
+ this.toolPercentage[eInd].push(k.tool[0]);
|
|
|
+
|
|
|
+ if (this.TeaStuInt.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.interact[eInd].push(k.tool[0]);
|
|
|
+ }
|
|
|
+ if (this.hd.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[0].push(k);
|
|
|
+ }
|
|
|
+ if (this.sw.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[1].push(k);
|
|
|
+ }
|
|
|
+ if (this.xz.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[2].push(k);
|
|
|
+ }
|
|
|
+ if (this.cp.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[3].push(k);
|
|
|
+ }
|
|
|
+ if (this.pj.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[4].push(k);
|
|
|
+ }
|
|
|
+ if (this.bc.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[5].push(k);
|
|
|
+ }
|
|
|
+ if (this.xk.indexOf(k.tool[0]) != -1) {
|
|
|
+ this.toolData[6].push(k);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ // 环形图占比
|
|
|
+ this.toolRatio[0].value = this.toolData[0].length;
|
|
|
+ this.toolRatio[1].value = this.toolData[1].length;
|
|
|
+ this.toolRatio[2].value = this.toolData[2].length;
|
|
|
+ this.toolRatio[3].value = this.toolData[3].length;
|
|
|
+ this.toolRatio[4].value = this.toolData[4].length;
|
|
|
+ this.toolRatio[5].value = this.toolData[5].length;
|
|
|
+ this.toolRatio[6].value = this.toolData[6].length;
|
|
|
+ this.toolRatio = this.toolRatio.filter(e => {
|
|
|
+ return e.value != 0;
|
|
|
+ });
|
|
|
+ // 作业提交率折线图
|
|
|
+ let repeatWork = this.newArrFn(this.data3);
|
|
|
+ this.getFoldLineData(repeatWork);
|
|
|
+
|
|
|
+ // 计算任务得分
|
|
|
+ this.getFoldLineSCoData(this.data4);
|
|
|
+
|
|
|
+ // 计算分组工具使用比例
|
|
|
+ this.getColumnData();
|
|
|
+
|
|
|
+ // 师生互动数据
|
|
|
+ let TeaStuHdData = [];
|
|
|
+ repeatWork.forEach(e => {
|
|
|
+ if (this.TeaStuInt2.indexOf(e.type) != -1) {
|
|
|
+ TeaStuHdData.push(e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.getTeaStuHd(TeaStuHdData);
|
|
|
+
|
|
|
+ // 生生互动主动
|
|
|
+ this.getStuInterAllWork(this.data6, this.data7);
|
|
|
+
|
|
|
+ // 生生互动被动
|
|
|
+ this.getBdStuInterAllWork(this.data6, this.data8);
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ this.renderChart();
|
|
|
+ this.renderChart2();
|
|
|
+ this.initChart();
|
|
|
+ this.initChart2();
|
|
|
+ this.initChart3();
|
|
|
+ this.initChart4();
|
|
|
+ this.initChart5();
|
|
|
+ this.initChart6();
|
|
|
+ }, 500);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 生生互动被动
|
|
|
+ getBdStuInterAllWork(val, likeData) {
|
|
|
+ this.bdStuInterAllWork.forEach((e, index) => {
|
|
|
+ val.forEach(k => {
|
|
|
+ if (k.stage == index) {
|
|
|
+ e.push(k.id);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ this.bdStuInterAllWork.forEach((e, index) => {
|
|
|
+ likeData.forEach(k => {
|
|
|
+ if (e.indexOf(k.workId) != -1) {
|
|
|
+ this.bdStuInterAllLike[index].push(k);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 生生互动主动
|
|
|
+ getStuInterAllWork(val, likeData) {
|
|
|
+ this.stuInterAllWork.forEach((e, index) => {
|
|
|
+ val.forEach(k => {
|
|
|
+ if (k.stage == index) {
|
|
|
+ e.push(k.id);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ this.stuInterAllWork.forEach((e, index) => {
|
|
|
+ likeData.forEach(k => {
|
|
|
+ if (e.indexOf(k.workId) != -1) {
|
|
|
+ this.stuInterAllLike[index].push(k);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 师生互动数据
|
|
|
+ getTeaStuHd(TeaStuHdData) {
|
|
|
+ this.interactWork.forEach((e, index) => {
|
|
|
+ TeaStuHdData.forEach(k => {
|
|
|
+ if (k.stage == index) {
|
|
|
+ e.push(k);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 计算任务得分
|
|
|
+ getFoldLineSCoData(repeatWork) {
|
|
|
+ // 作业数据e.sco得分
|
|
|
+ repeatWork.forEach(e => {
|
|
|
+ let con = Object.values(JSON.parse(e.rate));
|
|
|
+ e.sco = 0;
|
|
|
+ con.forEach(i => {
|
|
|
+ if (!isNaN(Number(i))) {
|
|
|
+ e.sco += i * 1;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (e.sco == 0 || con.length == 0) {
|
|
|
+ e.sco = 0;
|
|
|
+ } else {
|
|
|
+ e.sco = (e.sco / (con.length - 1)).toFixed(1);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ let repeatWorkCopy = []; // 阶段分类作业容器
|
|
|
+ let scoList = []; //分数每个阶段的所有任务分的集合
|
|
|
+
|
|
|
+ this.stageList.forEach((e, index) => {
|
|
|
+ repeatWorkCopy[index] = [];
|
|
|
+ scoList[index] = 0;
|
|
|
+ });
|
|
|
+
|
|
|
+ // 将作业进行阶段分类
|
|
|
+ repeatWork.forEach(e => {
|
|
|
+ repeatWorkCopy[e.stage].push(e);
|
|
|
+ });
|
|
|
+
|
|
|
+ repeatWorkCopy.forEach((e, index) => {
|
|
|
+ e.forEach(k => {
|
|
|
+ scoList[index] += k.sco * 1;
|
|
|
+ });
|
|
|
+ scoList[index] = (scoList[index] / this.taskList[index].length).toFixed(
|
|
|
+ 1
|
|
|
+ );
|
|
|
+ });
|
|
|
+ this.scoFoldLineData = scoList;
|
|
|
+
|
|
|
+ let zSco = 0;
|
|
|
+ this.scoFoldLineData.forEach(e => {
|
|
|
+ zSco += e * 1;
|
|
|
+ });
|
|
|
+
|
|
|
+ this.star = (zSco / this.scoFoldLineData.length).toFixed(1) * 1;
|
|
|
+ },
|
|
|
+
|
|
|
+ getFoldLineData(repeatWork) {
|
|
|
+ // 阶段分类作业容器
|
|
|
+ let repeatWorkCopy = [];
|
|
|
+ this.stageList.forEach((e, index) => {
|
|
|
+ repeatWorkCopy[index] = [];
|
|
|
+ });
|
|
|
+
|
|
|
+ // 将作业进行阶段分类
|
|
|
+ repeatWork.forEach(e => {
|
|
|
+ repeatWorkCopy[e.stage].push(e);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 计算阶段工具作业提交率
|
|
|
+ this.toolPercentage.forEach((e, index) => {
|
|
|
+ repeatWorkCopy.forEach((k, kin) => {
|
|
|
+ if (index == kin) {
|
|
|
+ if (k.length == 0 || e.length == 0) {
|
|
|
+ this.stageListPer[index] = 0;
|
|
|
+ } else {
|
|
|
+ this.stageListPer[index] = (k.length / e.length).toFixed(2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 非阶段模式
|
|
|
+ // 获取作业提交率折线图
|
|
|
+ getFoldLineDataAi(repeatWork) {
|
|
|
+ // 阶段分类作业容器
|
|
|
+ let repeatWorkCopy = [];
|
|
|
+ this.stageList.forEach((e, index) => {
|
|
|
+ repeatWorkCopy[index] = [];
|
|
|
+ });
|
|
|
+
|
|
|
+ // 将作业进行阶段分类
|
|
|
+ repeatWork.forEach(e => {
|
|
|
+ repeatWorkCopy[e.task].push(e);
|
|
|
+ });
|
|
|
+ // console.log("repeatWorkCopy", repeatWorkCopy);
|
|
|
+
|
|
|
+ // 计算阶段工具作业提交率
|
|
|
+ this.toolPercentage.forEach((e, index) => {
|
|
|
+ repeatWorkCopy.forEach((k, kin) => {
|
|
|
+ if (index == kin) {
|
|
|
+ if (k.length == 0 || e.length == 0) {
|
|
|
+ this.stageListPer[index] = 0;
|
|
|
+ } else {
|
|
|
+ this.stageListPer[index] = (k.length / e.length).toFixed(2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 计算任务得分
|
|
|
+ getFoldLineSCoDataAi(repeatWork) {
|
|
|
+ // 作业数据e.sco得分
|
|
|
+ repeatWork.forEach(e => {
|
|
|
+ let con = Object.values(JSON.parse(e.rate));
|
|
|
+ e.sco = 0;
|
|
|
+ con.forEach(i => {
|
|
|
+ if (!isNaN(Number(i))) {
|
|
|
+ e.sco += i * 1;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (e.sco == 0 || con.length == 0) {
|
|
|
+ e.sco = 0;
|
|
|
+ } else {
|
|
|
+ e.sco = (e.sco / (con.length - 1)).toFixed(1);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ let repeatWorkCopy = []; // 任务分类作业容器
|
|
|
+ let scoList = []; //分数每个任务的所有任务分的集合
|
|
|
+
|
|
|
+ this.stageList.forEach((e, index) => {
|
|
|
+ repeatWorkCopy[index] = [];
|
|
|
+ scoList[index] = 0;
|
|
|
+ });
|
|
|
+
|
|
|
+ // 将作业进行阶段分类
|
|
|
+ repeatWork.forEach(e => {
|
|
|
+ repeatWorkCopy[e.task].push(e);
|
|
|
+ });
|
|
|
+
|
|
|
+ repeatWorkCopy.forEach((e, index) => {
|
|
|
+ e.forEach(k => {
|
|
|
+ scoList[index] += k.sco * 1;
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ this.scoFoldLineData = scoList;
|
|
|
+
|
|
|
+ let zSco = 0;
|
|
|
+ this.scoFoldLineData.forEach(e => {
|
|
|
+ zSco += e * 1;
|
|
|
+ });
|
|
|
+
|
|
|
+ this.star = (zSco / this.scoFoldLineData.length).toFixed(1) * 1;
|
|
|
+ },
|
|
|
+ // 师生互动数据
|
|
|
+ getTeaStuHdAi(TeaStuHdData) {
|
|
|
+ this.interactWork.forEach((e, index) => {
|
|
|
+ TeaStuHdData.forEach(k => {
|
|
|
+ if (k.task == index) {
|
|
|
+ e.push(k);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 生生互动主动
|
|
|
+ getStuInterAllWorkAi(val, likeData) {
|
|
|
+ this.stuInterAllWork.forEach((e, index) => {
|
|
|
+ val.forEach(k => {
|
|
|
+ if (k.task == index) {
|
|
|
+ e.push(k.id);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ this.stuInterAllWork.forEach((e, index) => {
|
|
|
+ likeData.forEach(k => {
|
|
|
+ if (e.indexOf(k.workId) != -1) {
|
|
|
+ this.stuInterAllLike[index].push(k);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 生生互动被动
|
|
|
+ getBdStuInterAllWorkAi(val, likeData) {
|
|
|
+ this.bdStuInterAllWork.forEach((e, index) => {
|
|
|
+ val.forEach(k => {
|
|
|
+ if (k.task == index) {
|
|
|
+ e.push(k.id);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ this.bdStuInterAllWork.forEach((e, index) => {
|
|
|
+ likeData.forEach(k => {
|
|
|
+ if (e.indexOf(k.workId) != -1) {
|
|
|
+ this.bdStuInterAllLike[index].push(k);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 通用方法
|
|
|
+ // 五边形
|
|
|
+ renderChart() {
|
|
|
+ let chartObj = echarts.init(this.$refs.chart);
|
|
|
+ const seriesData = this.chartData.map((values, index) => ({
|
|
|
+ value: values
|
|
|
+ }));
|
|
|
+
|
|
|
+ const option = {
|
|
|
+ title: {
|
|
|
+ text: "素养发展雷达图",
|
|
|
+ // subtext: '这是一个副标题',
|
|
|
+ top: "bottom", // 标题在底部显示
|
|
|
+ left: "center" // 标题居中显示
|
|
|
+ },
|
|
|
+ tooltip: {},
|
|
|
+ legend: {
|
|
|
+ // data: this.bLeg.map((series) => series.name),
|
|
|
+ bottom: 0
|
|
|
+ },
|
|
|
+ radar: {
|
|
|
+ indicator: this.categories.map(category => ({
|
|
|
+ name: category,
|
|
|
+ max: 5
|
|
|
+ }))
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ type: "radar",
|
|
|
+ data: seriesData
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ chartObj.setOption(option);
|
|
|
+ },
|
|
|
+ // 环形
|
|
|
+ renderChart2() {
|
|
|
+ let chartObj2 = echarts.init(this.$refs.ringChart);
|
|
|
+
|
|
|
+ const option = {
|
|
|
+ title: {
|
|
|
+ text: "工具使用情况",
|
|
|
+ // subtext: '这是一个副标题',
|
|
|
+ top: "bottom", // 标题在底部显示
|
|
|
+ left: "center" // 标题居中显示
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ trigger: "item",
|
|
|
+ formatter: "{a} <br/>{b}: {c} ({d}%)"
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ orient: "vertical",
|
|
|
+ right: 0,
|
|
|
+ itemWidth: 10, // 控制图例项的宽度
|
|
|
+ itemHeight: 10, // 控制图例项的高度
|
|
|
+ data: this.toolRatio.map(item => item.name)
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: "工具占比",
|
|
|
+ type: "pie",
|
|
|
+ radius: ["30%", "70%"],
|
|
|
+ avoidLabelOverlap: false,
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ position: "inside",
|
|
|
+ formatter: " {d}%"
|
|
|
+ },
|
|
|
+ emphasis: {
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ fontSize: "20"
|
|
|
+ // fontWeight: 'bold'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ labelLine: {
|
|
|
+ show: false
|
|
|
+ },
|
|
|
+ center: ["40%", "50%"], // 控制饼图的位置
|
|
|
+
|
|
|
+ data: this.toolRatio
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ chartObj2.setOption(option);
|
|
|
+ },
|
|
|
+ // 工具提交折线图
|
|
|
+ initChart() {
|
|
|
+ const chart = echarts.init(this.$refs.toolSubEcharts);
|
|
|
+
|
|
|
+ const option = {
|
|
|
+ title: {
|
|
|
+ text: "作业提交率",
|
|
|
+ left: "left",
|
|
|
+ textStyle: {
|
|
|
+ color: "rgba(140, 140, 140, 1)", // 标题颜色
|
|
|
+ fontSize: 10 // 标题字体大小
|
|
|
+ }
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ trigger: "axis",
|
|
|
+ formatter: "{b} : {c}%"
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: "category",
|
|
|
+ data: this.stageList.map(item => item),
|
|
|
+ axisTick: {
|
|
|
+ alignWithLabel: true // 使刻度线和标签对齐
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: "value",
|
|
|
+ axisLabel: {
|
|
|
+ formatter: "{value}%"
|
|
|
+ },
|
|
|
+ max: 100
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ data: this.stageListPer.map(item => item * 100),
|
|
|
+ type: "line"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ chart.setOption(option);
|
|
|
+ },
|
|
|
+ // 课程得分
|
|
|
+ initChart2() {
|
|
|
+ const chart = echarts.init(this.$refs.cScoEcharts);
|
|
|
+ const option = {
|
|
|
+ title: {
|
|
|
+ text: this.cState == 1 ? "阶段成绩" : "任务成绩",
|
|
|
+ left: "left",
|
|
|
+ textStyle: {
|
|
|
+ color: "rgba(140, 140, 140, 1)", // 标题颜色
|
|
|
+ fontSize: 10 // 标题字体大小
|
|
|
+ }
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ trigger: "axis",
|
|
|
+ formatter: "{b} : {c}"
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: "category",
|
|
|
+ data: this.stageList.map(item => item),
|
|
|
+ axisTick: {
|
|
|
+ alignWithLabel: true // 使刻度线和标签对齐
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: "value",
|
|
|
+ axisLabel: {
|
|
|
+ formatter: "{value}"
|
|
|
+ },
|
|
|
+ max: 5
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ data: this.scoFoldLineData.map(item => item),
|
|
|
+ type: "line"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ chart.setOption(option);
|
|
|
+ },
|
|
|
+ // 分组工具占比
|
|
|
+ initChart3() {
|
|
|
+ const chart = echarts.init(this.$refs.groupingEcharts);
|
|
|
+
|
|
|
+ const option = {
|
|
|
+ title: {
|
|
|
+ text: "分组工具占比",
|
|
|
+ left: "left",
|
|
|
+ textStyle: {
|
|
|
+ color: "rgba(140, 140, 140, 1)", // 标题颜色
|
|
|
+ fontSize: 10 // 标题字体大小
|
|
|
+ }
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ trigger: "axis",
|
|
|
+ axisPointer: {
|
|
|
+ type: "shadow"
|
|
|
+ },
|
|
|
+ formatter: "{b} : {c}%"
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: "category",
|
|
|
+ data: this.stageList.map(item => item)
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: "value",
|
|
|
+ axisLabel: {
|
|
|
+ formatter: "{value}%"
|
|
|
+ },
|
|
|
+ max: 100
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ data: this.columnData.map(item => item * 100),
|
|
|
+ type: "bar"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ chart.setOption(option);
|
|
|
+ },
|
|
|
+ // 师生互动折线图
|
|
|
+ initChart4() {
|
|
|
+ const chart = echarts.init(this.$refs.interactionEcharts);
|
|
|
+
|
|
|
+ const option = {
|
|
|
+ title: {
|
|
|
+ text: "师生互动",
|
|
|
+ left: "left",
|
|
|
+ textStyle: {
|
|
|
+ color: "rgba(140, 140, 140, 1)", // 标题颜色
|
|
|
+ fontSize: 10 // 标题字体大小
|
|
|
+ }
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ trigger: "axis",
|
|
|
+ formatter: "{b} : {c}"
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: "category",
|
|
|
+ data: this.stageList.map(item => item),
|
|
|
+ axisTick: {
|
|
|
+ alignWithLabel: true // 使刻度线和标签对齐
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: "value",
|
|
|
+ axisLabel: {
|
|
|
+ formatter: "{value}"
|
|
|
+ }
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ data: this.interactWork.map(item => item.length),
|
|
|
+ type: "line"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ chart.setOption(option);
|
|
|
+ },
|
|
|
+ // 学生互动主动折线图
|
|
|
+ initChart5() {
|
|
|
+ const chart = echarts.init(this.$refs.stuInteractZdEcharts);
|
|
|
+
|
|
|
+ const option = {
|
|
|
+ title: {
|
|
|
+ text: "生生互动(主动)",
|
|
|
+ left: "left",
|
|
|
+ textStyle: {
|
|
|
+ color: "rgba(140, 140, 140, 1)", // 标题颜色
|
|
|
+ fontSize: 10 // 标题字体大小
|
|
|
+ }
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ trigger: "axis",
|
|
|
+ formatter: "{b} : {c}"
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: "category",
|
|
|
+ data: this.stageList.map(item => item),
|
|
|
+ axisTick: {
|
|
|
+ alignWithLabel: true // 使刻度线和标签对齐
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: "value",
|
|
|
+ axisLabel: {
|
|
|
+ formatter: "{value}"
|
|
|
+ }
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ data: this.stuInterAllLike.map(item => item.length),
|
|
|
+ type: "line"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ chart.setOption(option);
|
|
|
+ },
|
|
|
+ // 学生互动被动折线图
|
|
|
+ initChart6() {
|
|
|
+ const chart = echarts.init(this.$refs.bdStuInteractZdEcharts);
|
|
|
+
|
|
|
+ const option = {
|
|
|
+ title: {
|
|
|
+ text: "生生互动(被动)",
|
|
|
+ left: "left",
|
|
|
+ textStyle: {
|
|
|
+ color: "rgba(140, 140, 140, 1)", // 标题颜色
|
|
|
+ fontSize: 10 // 标题字体大小
|
|
|
+ }
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ trigger: "axis",
|
|
|
+ formatter: "{b} : {c}"
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: "category",
|
|
|
+ data: this.stageList.map(item => item),
|
|
|
+ axisTick: {
|
|
|
+ alignWithLabel: true // 使刻度线和标签对齐
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: "value",
|
|
|
+ axisLabel: {
|
|
|
+ formatter: "{value}"
|
|
|
+ }
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ data: this.bdStuInterAllLike.map(item => item.length),
|
|
|
+ type: "line"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ chart.setOption(option);
|
|
|
+ },
|
|
|
+ // 计算分组工具使用比例
|
|
|
+ getColumnData() {
|
|
|
+ let columnDataCopy = [];
|
|
|
+
|
|
|
+ this.toolPercentage.forEach((e, index) => {
|
|
|
+ columnDataCopy[index] = 0;
|
|
|
+ columnDataCopy[index] = e.filter(item => item === 49).length;
|
|
|
+ if (columnDataCopy[index]) {
|
|
|
+ this.columnData[index] = (columnDataCopy[index] / e.length).toFixed(
|
|
|
+ 2
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ this.columnData[index] = 0;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 计算时长
|
|
|
+ secondsToDhms(seconds) {
|
|
|
+ const days = Math.floor(seconds / (3600 * 24));
|
|
|
+ const hours = Math.floor((seconds % (3600 * 24)) / 3600);
|
|
|
+
|
|
|
+ return days + " 天 " + hours + " 时";
|
|
|
+ },
|
|
|
+ // 判断一个工具下是否提交多个作,有重复的只取一个
|
|
|
+ newArrFn(arr) {
|
|
|
+ // 创建一个新的空数组
|
|
|
+ let newArr = [];
|
|
|
+ for (let i = 0; i < arr.length; i++) {
|
|
|
+ // 设置一个开关,如果是true,就存进去,不是就不存
|
|
|
+ let flag = true;
|
|
|
+ for (let j = 0; j < newArr.length; j++) {
|
|
|
+ // 原数组和新数组作比较,如果一致,开关变为 false
|
|
|
+ if (
|
|
|
+ arr[i].stage == newArr[j].stage &&
|
|
|
+ arr[i].task == newArr[j].task &&
|
|
|
+ arr[i].tool == newArr[j].tool
|
|
|
+ ) {
|
|
|
+ flag = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ flag ? newArr.push(arr[i]) : newArr;
|
|
|
+ }
|
|
|
+ return newArr;
|
|
|
+ },
|
|
|
+ handleClose(done) {
|
|
|
+ done();
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.pbl {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ box-sizing: border-box;
|
|
|
+ margin: auto;
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
+ padding: 20px;
|
|
|
+ padding-top: 10px;
|
|
|
+ overflow: auto;
|
|
|
+ border-radius: 10px;
|
|
|
+}
|
|
|
+.pageTit {
|
|
|
+ width: 100%;
|
|
|
+ text-align: left;
|
|
|
+ font-size: 28px;
|
|
|
+ padding: 10px 0;
|
|
|
+ font-weight: bold;
|
|
|
+ border-bottom: 1px solid #ccc;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+.full_diy {
|
|
|
+ min-width: 1200px !important;
|
|
|
+}
|
|
|
+.full_diy >>> .el-dialog {
|
|
|
+ height: 80%;
|
|
|
+ width: 598px !important;
|
|
|
+ margin-top: 10vh !important;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+.full_diy >>> .el-dialog__body {
|
|
|
+ overflow: auto;
|
|
|
+ flex: 1;
|
|
|
+ padding: 0 !important;
|
|
|
+}
|
|
|
+.full_diy >>> .el-dialog__title {
|
|
|
+ color: #fff !important;
|
|
|
+}
|
|
|
+.full_diy >>> .el-dialog__header {
|
|
|
+ padding: 9px 20px 10px;
|
|
|
+ background: #32455b !important;
|
|
|
+}
|
|
|
+.coverPage {
|
|
|
+ min-height: 743px;
|
|
|
+ background-color: #ccc;
|
|
|
+ position: relative;
|
|
|
+ background-image: url("../../../assets/icon/exportPdfworks/bcg1.svg"),
|
|
|
+ url("../../../assets/icon/exportPdfworks/bcg2.svg");
|
|
|
+ /* 设置每个背景的位置和尺寸,可以使用关键字或者具体的像素值,用逗号分隔 */
|
|
|
+ background-position: top left, bottom;
|
|
|
+ /* background-size: cover, cover; */
|
|
|
+
|
|
|
+ /* 设置每个背景图片的重复方式,用逗号分隔 */
|
|
|
+ background-repeat: no-repeat, no-repeat;
|
|
|
+}
|
|
|
+.coverPageLogo {
|
|
|
+ padding: 40px;
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ box-sizing: border-box;
|
|
|
+ margin-bottom: 30px;
|
|
|
+}
|
|
|
+.coverPageFrom {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ width: 70%;
|
|
|
+ margin: 0 auto;
|
|
|
+}
|
|
|
+.coverPageFromTit {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+.fromCss {
|
|
|
+ border: 1.5px dashed rgba(158, 208, 255, 1);
|
|
|
+ border-radius: 16px;
|
|
|
+ background-color: #fff;
|
|
|
+ padding: 24px 32px;
|
|
|
+ width: 300px;
|
|
|
+ margin: 30px;
|
|
|
+ color: rgba(35, 99, 205, 1);
|
|
|
+}
|
|
|
+.fromCss > div {
|
|
|
+ margin-bottom: 10px;
|
|
|
+ display: flex;
|
|
|
+}
|
|
|
+.fromCss > div > span {
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-right: 5px;
|
|
|
+ font-size: 16px;
|
|
|
+}
|
|
|
+.fromCss > div:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+.txt {
|
|
|
+ width: 100%;
|
|
|
+ border-bottom: 1px solid rgba(192, 210, 229, 1);
|
|
|
+ text-align: center;
|
|
|
+ color: #000;
|
|
|
+}
|
|
|
+.coverPageCon {
|
|
|
+ background-color: #e3edfe;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ padding: 0 20px;
|
|
|
+ padding-bottom: 30px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+.zhBlock {
|
|
|
+ width: 125px;
|
|
|
+ height: 64px;
|
|
|
+ padding: 10px 8px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background-color: rgba(255, 255, 255, 1);
|
|
|
+ border-radius: 8px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+.zhBlockTit {
|
|
|
+ font-size: 10px;
|
|
|
+ font-weight: 400;
|
|
|
+ color: rgba(0, 0, 0, 0.6);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 6px;
|
|
|
+}
|
|
|
+.zhBlockCon {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 14px;
|
|
|
+ color: rgba(0, 0, 0, 0.9);
|
|
|
+ font-weight: 400;
|
|
|
+ background-color: rgba(243, 247, 253, 1);
|
|
|
+ border-radius: 5px;
|
|
|
+}
|
|
|
+.zhBlockCon >>> .el-rate__icon {
|
|
|
+ margin: 0 !important;
|
|
|
+}
|
|
|
+.zhBlockCon2 {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: space-between;
|
|
|
+ /* flex-wrap: wrap; */
|
|
|
+ flex: 1;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.zhBlockCon2 > div {
|
|
|
+
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+.zhBlockCon2 > div >span{
|
|
|
+ font-size: 8px;
|
|
|
+ font-weight: 400;
|
|
|
+ color: rgba(0, 0, 0, 0.9);
|
|
|
+ background-color: rgba(243, 247, 253, 1);
|
|
|
+ border-radius: 2px;
|
|
|
+ padding: 0px 4px;
|
|
|
+ height: 15px;
|
|
|
+ line-height: 15px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ margin-right: 4px;
|
|
|
+ margin-bottom: 2px;
|
|
|
+}
|
|
|
+.zxt {
|
|
|
+ height: 300px;
|
|
|
+ width: 100%;
|
|
|
+ border: 1px solid #ccc;
|
|
|
+ margin: 10px 0;
|
|
|
+ background-color: rgba(255, 255, 255, 1);
|
|
|
+ padding: 10px 0;
|
|
|
+ border-radius: 15px;
|
|
|
+}
|
|
|
+</style>
|