فهرست منبع

知识点作答

liurongli 1 روز پیش
والد
کامیت
8862d85c43
2فایلهای تغییر یافته به همراه426 افزوده شده و 2 حذف شده
  1. 417 0
      src/views/targetImprove/components/ErrorManual.vue
  2. 9 2
      src/views/targetImprove/practice/practiceAnswer.vue

+ 417 - 0
src/views/targetImprove/components/ErrorManual.vue

@@ -0,0 +1,417 @@
+<template>
+  <div :key="dialogKey">
+    <el-dialog title="导出个性化错题手册" class="page_full_dialog" :visible.sync="showDialog" fullscreen height="100%">
+      <div class="dialog_print_content">
+        <div class="page_jg_20"></div>
+        <div class="dialog_print_page">
+          <div class="item_page">内容</div>
+        </div>
+        <div class="fixed_set_box">
+          <div class="item_set">
+            <el-radio-group v-model="radioVal">
+              <el-radio :label="0">答案解析在卷底</el-radio>
+              <el-radio :label="1">答案解析在每题后</el-radio>
+            </el-radio-group>
+          </div>
+          <div class="item_set">
+            <el-checkbox-group v-model="checkVal">
+              <el-checkbox label="0">我的作答</el-checkbox>
+              <el-checkbox label="1">答案解析</el-checkbox>
+            </el-checkbox-group>
+          </div>
+        </div>
+        <div class="dialog_close" @click="showDialog = false">关闭</div>
+        <div class="dialog_print" @click="DownloadPdfs()">下载PDF文件</div>
+      </div>
+    </el-dialog>
+    <div class="page_dialog">
+      <el-dialog title="下载PDF" class="page_dialog" :visible.sync="showReportLoading" width="500px" top="15%">
+        <div class="report_loading">
+          <div class="report_loading_icon">
+            <img src="@/assets/report/report_loading.png" />
+          </div>
+          <div class="report_loading_title">正在努力生成PDF中,请稍等...</div>
+          <div class="report_loading_progress">
+            <el-progress :text-inside="true" color="#2E64FA" text-color="#ffffff" :stroke-width="16"
+              :percentage="targetProgress"></el-progress>
+          </div>
+        </div>
+      </el-dialog>
+    </div>
+  </div>
+</template>
+
+<script>
+import { jsPDF } from "jspdf";
+import domtoimage from "dom-to-image";
+export default {
+  data() {
+    return {
+      showDialog: false, //是否显示弹窗
+      tableData: [],
+      progressInterval: null,
+      total: 0,
+      loading: null,
+      radioVal: 0,
+      checkVal: ['0', '1'], //默认值
+      pageInfo: {
+        //794*1123
+        width: 794, //595
+        height: 1123, //842
+      }, //成绩小条比例配置
+      showReportLoading: false, //成绩小条页加载图标
+      reportLoadingProgress: 0,
+      targetProgress: 0, //目标进度值
+      dialogKey: 1,
+    };
+  },
+  created() {
+    this.GetSlipData(); //获取成绩小条
+  },
+  beforeDestroy() {
+    // 组件销毁前清除定时器
+    if (this.progressInterval) {
+      clearInterval(this.progressInterval);
+      this.progressInterval = null;
+    }
+  },
+  methods: {
+    //获取总分 成绩小条数据
+    GetSlipData() {
+      this.dialogKey += 1;
+    },
+    //导出所有pdf domtoimage的方式
+    async DownloadPdfs() {
+      this.showReportLoading = true;
+
+      // 创建PDF对象,使用自定义纸张尺寸
+      const pdf = new jsPDF("p", "pt", "a4"); //p 为纵向布局
+      const pdfWidth = pdf.internal.pageSize.getWidth();
+      const pdfHeight = pdf.internal.pageSize.getHeight();
+
+      //获取所有的area_page 元素
+      const elements = document.querySelectorAll(".item_page");
+
+      let fillCount = 0; //完成数量
+      let pageCount = elements.length; //总数量
+      this.targetProgress = 0;
+      let oneProgress = Math.round((1 / pageCount) * 100);
+      this.StartProgress(0, oneProgress);
+
+      console.log("开始导出", this.targetProgress);
+
+      // 遍历每个页面数据
+      for (const [pageIndex, element] of Array.from(elements).entries()) {
+        // 确保页面元素存在并可见
+        await this.$nextTick();
+        if (element) {
+          // 确保元素可见并已渲染
+          // 确保元素可见并已渲染,并设置为横向排列样式
+          element.style.visibility = "visible";
+          element.offsetHeight; // 触发重排
+
+          // 等待元素完全渲染
+          await new Promise((resolve) => setTimeout(resolve, 100));
+
+          // 使用 dom-to-image 生成图片
+          const dataUrl = await domtoimage.toJpeg(element, {
+            quality: 0.8, // 降低质量以减小文件大小
+            // 获取完整尺寸
+            width: element.scrollWidth * 2,
+            height: element.scrollHeight * 2,
+            // 提高画布分辨率以获得更清晰的图像
+            canvasWidth: element.scrollWidth * 2,
+            canvasHeight: element.scrollHeight * 2,
+            style: {
+              transform: "scale(2)",
+              "transform-origin": "top left",
+              "background-color": "#ffffff",
+              overflow: "visible",
+              "white-space": "normal",
+              position: "relative",
+              visibility: "visible",
+            },
+            bgcolor: "#ffffff",
+          });
+
+          // 获取图像属性并计算缩放比例
+          const imgProps = pdf.getImageProperties(dataUrl);
+
+          const imgWidth = imgProps.width;
+          const imgHeight = imgProps.height;
+
+          // 计算缩放比例(保持宽高比)
+          const ratio = Math.min(pdfWidth / imgWidth, pdfHeight / imgHeight);
+          const adjustWidth = imgWidth * ratio;
+          const adjustHeight = imgHeight * ratio;
+
+          // 居中放置图像
+          const xPosition = (pdfWidth - adjustWidth) / 2;
+          const yPosition = (pdfHeight - adjustHeight) / 2;
+
+          // 如果不是第一页,添加新页面
+          if (pageIndex > 0) {
+            pdf.addPage();
+          }
+          pdf.addImage(
+            dataUrl,
+            "JPEG",
+            xPosition,
+            yPosition,
+            adjustWidth,
+            adjustHeight,
+          );
+          fillCount++;
+          // console.log("打印当前完成数量", fillCount);
+
+          // 更新进度
+          const progress = Math.floor((fillCount / pageCount) * 100);
+          const lastProgressprogress = progress - oneProgress;
+          // if(this.targetProgress<progress)
+          // {
+          // this.targetProgress=progress;
+          // }
+
+          this.StartProgress(lastProgressprogress, progress);
+
+          // 页面间短暂延迟
+          // await new Promise(resolve => setTimeout(resolve, 50));
+        }
+      }
+
+      // 保存PDF文件
+      pdf.save(this.examName + "-" + this.subjectName + "-成绩小条.pdf");
+
+      this.showReportLoading = false; //关闭加载loading
+    },
+    // 开始进度条数值变化  最大增加进度值 maxIncrement
+    StartProgress(currentValue, targetValue) {
+      console.log("开始进度动画,目标值:", targetValue);
+
+      // 清除已存在的定时器
+      if (this.progressInterval) {
+        clearInterval(this.progressInterval);
+        this.progressInterval = null;
+      }
+
+      // 获取当前进度值
+      if (this.targetProgress < currentValue) {
+        this.targetProgress = currentValue;
+      }
+      const targetProgress = targetValue;
+      // 如果当前值大于等于目标值,则不需要动画(进度不能递减)
+      if (this.targetProgress >= targetProgress) {
+        console.log("当前进度已达到或超过目标进度,无需动画");
+        return;
+      }
+
+      // 计算差值
+      const difference = targetProgress - currentValue;
+      console.log("差值:", difference);
+
+      // 根据差值计算时间间隔(差值越大,时间间隔越小)
+      // 这里设置时间间隔在50ms到100ms之间变化
+      const minInterval = 50;
+      const maxInterval = 500;
+      // 限制差值在1-10范围内
+      // 限制差值在1-10范围内
+      const clampedDifference = Math.max(1, Math.min(difference, 10));
+
+      // 计算时间间隔:差值1->500ms,差值10->50ms
+      let interval =
+        maxInterval -
+        (clampedDifference - 1) * ((maxInterval - minInterval) / 9);
+
+      // 将时间间隔调整为10的倍数
+      interval = Math.round(interval / 10) * 10;
+
+      // 确保时间间隔在有效范围内
+      interval = Math.max(minInterval, Math.min(interval, maxInterval));
+      // 计算每次增加的步长(差值越大,步长越大)
+      const step = Math.max(1, Math.floor(difference / 5)) || 1;
+
+      console.log(
+        "动画参数:当前进度=",
+        currentValue,
+        "目标进度=",
+        targetProgress,
+        "差值=",
+        difference,
+        "时间间隔=",
+        interval,
+        "步长=",
+        step,
+      );
+
+      // 创建新的定时器
+      this.progressInterval = setInterval(() => {
+        // 只能增加,不能减少
+        this.targetProgress = Math.min(
+          this.targetProgress + step,
+          targetProgress,
+        );
+        console.log("进度更新:", this.targetProgress);
+
+        // 如果达到目标值,清除定时器
+        if (this.targetProgress >= targetProgress) {
+          this.targetProgress = targetProgress;
+          console.log("进度动画完成,最终值:", this.targetProgress);
+          clearInterval(this.progressInterval);
+          this.progressInterval = null;
+        }
+      }, interval);
+    }
+  },
+};
+</script>
+<style scoped lang="scss">
+.dialog_print_content {
+  width: 100%;
+  height: 100vh;
+  background: #f0f4fb;
+  position: relative;
+  overflow: hidden;
+
+  .dialog_print_page {
+    width: 100%;
+    height: calc(100% - 40px);
+    margin: auto;
+    overflow-y: auto;
+
+    .item_page {
+      width: 595px;
+      height: 842px;
+      margin: auto;
+      background: #fff;
+      border-radius: 0px 0px 0px 0px;
+      padding: 20px;
+      box-sizing: border-box;
+      margin-bottom: 20px;
+    }
+  }
+
+  .fixed_set_box {
+    position: absolute;
+    top: 20px;
+    left: 20px;
+    display: flex;
+    flex-direction: column;
+    gap: 16px;
+  }
+
+  .item_set {
+    width: 160px;
+    background-color: #ffffff;
+    border-radius: 4px;
+    padding: 12px 14px 12px 12px;
+    box-sizing: border-box;
+
+    :deep(.el-radio-group) {
+      display: flex;
+      flex-direction: column;
+      gap: 8px;
+
+      .el-radio {
+        margin-right: 0;
+        line-height: 22px;
+        font-weight: 400;
+        font-size: 14px;
+        color: #333333;
+
+        .el-radio__input {
+          &.is-checked+.el-radio__label {
+            color: #333333;
+          }
+
+          &.is-checked .el-radio__inner {
+            border-color: #2e64fa;
+            background-color: #ffff;
+          }
+
+          .el-radio__inner {
+            width: 16px;
+            height: 16px;
+            border-color: rgba(0, 0, 0, 0.2);
+
+            &::after {
+              width: 10px;
+              height: 10px;
+              background-color: #2e64fa;
+            }
+          }
+        }
+
+        .el-radio__label {
+          padding-left: 3px;
+        }
+      }
+    }
+
+    :deep(.el-checkbox-group) {
+      display: flex;
+      flex-direction: column;
+      gap: 8px;
+
+      .el-checkbox {
+        font-weight: 400;
+        font-size: 14px;
+        color: #333333;
+        margin-right: 0;
+
+        .el-checkbox__input {
+          .el-checkbox__inner {
+            width: 16px;
+            height: 16px;
+
+            &::after {
+              left: 5px;
+            }
+          }
+
+          &.is-checked+.el-checkbox__label {
+            color: #333333;
+          }
+        }
+
+        .el-checkbox__label {
+          padding-left: 3px;
+          line-height: 22px;
+        }
+      }
+    }
+  }
+
+  .dialog_close {
+    position: absolute;
+    right: 20px;
+    top: 20px;
+    width: 160px;
+    height: 42px;
+    background: rgba(245, 108, 108, 0.1);
+    border-radius: 4px 4px 4px 4px;
+    border: 1px solid #f56c6c;
+    line-height: 42px;
+    text-align: center;
+    font-weight: 500;
+    font-size: 14px;
+    color: #f56c6c;
+    cursor: pointer;
+  }
+
+  .dialog_print {
+    position: absolute;
+    right: 20px;
+    top: 82px;
+    width: 160px;
+    height: 44px;
+    background: #2e64fa;
+    border-radius: 4px 4px 4px 4px;
+    line-height: 42px;
+    font-weight: 500;
+    font-size: 14px;
+    color: #ffffff;
+    text-align: center;
+    cursor: pointer;
+  }
+}
+</style>

+ 9 - 2
src/views/targetImprove/practice/practiceAnswer.vue

@@ -4,7 +4,7 @@
       <el-aside width="260px" class="hide_scrollbar">
         <div class="side_list">
           <div class="side_title">待练习知识点</div>
-          <div class="side_item" v-for="item in waitList" :key="item.exerciseId" @click="ChangeKnowledge(item)">
+          <div :class="['side_item',{'active':item.exerciseId == exerciseId}]" v-for="item in waitList" :key="item.exerciseId" @click="ChangeKnowledge(item)">
             <div class="item_name">
               {{ item.knowledgeName }}
             </div>
@@ -138,7 +138,7 @@ export default {
       waitList: [], //待练习知识点
       exerciseId: '', // 练习id
       knowledgeName:'',//知识点名称
-      questionList: [{}, {}, {}, {}],
+      questionList: [],
       fileList: [
         {
           name: "food.jpeg",
@@ -188,6 +188,8 @@ export default {
         .then((res) => {
           if (res.code == 200) {
             this.questionList = res?.data || [];
+          }else{
+            this.questionList = [];
           }
         });
     },
@@ -249,6 +251,11 @@ export default {
       padding: 10px;
       box-sizing: border-box;
       cursor: pointer;
+      &:active {
+        background: rgba(46,100,250,0.1);
+        border: 1px solid #2E64FA;
+      }
+
       .item_name {
         width: 100%;
         font-weight: 500;