Sfoglia il codice sorgente

Merge remote-tracking branch 'origin/seec' into seec

# Conflicts:
#	package-lock.json
181250114 3 anni fa
parent
commit
611bd24ffa

File diff suppressed because it is too large
+ 658 - 281
package-lock.json


+ 13 - 0
package.json

@@ -15,14 +15,26 @@
     "core-js": "^3.6.5",
     "echarts": "^4.8.0",
     "element-plus": "^1.0.2-beta.71",
+    "pdfjs-dist": "^2.0.943",
     "pdfmake": "^0.2.6",
+    "react": "^18.2.0",
     "react-pdf": "^6.0.3",
     "resize-detector": "^0.3.0",
     "vue": "^3.1.0",
+    "vue-pdf-embed": "^1.1.5",
+    "vue-pdf-preview": "^0.0.3",
+    "vue-pdf-signature": "^4.2.7",
     "vue-router": "^4.0.12",
+    "vue3-pdfjs": "^0.1.6",
     "vuex": "^4.0.2"
   },
   "devDependencies": {
+    "@babel/core": "^7.20.2",
+    "@babel/plugin-proposal-class-properties": "^7.18.6",
+    "@babel/plugin-transform-runtime": "^7.19.6",
+    "@babel/preset-env": "^7.20.2",
+    "@babel/preset-react": "^7.18.6",
+    "@babel/runtime": "^7.20.1",
     "@vue/cli-plugin-babel": "~4.5.0",
     "@vue/cli-plugin-eslint": "~4.5.0",
     "@vue/cli-plugin-router": "^4.5.15",
@@ -30,6 +42,7 @@
     "@vue/cli-service": "~4.5.0",
     "@vue/compiler-sfc": "^3.0.0",
     "babel-eslint": "^10.1.0",
+    "babel-loader": "^8.3.0",
     "eslint": "^6.7.2",
     "eslint-plugin-vue": "^7.0.0",
     "file-loader": "^6.2.0",

+ 13 - 11
src/api/courseWare.js

@@ -31,22 +31,24 @@ function downloadCourseWare(id) {
     );
 }
 
-const host = process.env.NODE_ENV === "development" ? "http://localhost:8080" : "";
-const slideUrl = host + "/api/slide";
-const useSlideServer = postfix => postfix ? slideUrl + postfix : slideUrl;
+// const host = process.env.NODE_ENV === "development" ? "http://localhost:8080" : "";
+// const slideUrl = host + "/api/slide";
+// const useSlideServer = postfix => postfix ? slideUrl + postfix : slideUrl;
 
 // 获取课件的文件链接
-function getSlideUrl ({ slideId }) {
-    return axios
-        .get(useSlideServer("/" + slideId + "/url"))
-        .then(res => res.data);
+function getSlideUrl (slideId) {
+    // return axios
+    //     .get(useSlideServer("/" + slideId + "/url"))
+    //     .then(res => res.data);
+    return axios.get(`${prefix}/getSlideUrl`, {params: {slideId}});
 }
 
 // 获取某个具体课件的信息
-function getSlideInfo ({ slideId }) {
-    return axios
-        .get(useSlideServer("/" + slideId))
-        .then(res => res.data);
+function getSlideInfo (slideId) {
+    // return axios
+    //     .get(useSlideServer("/" + slideId))
+    //     .then(res => res.data);
+    return axios.get(`${prefix}/getSlideInfo`, {params: {slideId}});
 }
 
 function checkCourseWareNameUnique(courseId, name) {

+ 88 - 89
src/components/Basic/CButton.vue

@@ -1,96 +1,95 @@
-<template>
-    <el-button></el-button>
+<!--<template>-->
 <!--  <button class="c-button" :style="style" :class="classList" @click="$emit('click')">-->
 <!--    <c-icon :bold="!noBold" :right="6" :left="-4" v-if="icon" class="icon" :size="20">{{icon}}</c-icon>-->
 <!--    <slot></slot>-->
 <!--  </button>-->
-</template>
-
-<script>
-// import CIcon from "@/components/Basic/CIcon";
-//
-// export default {
-//   components: { CIcon },
-//   // props: ['icon', 'noClickWarn']
-//   props: {
-//     icon: {
-//       type: String,
-//       default: null
-//     },
-//     noClickWarn: {
-//       type: Boolean,
-//       default: false
-//     },
-//     theme: {
-//       type: String,
-//       default: "normal"
-//     },
-//     // 背景透明的按钮
-//     text: {
-//       type: Boolean,
-//       default: false
-//     },
-//     // 使用白色字体、深色背景的最显眼按钮,优先级大于 text
-//     standout: {
-//       type: Boolean,
-//       default: false
-//     },
-//     // 占满宽度
-//     block: {
-//       type: Boolean,
-//       default: false
-//     },
-//     small: {
-//       type: Boolean,
-//       default: false
-//     },
-//     large: {
-//       type: Boolean,
-//       default: false
-//     },
-//     // 去掉涟漪效果
-//     noRipple: {
-//       type: Boolean,
-//       default: false
-//     },
-//     noBold: {
-//       type: Boolean,
-//       default: false
-//     },
-//     left: {
-//       type: Number,
-//       default: 0
-//     },
-//     right: {
-//       type: Number,
-//       default: 0
-//     }
-//   },
-//   computed: {
-//     style () {
-//       return {
-//         marginRight: this.right ? this.right + "px" : null,
-//         marginLeft: this.left ? this.left + "px" : null
-//       };
-//     },
-//     classList () {
-//       return [
-//         this.standout
-//           ? (this.theme ? "c-button-standout--" + this.theme : "c-button-standout--normal")
-//           : (
-//             this.text
-//               ? (this.theme ? "c-button-text--" + this.theme : "c-button-text--normal")
-//               : (this.theme ? "c-button--" + this.theme : "c-button--normal")
-//           ),
-//         this.large ? "c-button--large" : "",
-//         this.small ? "c-button--small" : "",
-//         this.noClickWarn ? "c-button--disabled" : "",
-//         this.block ? "c-button--block" : ""
-//       ];
-//     }
-//   }
-// };
-</script>
+<!--</template>-->
+
+<!--<script>-->
+<!--import CIcon from "@/components/Basic/CIcon";-->
+
+<!--export default {-->
+<!--  components: { CIcon },-->
+<!--  // props: ['icon', 'noClickWarn']-->
+<!--  props: {-->
+<!--    icon: {-->
+<!--      type: String,-->
+<!--      default: null-->
+<!--    },-->
+<!--    noClickWarn: {-->
+<!--      type: Boolean,-->
+<!--      default: false-->
+<!--    },-->
+<!--    theme: {-->
+<!--      type: String,-->
+<!--      default: "normal"-->
+<!--    },-->
+<!--    // 背景透明的按钮-->
+<!--    text: {-->
+<!--      type: Boolean,-->
+<!--      default: false-->
+<!--    },-->
+<!--    // 使用白色字体、深色背景的最显眼按钮,优先级大于 text-->
+<!--    standout: {-->
+<!--      type: Boolean,-->
+<!--      default: false-->
+<!--    },-->
+<!--    // 占满宽度-->
+<!--    block: {-->
+<!--      type: Boolean,-->
+<!--      default: false-->
+<!--    },-->
+<!--    small: {-->
+<!--      type: Boolean,-->
+<!--      default: false-->
+<!--    },-->
+<!--    large: {-->
+<!--      type: Boolean,-->
+<!--      default: false-->
+<!--    },-->
+<!--    // 去掉涟漪效果-->
+<!--    noRipple: {-->
+<!--      type: Boolean,-->
+<!--      default: false-->
+<!--    },-->
+<!--    noBold: {-->
+<!--      type: Boolean,-->
+<!--      default: false-->
+<!--    },-->
+<!--    left: {-->
+<!--      type: Number,-->
+<!--      default: 0-->
+<!--    },-->
+<!--    right: {-->
+<!--      type: Number,-->
+<!--      default: 0-->
+<!--    }-->
+<!--  },-->
+<!--  computed: {-->
+<!--    style () {-->
+<!--      return {-->
+<!--        marginRight: this.right ? this.right + "px" : null,-->
+<!--        marginLeft: this.left ? this.left + "px" : null-->
+<!--      };-->
+<!--    },-->
+<!--    classList () {-->
+<!--      return [-->
+<!--        this.standout-->
+<!--          ? (this.theme ? "c-button-standout&#45;&#45;" + this.theme : "c-button-standout&#45;&#45;normal")-->
+<!--          : (-->
+<!--            this.text-->
+<!--              ? (this.theme ? "c-button-text&#45;&#45;" + this.theme : "c-button-text&#45;&#45;normal")-->
+<!--              : (this.theme ? "c-button&#45;&#45;" + this.theme : "c-button&#45;&#45;normal")-->
+<!--          ),-->
+<!--        this.large ? "c-button&#45;&#45;large" : "",-->
+<!--        this.small ? "c-button&#45;&#45;small" : "",-->
+<!--        this.noClickWarn ? "c-button&#45;&#45;disabled" : "",-->
+<!--        this.block ? "c-button&#45;&#45;block" : ""-->
+<!--      ];-->
+<!--    }-->
+<!--  }-->
+<!--};-->
+<!--</script>-->
 
 <!--<style lang="scss" scoped>-->
 <!--@import "src/style/theme.scss";-->

+ 56 - 55
src/components/Basic/CIcon.vue

@@ -1,62 +1,62 @@
 <template>
-    <i></i>
-<!--  <i class="c-icons c-icon" :class="classList" :style="style">-->
-<!--    <slot></slot>-->
-<!--  </i>-->
+  <i></i>
+  <!--  <i class="c-icons c-icon" :class="classList" :style="style">-->
+  <!--    <slot></slot>-->
+  <!--  </i>-->
 </template>
 
 <script>
-// export default {
-//   props: {
-//     bold: {
-//       type: Boolean,
-//       default: false
-//     },
-//
-//     // icon 大小
-//     size: {
-//       type: Number,
-//       default: 0
-//     },
-//
-//     // 可以直接传入 6 位颜色值,将覆盖 theme 设置的颜色
-//     color: {
-//       type: String,
-//       default: ""
-//     },
-//
-//     theme: {
-//       type: String,
-//       default: "normal"
-//     },
-//
-//     right: {
-//       type: Number,
-//       default: 0
-//     },
-//
-//     left: {
-//       type: Number,
-//       default: 0
-//     }
-//   },
-//   computed: {
-//     classList () {
-//       return [
-//         this.bold ? "bold" : "",
-//         this.theme ? "c-icon--" + this.theme : ""
-//       ];
-//     },
-//     style () {
-//       return {
-//         fontSize: this.size ? this.size + "px" : null,
-//         marginRight: this.right ? this.right + "px" : null,
-//         marginLeft: this.left ? this.left + "px" : null,
-//         color: this.color || null
-//       };
-//     }
-//   }
-// };
+  // export default {
+  //   props: {
+  //     bold: {
+  //       type: Boolean,
+  //       default: false
+  //     },
+  //
+  //     // icon 大小
+  //     size: {
+  //       type: Number,
+  //       default: 0
+  //     },
+  //
+  //     // 可以直接传入 6 位颜色值,将覆盖 theme 设置的颜色
+  //     color: {
+  //       type: String,
+  //       default: ""
+  //     },
+  //
+  //     theme: {
+  //       type: String,
+  //       default: "normal"
+  //     },
+  //
+  //     right: {
+  //       type: Number,
+  //       default: 0
+  //     },
+  //
+  //     left: {
+  //       type: Number,
+  //       default: 0
+  //     }
+  //   },
+  //   computed: {
+  //     classList () {
+  //       return [
+  //         this.bold ? "bold" : "",
+  //         this.theme ? "c-icon--" + this.theme : ""
+  //       ];
+  //     },
+  //     style () {
+  //       return {
+  //         fontSize: this.size ? this.size + "px" : null,
+  //         marginRight: this.right ? this.right + "px" : null,
+  //         marginLeft: this.left ? this.left + "px" : null,
+  //         color: this.color || null
+  //       };
+  //     }
+  //   }
+  // };
 </script>
 
 <!--<style lang="scss" scoped>-->
@@ -77,3 +77,4 @@
 
 <!--@include setTheme-->
 <!--</style>-->
+

+ 24 - 24
src/components/Basic/CInput.vue

@@ -1,32 +1,32 @@
 <template>
     <el-button></el-button>
-<!--  <component-->
-<!--    class="c-input"-->
-<!--    :required="required"-->
-<!--    :is="textarea ? 'textarea' : 'input'"-->
-<!--    :type="type ? type : 'text'"-->
-<!--    :placeholder="placeholder"-->
-<!--    :value="value"-->
-<!--    :maxlength="maxlength ? maxlength : null"-->
-<!--    @input="$emit('input', $event.target.value)"-->
-<!--  />-->
+    <!--  <component-->
+    <!--    class="c-input"-->
+    <!--    :required="required"-->
+    <!--    :is="textarea ? 'textarea' : 'input'"-->
+    <!--    :type="type ? type : 'text'"-->
+    <!--    :placeholder="placeholder"-->
+    <!--    :value="value"-->
+    <!--    :maxlength="maxlength ? maxlength : null"-->
+    <!--    @input="$emit('input', $event.target.value)"-->
+    <!--  />-->
 </template>
 
 <script>
-// export default {
-//   model: {
-//     prop: "value",
-//     event: "input"
-//   },
-//   props: {
-//     value: [String, Number],
-//     placeholder: String,
-//     textarea: Boolean,
-//     type: String,
-//     maxlength: Number,
-//     required: Boolean
-//   }
-// };
+    // export default {
+    //   model: {
+    //     prop: "value",
+    //     event: "input"
+    //   },
+    //   props: {
+    //     value: [String, Number],
+    //     placeholder: String,
+    //     textarea: Boolean,
+    //     type: String,
+    //     maxlength: Number,
+    //     required: Boolean
+    //   }
+    // };
 </script>
 
 <!--<style lang="scss" scoped>-->

+ 16 - 16
src/components/Basic/CTag.vue

@@ -1,24 +1,24 @@
 <template>
     <el-tag></el-tag>
-<!--  <div class="c-tag" :class="classList">-->
-<!--    <slot></slot>-->
-<!--  </div>-->
+    <!--  <div class="c-tag" :class="classList">-->
+    <!--    <slot></slot>-->
+    <!--  </div>-->
 </template>
 
 <script>
-// export default {
-//   props: {
-//     theme: {
-//       type: String,
-//       default: "normal"
-//     }
-//   },
-//   computed: {
-//     classList () {
-//       return [this.theme ? "c-tag--" + this.theme : ""];
-//     }
-//   }
-// };
+    // export default {
+    //   props: {
+    //     theme: {
+    //       type: String,
+    //       default: "normal"
+    //     }
+    //   },
+    //   computed: {
+    //     classList () {
+    //       return [this.theme ? "c-tag--" + this.theme : ""];
+    //     }
+    //   }
+    // };
 </script>
 
 <!--<style lang="scss" scoped>-->

+ 57 - 56
src/components/Basic/IconButton.vue

@@ -1,63 +1,63 @@
 <template>
-    <el-button></el-button>
-<!--  <div class="icon-button" :class="classList" :title="title ? title : ''" @click="$emit('click')" :style="style">-->
-<!--    <c-icon :theme="theme" :bold="!noBold" :size="size ? size / 1.4 - 4 : 26">-->
-<!--      <slot></slot>-->
-<!--    </c-icon>-->
-<!--    <ripple :color="theme"></ripple>-->
-<!--  </div>-->
+  <el-button></el-button>
+  <!--  <div class="icon-button" :class="classList" :title="title ? title : ''" @click="$emit('click')" :style="style">-->
+  <!--    <c-icon :theme="theme" :bold="!noBold" :size="size ? size / 1.4 - 4 : 26">-->
+  <!--      <slot></slot>-->
+  <!--    </c-icon>-->
+  <!--    <ripple :color="theme"></ripple>-->
+  <!--  </div>-->
 </template>
 
 <script>
-// import CIcon from "@/components/Basic/CIcon";
-// import Ripple from "@/components/Basic/Ripple";
-//
-// export default {
-//   components: { Ripple, CIcon },
-//   // props: ['title', 'ripple', 'small']
-//   props: {
-//     title: {
-//       type: String,
-//       default: "按钮"
-//     },
-//
-//     // 可以直接传入 6 位颜色值,将覆盖 theme 设置的颜色
-//     color: {
-//       type: String,
-//       default: ""
-//     },
-//
-//     // 这个值需要在下方 scss 中有相应的定义,否则无效
-//     theme: {
-//       type: String,
-//       default: "normal"
-//     },
-//
-//     noBold: {
-//       type: Boolean,
-//       default: false
-//     },
-//
-//     // icon button 大小
-//     size: Number,
-//     left: Number,
-//     right: Number
-//   },
-//   computed: {
-//     classList () {
-//       return [this.theme ? "icon-button--" + this.theme : ""];
-//     },
-//     style () {
-//       return {
-//         color: this.color.match(/^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/) ? this.color : "",
-//         width: this.size ? this.size + "px" : null,
-//         height: this.size ? this.size + "px" : null,
-//         marginLeft: this.left ? this.left + "px" : null,
-//         marginRight: this.right ? this.right + "px" : null
-//       };
-//     }
-//   }
-// };
+  // import CIcon from "@/components/Basic/CIcon";
+  // import Ripple from "@/components/Basic/Ripple";
+  //
+  // export default {
+  //   components: { Ripple, CIcon },
+  //   // props: ['title', 'ripple', 'small']
+  //   props: {
+  //     title: {
+  //       type: String,
+  //       default: "按钮"
+  //     },
+  //
+  //     // 可以直接传入 6 位颜色值,将覆盖 theme 设置的颜色
+  //     color: {
+  //       type: String,
+  //       default: ""
+  //     },
+  //
+  //     // 这个值需要在下方 scss 中有相应的定义,否则无效
+  //     theme: {
+  //       type: String,
+  //       default: "normal"
+  //     },
+  //
+  //     noBold: {
+  //       type: Boolean,
+  //       default: false
+  //     },
+  //
+  //     // icon button 大小
+  //     size: Number,
+  //     left: Number,
+  //     right: Number
+  //   },
+  //   computed: {
+  //     classList () {
+  //       return [this.theme ? "icon-button--" + this.theme : ""];
+  //     },
+  //     style () {
+  //       return {
+  //         color: this.color.match(/^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/) ? this.color : "",
+  //         width: this.size ? this.size + "px" : null,
+  //         height: this.size ? this.size + "px" : null,
+  //         marginLeft: this.left ? this.left + "px" : null,
+  //         marginRight: this.right ? this.right + "px" : null
+  //       };
+  //     }
+  //   }
+  // };
 </script>
 
 <!--<style lang="scss" scoped>-->
@@ -107,3 +107,4 @@
 
 <!--@include setTheme()-->
 <!--</style>-->
+

+ 25 - 25
src/components/Basic/Ripple.vue

@@ -1,32 +1,32 @@
 <template>
-    <el-tag></el-tag>
-<!--  <div class="ripple-wrapper" :class="color || ''">-->
-<!--    <div class="ripple" @click="handleRipple" :class="className" :style="size ? `width: ${size}px; height: ${size}px;` : ''">-->
-<!--    </div>-->
-<!--    <div class="background"></div>-->
-<!--  </div>-->
+  <el-tag></el-tag>
+  <!--  <div class="ripple-wrapper" :class="color || ''">-->
+  <!--    <div class="ripple" @click="handleRipple" :class="className" :style="size ? `width: ${size}px; height: ${size}px;` : ''">-->
+  <!--    </div>-->
+  <!--    <div class="background"></div>-->
+  <!--  </div>-->
 </template>
 
 <script>
-// export default {
-//   props: ["size", "color"],
-//   data () {
-//     return {
-//       className: "hide"
-//     };
-//   },
-//   methods: {
-//     handleRipple () {
-//       this.className = "";
-//       this.$nextTick(() => {
-//         this.className = "show";
-//         setTimeout(() => {
-//           this.className = "";
-//         }, 500);
-//       });
-//     }
-//   }
-// };
+  // export default {
+  //   props: ["size", "color"],
+  //   data () {
+  //     return {
+  //       className: "hide"
+  //     };
+  //   },
+  //   methods: {
+  //     handleRipple () {
+  //       this.className = "";
+  //       this.$nextTick(() => {
+  //         this.className = "show";
+  //         setTimeout(() => {
+  //           this.className = "";
+  //         }, 500);
+  //       });
+  //     }
+  //   }
+  // };
 </script>
 
 <!--<style lang="scss" scoped>-->

+ 1 - 0
src/components/CourseCard.vue

@@ -43,6 +43,7 @@ export default {
   },
   computed: {
     imageUrl() {
+      console.log(this.courseVO.imageUrl);
       return this.courseVO.imageUrl === null ? this.noImgUrl : this.courseVO.imageUrl + "?t=" + Date.now().valueOf();
     },
     title() {

+ 31 - 28
src/components/PDF/Pdf.vue

@@ -1,29 +1,29 @@
 <template>
-    <el-tag></el-tag>
+  <button></button>
 <!--  <div class="pdf">-->
 <!--    <canvas class="pdf pdf-canvas" id="pdf-canvas" :class="classList"></canvas>-->
-<!--    <div v-if="loading" class="loading">加载中...</div>-->
-<!--    <fade-transition>-->
-<!--      <div v-if="focus" class="focus-mask">禁用快捷键中...<br>点击空白出退出</div>-->
-<!--    </fade-transition>-->
+<!--&lt;!&ndash;    <div v-if="loading" class="loading">加载中...</div>&ndash;&gt;-->
+<!--&lt;!&ndash;    <fade-transition>&ndash;&gt;-->
+<!--&lt;!&ndash;      <div v-if="focus" class="focus-mask">禁用快捷键中...<br>点击空白出退出</div>&ndash;&gt;-->
+<!--&lt;!&ndash;    </fade-transition>&ndash;&gt;-->
 <!--  </div>-->
 </template>
 
 <script>
-// import pdfjs from "@/utils/pdf";
 // import { mapState } from "vuex";
 // import { SET_TOTAL_PAGES } from "@/store/types/pdf-types";
 // import FadeTransition from "@/animations/FadeTransition";
 //
+// const pdfJS = require("pdfjs-dist");
+// pdfJS.GlobalWorkerOptions.workerSrc = require("pdfjs-dist/build/pdf.worker.entry");
+//
 // export default {
-//   components: { FadeTransition },
-//   data () {
+//   data() {
 //     return {
-//       loading: true
+//       loading: true,
 //     };
 //   },
-//   mounted () {
-//     console.log("hhh");
+//   mounted() {
 //     this.loading = true;
 //     this._canvas = document.getElementById("pdf-canvas");
 //     this._context = this._canvas.getContext("2d");
@@ -32,15 +32,17 @@
 //     this._canvas.height = 1080;
 //     this._canvas.width = 1440;
 //
+//     // if (this.src) {
+//     //   console.log(this.src);
+//     //   this.load(this.src);
+//     // } else {
+//     //   // ! 1秒后重试
+//     //   setTimeout(() => {
+//     //     //this.load(this.src);
+//     //   }, 1000);
+//     // }
 //     console.log(this.src);
-//     if (this.src) {
-//       this.load(this.src);
-//     } else {
-//       // ! 1秒后重试
-//       setTimeout(() => {
-//         this.load(this.src);
-//       }, 1000);
-//     }
+//     this.load(this.src);
 //   },
 //   computed: {
 //     ...mapState({
@@ -50,31 +52,32 @@
 //       screenShot: state => state.pdf.screenShot,
 //       focus: state => state.pdf.focus
 //     }),
-//     classList () {
+//     classList() {
 //       return {
 //         "full-size": !this.showDiscussion
 //       };
 //     }
 //   },
 //   watch: {
-//     currentPage () {
+//     currentPage() {
 //       this.showPage();
 //     }
 //   },
 //   methods: {
-//     load (src) {
-//       const loadingTask = pdfjs.getDocument(src);
+//     load(src) {
+//       console.log(src);
+//       const loadingTask = pdfJS.getDocument(src);
 //       loadingTask.promise.then(pdf => {
 //         this.loading = false;
 //         this._pdf = pdf;
-//         this.$store.commit(SET_TOTAL_PAGES, { totalPages: pdf.numPages });
+//         this.$store.commit(SET_TOTAL_PAGES, {totalPages: pdf.numPages});
 //         this.showPage();
 //       });
 //     },
-//     showPage () {
+//     showPage() {
 //       this._pdf && this._pdf.getPage(this.currentPage || 1).then(page => {
 //         const scale = 2.5;
-//         const viewport = page.getViewport({ scale: scale });
+//         const viewport = page.getViewport({scale: scale});
 //
 //         this._canvas.height = viewport.height;
 //         this._canvas.width = viewport.width;
@@ -89,12 +92,12 @@
 //         //this.$setInfoMessage('PDF 当前页解析错误')
 //       });
 //     }
-//   }
+//   },
 // };
 </script>
 
 <!--<style lang="scss" scoped>-->
-<!--@import 'src/style/theme.scss';-->
+<!--@import 'src/style/set-theme.scss';-->
 
 <!--.pdf {-->
 <!--  z-index: -1;-->

+ 2 - 2
src/components/PDF/PdfController.vue

@@ -1,5 +1,5 @@
 <template>
-    <el-button></el-button>
+  <button></button>
 <!--  <div class="pdf-controller" style="margin-top: 5%">-->
 <!--    <div class="actions" :class="hide ? 'hide-actions' : ''">-->
 <!--      <a :href="src">-->
@@ -80,7 +80,7 @@
 </script>
 
 <!--<style lang="scss" scoped>-->
-<!--@import 'src/style/theme.scss';-->
+<!--//@import 'src/style/set-theme.scss';-->
 
 <!--.pdf-controller {-->
 <!--  position: fixed;-->

+ 187 - 6
src/components/PDF/PdfViewer.vue

@@ -1,17 +1,31 @@
 <template>
-    <el-tag></el-tag>
-<!--  <div>-->
+  <div>
+<!--    <canvas class="pdf pdf-canvas" id="pdf-canvas" :class="classList"></canvas>-->
+
+<!--    <input type="file" ref="fielinput" @change="uploadFile" />-->
+<!--    <div class="canvas-container">-->
+<!--      <canvas ref="myCanvas" class="pdf-container"> </canvas>-->
+<!--    </div>-->
+<!--    <div class="pagination-wrapper">-->
+<!--      <button @click="clickPre">上一页</button>-->
+<!--      <span>第{{ pageNo }} / {{ pdfPageNumber }}页</span>-->
+<!--      <button @click="clickNext">下一页</button>-->
+<!--    </div>-->
+
 <!--    <pdf></pdf>-->
 <!--    <pdf-controller></pdf-controller>-->
-<!--  </div>-->
+  </div>
 </template>
 
 <script>
 // import Pdf from "@/components/PDF/Pdf";
-// import PdfController from "@/components/PDF/PdfController";
+// // import PdfController from "@/components/PDF/PdfController";
+//
 // export default {
-//   components: { PdfController, Pdf },
-//   props: ["src", "discussion"],
+//   components: {
+//     // PdfController,
+//     Pdf },
+//   props: ["src"],
 //   data () {
 //     return {
 //       currentPage: 1,
@@ -24,6 +38,173 @@
 //     }
 //   }
 // };
+//
+
+
+// import { mapState } from "vuex";
+// import { SET_TOTAL_PAGES } from "@/store/types/pdf-types";
+// import FadeTransition from "@/animations/FadeTransition";
+
+// const pdfJS = require("pdfjs-dist");
+// pdfJS.GlobalWorkerOptions.workerSrc = require("pdfjs-dist/build/pdf.worker.entry");
+
+// export default {
+//   data() {
+//     return {
+//       loading: true,
+//     };
+//   },
+//   mounted() {
+//     this.loading = true;
+//     this._canvas = document.getElementById("pdf-canvas");
+//     this._context = this._canvas.getContext("2d");
+//
+//     // Default size
+//     this._canvas.height = 1080;
+//     this._canvas.width = 1440;
+//
+//     if (this.src) {
+//       this.load(this.src);
+//     } else {
+//       // ! 1秒后重试
+//       setTimeout(() => {
+//         this.load(this.src);
+//       }, 1000);
+//     }
+//   },
+//   computed: {
+//     ...mapState({
+//       src: state => state.pdf.src,
+//       showDiscussion: state => state.pdf.showDiscussion,
+//       currentPage: state => state.pdf.currentPage,
+//       screenShot: state => state.pdf.screenShot,
+//       focus: state => state.pdf.focus
+//     }),
+//     classList() {
+//       return {
+//         "full-size": !this.showDiscussion
+//       };
+//     }
+//   },
+//   watch: {
+//     currentPage() {
+//       this.showPage();
+//     }
+//   },
+//   methods: {
+//     load(src) {
+//       console.log(pdfJS);
+//       const loadingTask = pdfJS.getDocument(src);
+//       loadingTask.promise.then(pdf => {
+//         this.loading = false;
+//         this._pdf = pdf;
+//         this.$store.commit(SET_TOTAL_PAGES, {totalPages: pdf.numPages});
+//         this.showPage();
+//       });
+//     },
+//     showPage() {
+//       this._pdf && this._pdf.getPage(this.currentPage || 1).then(page => {
+//         const scale = 2.5;
+//         const viewport = page.getViewport({scale: scale});
+//
+//         this._canvas.height = viewport.height;
+//         this._canvas.width = viewport.width;
+//
+//         const renderContext = {
+//           canvasContext: this._context,
+//           viewport: viewport
+//         };
+//         page.render(renderContext);
+//       }).catch(() => {
+//         console.log("PDF 当前页解析错误");
+//         //this.$setInfoMessage('PDF 当前页解析错误')
+//       });
+//     }
+//   },
+// };
+
+// export default {
+//   mounted() {},
+//   data() {
+//     return {
+//       pageNo: null,
+//       pdfPageNumber: null,
+//       pdfTotalPages: 1,
+//       renderingPage: false,
+//       pdfData: null, // PDF的base64
+//       scale: 1, // 缩放值
+//     };
+//   },
+//   methods: {
+//     uploadFile() {
+//       let inputDom = this.$refs.fielinput;
+//       let file = inputDom.files[0];
+//       let reader = new FileReader();
+//       reader.readAsDataURL(file);
+//       reader.onload = () => {
+//         let data = atob(
+//                 reader.result.substring(reader.result.indexOf(",") + 1)
+//         );
+//         this.loadPdfData(data);
+//       };
+//     },
+//     loadPdfData(data) {
+//       console.log(pdfJS);
+//       // 引入pdf.js的字体
+//       let CMAP_URL = "https://unpkg.com/pdfjs-dist@2.0.943/cmaps/";
+//       //读取base64的pdf流文件
+//       this.pdfData = pdfJS.getDocument({
+//         data: data, // PDF base64编码
+//         cMapUrl: CMAP_URL,
+//         cMapPacked: true,
+//       });
+//       console.log(this.pdfData);
+//       this.renderPage(1);
+//       // this.renderScrollPdf();
+//     },
+//
+//     // 根据页码渲染相应的PDF
+//     renderPage(num) {
+//       this.renderingPage = true;
+//       this.pdfData.promise.then((pdf) => {
+//         this.pdfPageNumber = pdf.numPages;
+//
+//         pdf.getPage(num).then((page) => {
+//           // 获取DOM中为预览PDF准备好的canvasDOM对象
+//           let canvas = this.$refs.myCanvas;
+//           let viewport = page.getViewport(this.scale);
+//           canvas.height = viewport.height;
+//           canvas.width = viewport.width;
+//
+//           let ctx = canvas.getContext("2d");
+//           let renderContext = {
+//             canvasContext: ctx,
+//             viewport: viewport,
+//           };
+//           page.render(renderContext).then(() => {
+//             this.renderingPage = false;
+//             this.pageNo = num;
+//           });
+//         });
+//       });
+//     },
+//     clickPre() {
+//       if (!this.renderingPage && this.pageNo && this.pageNo > 1) {
+//         this.renderPage(this.pageNo - 1);
+//       }
+//     },
+//     clickNext() {
+//       if (
+//               !this.renderingPage &&
+//               this.pdfPageNumber &&
+//               this.pageNo &&
+//               this.pageNo < this.pdfPageNumber
+//       ) {
+//         this.renderPage(this.pageNo + 1);
+//       }
+//     },
+//   },
+// };
 </script>
 
 <!--<style lang="scss" scoped>-->

+ 1 - 1
src/components/PDF/PointerCanvas.vue

@@ -1,7 +1,7 @@
 <template>
-    <el-button></el-button>
 <!--  <canvas :width="width" :height="height" class="pointer-canvas" ref="pointerCanvas" @click="handleFocus">-->
 <!--  </canvas>-->
+  <div></div>
 </template>
 
 <script>

+ 21 - 6
src/utils/pdf.js

@@ -1,10 +1,25 @@
-import pdfjs from "pdfjs";
+// import pdfjs from "pdfjs-dist";
+//
+// // import pdfMake from "pdfmake/build/pdfmake";
+// // import pdfFonts from "pdfmake/build/vfs_fonts";
+// // import { Document, Page, pdfjs } from "react-pdf";
+// // pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/@2.16.105/pdf.worker.js`;
+//
+// pdfjs.GlobalWorkerOptions.workerSrc = "node_modules/pdfjs-dist/build/pdf.worker.js";
+// // // pdfjs.GlobalWorkerOptions.workerSrc = "https://cdn.jsdelivr.net/npm/pdfjs-dist@3.0.279/build/pdf.worker.min.js";
+// // pdfjs.GlobalWorkerOptions.workerSrc = "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.16.105/build/pdf.worker.js";
+//
+// export default pdfjs;
 
-import pdfMake from "pdfmake/build/pdfmake";
-import pdfFonts from "pdfmake/build/vfs_fonts";
-//import { Document, Page, pdfjs } from "react-pdf";
-//pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
 
-pdfjs.GlobalWorkerOptions.workerSrc = "https://cdn.jsdelivr.net/npm/pdfjs-dist@3.0.279/build/pdf.worker.min.js";
+//import pdfjs from "pdfjs";
+
+//pdfjs.GlobalWorkerOptions.workerSrc = "D:\\Desktop\\seecoder\\SEEC-Portal-Front\\node_modules\\pdfjs-dist\\build\\pdf.worker.js";
+
+
+const pdfjs = await import("pdfjs-dist/build/pdf");
+const pdfjsWorker = await import("pdfjs-dist/build/pdf.worker.entry");
+
+pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;
 
 export default pdfjs;

+ 180 - 74
src/views/CoursePage/tabs/CoursewareTab.vue

@@ -1,17 +1,28 @@
 <template>
   <div class="courseware-tab">
-    <el-button @click="uploadDialogVisible = true" type="primary" plain>添加课件</el-button>
-    <el-dialog v-model="uploadDialogVisible" :before-close="handleFormCancel" :width="700">
+      <el-row>
+          <el-col :span="3.5">
+              <el-button
+                      @click="uploadDialogVisible = true"
+                      type="primary"
+                      icon="el-icon-circle-plus-outline"
+                      plain>新建</el-button>
+          </el-col>
+          <el-col :span="15">
+              <span style="font-size: smaller; position: absolute; bottom: 25%">(支持拓展名:.pdf .ppt .pptx .doc .docx .xls .jpg .jpeg .png,单次只可上传一个文件)</span>
+          </el-col>
+      </el-row>
+      <el-dialog v-model="uploadDialogVisible" :before-close="handleFormCancel" :width="700">
       <el-form ref="formRef" :model="form"  label-width="100px">
 <!--          :rules="formRules"-->
-          <el-form-item label="使用时间" required>
-              <el-select v-model="form.useTime" placeholder="时间">
-                  <el-option key="1" label="课前" value="BEFORE_CLASS"></el-option>
-                  <el-option key="2" label="课中" value="IN_CLASS"></el-option>
-                  <el-option key="3" label="课后" value="AFTER_CLASS"></el-option>
-                  <el-option key="4" label="期末" value="FINISH_CLASS"></el-option>
-              </el-select>
-          </el-form-item>
+<!--          <el-form-item label="使用时间" required>-->
+<!--              <el-select v-model="form.useTime" placeholder="时间">-->
+<!--                  <el-option key="1" label="课前" value="BEFORE_CLASS"></el-option>-->
+<!--                  <el-option key="2" label="课中" value="IN_CLASS"></el-option>-->
+<!--                  <el-option key="3" label="课后" value="AFTER_CLASS"></el-option>-->
+<!--                  <el-option key="4" label="期末" value="FINISH_CLASS"></el-option>-->
+<!--              </el-select>-->
+<!--          </el-form-item>-->
 
           <el-form-item label="使用类型" required>
               <el-select v-model="form.useMethod" placeholder="类型">
@@ -27,8 +38,14 @@
                   action=""
                   class="upload-demo"
                   :auto-upload="false"
-                  :show-file-list="false">
-                  <el-button plain type="primary" class="tabs-function-button">上传文件<i class="el-icon-upload"></i></el-button>(请选择单个文件)
+                  :show-file-list="false"
+              >
+                  <el-button
+                      plain
+                      type="primary"
+                      class="tabs-function-button"
+                      icon="el-icon-upload"
+                        >上传文件</el-button>(请选择单个文件)
               </el-upload>
               <el-tag
                       v-if="isUnique"
@@ -53,15 +70,15 @@
       <el-table-column
         prop="name"
         label="文件名"
-        width="220">
+        width="240">
           <template #default="scope">
             <el-icon v-if="scope.row['courseWareVO'].useMethod === 'SCAN'" style="color: #337ecc" class="myicon"><Reading /></el-icon>
             <el-icon v-if="scope.row['courseWareVO'].useMethod === 'ATTACHMENT'" style="color: green" class="myicon"><Paperclip /></el-icon>
             {{scope.row["courseWareVO"].name}}
-            <el-tag v-if="scope.row['courseWareVO'].useTime === 'BEFORE_CLASS'" type="success" class="mytag" size="mini"> {{getUseTimeTransition(scope.row["courseWareVO"].useTime)}} </el-tag>
-            <el-tag v-else-if="scope.row['courseWareVO'].useTime === 'IN_CLASS'" type="warning" class="mytag" size="mini"> {{getUseTimeTransition(scope.row["courseWareVO"].useTime)}} </el-tag>
-            <el-tag v-else-if="scope.row['courseWareVO'].useTime === 'AFTER_CLASS'" class="mytag" size="mini"> {{getUseTimeTransition(scope.row["courseWareVO"].useTime)}} </el-tag>
-            <el-tag v-else type="danger" class="mytag" size="mini"> {{getUseTimeTransition(scope.row["courseWareVO"].useTime)}} </el-tag>
+<!--            <el-tag v-if="scope.row['courseWareVO'].useTime === 'BEFORE_CLASS'" type="success" class="mytag" size="mini"> {{getUseTimeTransition(scope.row["courseWareVO"].useTime)}} </el-tag>-->
+<!--            <el-tag v-else-if="scope.row['courseWareVO'].useTime === 'IN_CLASS'" type="warning" class="mytag" size="mini"> {{getUseTimeTransition(scope.row["courseWareVO"].useTime)}} </el-tag>-->
+<!--            <el-tag v-else-if="scope.row['courseWareVO'].useTime === 'AFTER_CLASS'" class="mytag" size="mini"> {{getUseTimeTransition(scope.row["courseWareVO"].useTime)}} </el-tag>-->
+<!--            <el-tag v-else type="danger" class="mytag" size="mini"> {{getUseTimeTransition(scope.row["courseWareVO"].useTime)}} </el-tag>-->
           </template>
       </el-table-column>
       <el-table-column
@@ -69,13 +86,13 @@
         label="文件大小"
         width="100">
           <template #default="scope">
-            <span>{{scope.row["courseWareVO"].size}} KB</span>
+            {{getSizeTransition(scope.row["courseWareVO"].size)}}
           </template>
       </el-table-column>
       <el-table-column
         prop="created_time"
         label="上传时间"
-        width="180">
+        width="160">
           <template #default="scope">
             {{timestampToTime(scope.row["courseWareVO"].createdTime)}}
           </template>
@@ -85,8 +102,16 @@
         label="操作"
         width="220">
           <template #default="scope">
-            <el-button v-if="scope.row['courseWareVO'].useMethod === 'SCAN'"
-                       size="mini" type="primary" @click="handleCheck(scope.row['courseWareVO'].id)" plain style="margin-right: 5px">查看</el-button>
+            <a :href="scope.row['courseWareVO'].fileUrl" v-if="isPdfOrPicture(scope.row['courseWareVO'].name) === 'OTHER'">
+              <el-button v-if="scope.row['courseWareVO'].useMethod === 'SCAN'"
+                       size="mini" type="primary" plain style="margin-right: 5px">预览</el-button>
+            </a>
+            <el-button v-if="scope.row['courseWareVO'].useMethod === 'SCAN' && isPdfOrPicture(scope.row['courseWareVO'].name) === 'PDF'"
+                 @click="handleCheck(scope.row['courseWareVO'].fileUrl)"
+                   size="mini" type="primary" plain style="margin-right: 5px">预览</el-button>
+            <el-button v-if="scope.row['courseWareVO'].useMethod === 'SCAN' && isPdfOrPicture(scope.row['courseWareVO'].name) === 'PICTURE'"
+                 @click="handleCheckPicture(scope.row['courseWareVO'])"
+                 size="mini" type="primary" plain style="margin-right: 5px">预览</el-button>
             <a :href="scope.row['courseWareVO'].fileUrl">
               <el-button size="mini" type="success" plain style="margin-right: 5px">下载</el-button>
             </a>
@@ -95,6 +120,21 @@
           </template>
       </el-table-column>
     </el-table>
+      <el-dialog
+              v-model = "pictureDialogVisible"
+              width = "80%"
+              :before-close = "handleClosePicture"
+      >
+          <img :src="pictureUrl" alt="" style="width: 100%" class="image" />
+<!--          <el-image style="width: 100px; height: 100px" :src="getPictureUrl" />-->
+          <template #footer>
+      <span class="dialog-footer">
+        <el-button type="primary" @click="pictureDialogVisible = false" plain>
+          关闭
+        </el-button>
+      </span>
+          </template>
+      </el-dialog>
   </div>
 </template>
 
@@ -124,7 +164,10 @@ export default {
       fileList: [],
       fileEntryList: [],
       uploadDialogVisible: false,
+      pictureDialogVisible: false,
       isUnique: false,
+      pictureUrl: null,
+      pictureName: null,
       fileNameTags: [],
       tag: null,
       num: 0,
@@ -134,7 +177,7 @@ export default {
     // isCreator(senderId) {
     //   return Number(senderId) === Number(this.$store.state.user.id);
     // },
-},
+  },
   mounted() {
       this.init();
   },
@@ -150,6 +193,26 @@ export default {
     timestampToTime: portal.functions.timestampToTime,
 
     async handleChange(file, fileList) {
+        const fileType = file.name.substring(file.name.indexOf(".") + 1);
+        console.log(this.form.useMethod + " + " + file.name.substring(file.name.indexOf(".") + 1));
+        if (!(fileType === "pdf" || fileType === "ppt" || fileType === "pptx" || fileType === "xls"
+            || fileType === "doc" || fileType === "docx" || fileType === "png" || fileType === "jpeg" || fileType === "jpg")) {
+            this.$message({
+                message: "该文件类型不属于支持的课件类型",
+                type: "error"
+            });
+            return;
+        }
+        // if (this.form.useMethod === "SCAN") {
+        //     if (!(fileType === "pdf" || fileType === "ppt" || fileType === "pptx" || fileType === "xls"
+        //         || fileType === "doc" || fileType === "docx" || fileType === "txt")) {
+        //         this.$message({
+        //             message: "该文件类型不属于支持的可浏览课件类型",
+        //             type: "error"
+        //         });
+        //         return;
+        //     }
+        // }
         if (this.num === 1) {
             this.$message({
                 message: "一次只能选择上传一个课件",
@@ -159,14 +222,10 @@ export default {
         }
         this.file = file;
         this.fileList = fileList;
+        console.log(this.file.raw.type);
         const isNameUnique = (await this.$apis.checkCourseWareNameUnique(this.courseId, this.file.name)).data.data;
         if (!isNameUnique) {
             console.log("notunique");
-            // await ElMessageBox.alert("该课程下已存在同名课件", "提示", {
-            //     confirmButtonText: "重新选择",
-            //     type: "warning",
-            //     center: true,
-            // });
             this.$message({
                 message: "该课程下已存在同名课件",
                 type: "error"
@@ -184,7 +243,7 @@ export default {
                 type: "error"
             });
         } else {
-            const fileUrl = (await this.$apis.uploadCourseWareFile(this.file.name, this.fileList[0].raw)).data.data;
+            const fileUrl = (await this.$apis.uploadCourseWareFile(this.courseId + "/" + this.file.name, this.fileList[0].raw)).data.data;
             this.$message({
                 message: "上传课件成功",
                 type: "success"
@@ -195,7 +254,7 @@ export default {
                 senderId: this.$store.state.user.id,
                 courseId: this.courseId,
                 createdTime: new Date(),
-                useTime: this.form.useTime,
+                useTime: "BEFORE_CLASS",
                 useMethod: this.form.useMethod,
                 fileUrl: fileUrl,
             }).then(async () => {
@@ -203,6 +262,7 @@ export default {
             });
             this.uploadDialogVisible = false;
             this.isUnique = false;
+            this.num = 0;
         }
     },
 
@@ -265,16 +325,28 @@ export default {
             });
     },
 
-    handleCheck(id) {
-        console.log("check" + id);
-        this.$router.push({ name: "courseWare", params: { courseWareId: id, page: "1"} });
+    handleCheck(fileUrl) {
+        console.log("check" + fileUrl);
+        //this.$router.push({ name: "courseWare", params: { courseWareId: id, page: "1"} });
+        window.open(fileUrl);
     },
 
-    // handleExceed(files) {
-    //     console.log(files);
-    //     ElMessage.error("一次只能上传一个文件");
-    //     this.fileList = null;
-    // },
+    handleCheckPicture(courseWareVO) {
+        this.pictureDialogVisible = true;
+        this.pictureUrl = courseWareVO.fileUrl;
+        this.pictureName = courseWareVO.name;
+    },
+
+    isPdfOrPicture(name) {
+        const fileType = name.substring(name.indexOf(".") + 1);
+        if (fileType === "pdf") {
+            return "PDF";
+        } else if (fileType === "png" || fileType === "jpg" || fileType === "jpeg") {
+            return "PICTURE";
+        } else {
+            return "OTHER";
+        }
+    },
 
     getUseTimeTransition(useTime) {
       switch (useTime) {
@@ -289,46 +361,80 @@ export default {
       }
     },
 
-    getUseTimeColor(useTime) {
-      switch (useTime) {
-          case "BEFORE_CLASS":
-              return "green";
-          case "IN_CLASS":
-              return "orange";
-          case "AFTER_CLASS":
-              return "blue";
-          case "FINISH_CLASS":
-              return "red";
-      }
+    getSizeTransition(size) {
+    if (size < 1000000) {
+        return (size * 1.0 / 1000).toFixed(2) + " MB";
+    } else {
+        return (size * 1.0 / 1000000).toFixed(2) + " GB";
+    }
+    },
+
+    handleClosePicture() {
+      ElMessageBox.confirm("Are you sure to close this dialog?")
+          .then(() => {
+              this.pictureDialogVisible = false;
+          });
     },
 
+    Previewf(file) {
+      console.log(file);
+      // window.open(file.response)
+      if (file) {
+          const addTypeArray = file.name.split(".");
+          const addType = addTypeArray[addTypeArray.length - 1];
+          console.log(addType);
+          if (addType === "pdf") {
+              let routeData = this.$router.resolve({
+                  path: "/insurancePdf",
+                  query: { url: file.response, showBack: false },
+              });
+              window.open(routeData.href, "_blank");
+          }
+          //".rar, .zip, .doc, .docx, .xls, .txt, .pdf, .jpg,  .png, .jpeg,"
+          else if (addType === "doc" || addType === "docx" || addType === "xls") {
+              window.open(
+                  "http://view.officeapps.live.com/op/view.aspx?src=" + file.response
+              );
+          } else if (addType === "txt") {
+              window.open(file.response);
+          } else if (["png", "jpg", "jpeg"].includes(addType)) {
+              window.open(file.response);
+          } else if (addType === "rar" || addType === "zip") {
+              this.$message({
+                  message: "该文件类型暂不支持预览",
+                  type: "warning",
+              });
+              return false;
+          }
+      }
+    }
 
-      // handleDownload(id) {
-      //   this.$apis.downloadCourseWare(id, {responseType: "blob"})
-      //       .then((res) => {
-      //       let data = res.data;
-      //       console.log(data);
-      //       if(!data){
-      //           return;
-      //       }
-      //       let fileName = res.headers["content-disposition"].split(";")[1];
-      //       console.log(fileName);
-      //       //构造a标签 通过a标签来下载
-      //       let url = window.URL.createObjectURL(new Blob([data]));
-      //       let a = document.createElement("a");
-      //       a.style.display = "none";
-      //       a.href = url;
-      //       //此处的download是a标签的内容,固定写法,不是后台api接口
-      //       a.setAttribute("download",fileName);
-      //       document.body.appendChild(a);
-      //       //点击下载
-      //       a.click();
-      //       // 下载完成移除元素
-      //       document.body.removeChild(a);
-      //       // 释放掉blob对象
-      //       window.URL.revokeObjectURL(url);
-      //   });
-      // }
+    // handleDownload(id) {
+    //   this.$apis.downloadCourseWare(id, {responseType: "blob"})
+    //       .then((res) => {
+    //       let data = res.data;
+    //       console.log(data);
+    //       if(!data){
+    //           return;
+    //       }
+    //       let fileName = res.headers["content-disposition"].split(";")[1];
+    //       console.log(fileName);
+    //       //构造a标签 通过a标签来下载
+    //       let url = window.URL.createObjectURL(new Blob([data]));
+    //       let a = document.createElement("a");
+    //       a.style.display = "none";
+    //       a.href = url;
+    //       //此处的download是a标签的内容,固定写法,不是后台api接口
+    //       a.setAttribute("download",fileName);
+    //       document.body.appendChild(a);
+    //       //点击下载
+    //       a.click();
+    //       // 下载完成移除元素
+    //       document.body.removeChild(a);
+    //       // 释放掉blob对象
+    //       window.URL.revokeObjectURL(url);
+    //   });
+    // }
 
     // handleDownloadFileIconClick(url) {
     // },

+ 187 - 190
src/views/CourseWarePage/CourseWarePage.vue

@@ -1,204 +1,201 @@
 <template>
-    <i class="el-icon-star-off"></i>
-<!--<el-row id="manage-page-body">-->
-<!--    <el-col :span="3">-->
-<!--        <el-menu background-color="#f8f9fb" default-active="1" style="position: fixed;"-->
-<!--                 @select="handleSelect">-->
-<!--            <el-menu-item index="0">-->
-<!--                <el-icon>-->
-<!--                    <Back/>-->
-<!--                </el-icon>-->
-<!--                <span style="padding-left: 20px">返回首页</span>-->
-<!--            </el-menu-item>-->
-<!--            <el-menu-item index="1">-->
-<!--                <el-icon>-->
-<!--                    <Document/>-->
-<!--                </el-icon>-->
-<!--                <span style="padding-left: 20px">全部课程</span>-->
-<!--            </el-menu-item>-->
-<!--        </el-menu>-->
-<!--    </el-col>-->
-<!--    <el-col :span="1"/>-->
-<!--    <el-col :span="18">-->
-<!--        <div class="pdf-reader">-->
-<!--            <pdf-viewer></pdf-viewer>-->
-<!--            <pointer-canvas ref="pointerCanvas" :no-pointer="!pointer" :no-box="!box"></pointer-canvas>-->
-<!--            <div class="pointer-actions">-->
-<!--                <c-button text :theme="pointer ? 'red' : ''" @click="pointer = !pointer">-->
-<!--                    <i class="el-icon-edit"/> 指针</c-button>-->
-<!--                <c-button text :left="8" :theme="box ? 'blue' : ''" @click="box = !box">-->
-<!--                    <i class="el-icon-crop"/> 框选</c-button>-->
-<!--                <c-button text :left="8" theme="orange" @click="cleanCanvas">-->
-<!--                    <i class="el-icon-refresh-left"/> 清除</c-button>-->
-<!--            </div>-->
-<!--        </div>-->
-<!--    </el-col>-->
-<!--</el-row>-->
+<el-row id="manage-page-body">
+    <el-col :span="3">
+        <el-menu background-color="#f8f9fb" default-active="1" style="position: fixed;"
+                 @select="handleSelect">
+            <el-menu-item index="0">
+                <el-icon>
+                    <Back/>
+                </el-icon>
+                <span style="padding-left: 20px">返回首页</span>
+            </el-menu-item>
+            <el-menu-item index="1">
+                <el-icon>
+                    <Document/>
+                </el-icon>
+                <span style="padding-left: 20px">全部课程</span>
+            </el-menu-item>
+        </el-menu>
+    </el-col>
+    <el-col :span="1"/>
+    <el-col :span="18">
+        <div class="pdf-reader">
+            <pdf-viewer></pdf-viewer>
+            <pointer-canvas ref="pointerCanvas" :no-pointer="!pointer" :no-box="!box"></pointer-canvas>
+            <div class="pointer-actions">
+                <c-button text :theme="pointer ? 'red' : ''" @click="pointer = !pointer">
+                    <i class="el-icon-edit"/> 指针</c-button>
+                <c-button text :left="8" :theme="box ? 'blue' : ''" @click="box = !box">
+                    <i class="el-icon-crop"/> 框选</c-button>
+                <c-button text :left="8" theme="orange" @click="cleanCanvas">
+                    <i class="el-icon-refresh-left"/> 清除</c-button>
+            </div>
+        </div>
+    </el-col>
+</el-row>
+
 </template>
 
 <script>
-    export default {
-        name: "CourseWarePage",
-    };
-// import PdfViewer from "@/components/PDF/PdfViewer";
-// import { mapState } from "vuex";
-// import {
-//     FOCUS_ON_INPUT,
-//     NEXT_PAGE,
-//     PREVIOUS_PAGE,
-//     RESET, SET_CURRENT_PAGE,
-//     SET_SRC,
-//     TOGGLE_SHOW_DISCUSSION,
-//     USE_FOCUS
-// } from "@/store/types/pdf-types";
-// import PointerCanvas from "@/components/PDF/PointerCanvas";
-// import CButton from "@/components/Basic/CButton";
-//
-// export default {
-//     components: {CButton, PointerCanvas, PdfViewer},
-//     computed: {
-//         ...mapState({
-//             src: state => state.pdf.src,
-//             focus: state => state.pdf.focus
-//         })
-//     },
-//     data () {
-//         return {
-//             pointer: false,
-//             box: false,
-//             slide: {}
-//         };
-//     },
-//     mounted () {
-//         console.log("coursewarepage");
-//         this.$store.commit(RESET);
-//         let { page } = this.$route.params;
-//         if (page) {
-//             this.$store.commit(SET_CURRENT_PAGE, { currentPage: parseInt(page) });
-//         }
-//         const _slideId = this.$route.params.slideId;
-//         this.$apis.getSlideInfo({ slideId: _slideId }).then(res => {
-//             this.slide = res;
-//         }).catch(err => {
-//             //this.$setErrorMessage(err.response.data.msg)
-//         });
-//         this.$apis.getSlideUrl({ slideId: _slideId }).then(res => {
-//             console.log(this.$apis.getSlideUrl({ slideId: _slideId }));
-//             this.$store.commit(SET_SRC, { src: res });
-//         }).catch(err => {
-//             //this.$setErrorMessage('获取课件链接的过程中:' + err.response.data.msg)
-//         });
-//         window.addEventListener("keydown", this.handleKey);
-//     },
-//     beforeUnmount () {
-//         window.removeEventListener("keydown", this.handleKey);
-//     },
-//     methods: {
-//         handleSelect(index) {
-//             if (index === "0") {
-//                 this.$router.push("portal");
-//             }
-//             if (index === "1") {
-//                 document.getElementById("app").scrollIntoView({behavior: "smooth"});
-//             }
-//         },
-//         handleKey (e) {
-//             if (e.key === "Enter") {
-//                 !this.showDiscussion && this.$store.commit(TOGGLE_SHOW_DISCUSSION);
-//                 !this.focus && this.$store.commit(FOCUS_ON_INPUT);
-//                 return;
-//             }
-//             if (e.key === "Escape") {
-//                 if (this.focus) {
-//                     this.$store.commit(USE_FOCUS);
-//                 } else {
-//                     this.$store.commit(TOGGLE_SHOW_DISCUSSION);
-//                 }
-//                 return;
-//             }
-//             if (!this.showDiscussion || !this.focus) {
-//                 switch (e.key) {
-//                     case "ArrowDown":
-//                     case "ArrowRight":
-//                     case "s":
-//                     case "d":
-//                     case " ":
-//                         this.$store.commit(NEXT_PAGE);
-//                         break;
-//                     case "ArrowUp":
-//                     case "ArrowLeft":
-//                     case "w":
-//                     case "a":
-//                         this.$store.commit(PREVIOUS_PAGE);
-//                         break;
-//                     case "c":
-//                         this.cleanCanvas();
-//                         break;
-//                     case "q":
-//                     case "z":
-//                         this.$refs.pointerCanvas.undo();
-//                         break;
-//                     case "e":
-//                     case "y":
-//                         this.$refs.pointerCanvas.redo();
-//                         break;
-//                     case "[":
-//                     case "b":
-//                         this.box = !this.box;
-//                         break;
-//                     case "p":
-//                     case "v":
-//                         this.pointer = !this.pointer;
-//                         break;
-//                 }
-//             }
-//         },
-//         cleanCanvas () {
-//             this.$refs.pointerCanvas.cleanCanvas();
-//         }
-//     },
-// };
+import PdfViewer from "@/components/PDF/PdfViewer";
+import { mapState } from "vuex";
+import {
+    FOCUS_ON_INPUT,
+    NEXT_PAGE,
+    PREVIOUS_PAGE,
+    RESET, SET_CURRENT_PAGE,
+    SET_SRC,
+    TOGGLE_SHOW_DISCUSSION,
+    USE_FOCUS
+} from "@/store/types/pdf-types";
+import PointerCanvas from "@/components/PDF/PointerCanvas";
+import CButton from "@/components/Basic/CButton";
+
+export default {
+    components: {CButton, PointerCanvas, PdfViewer},
+    computed: {
+        ...mapState({
+            src: state => state.pdf.src,
+            focus: state => state.pdf.focus
+        })
+    },
+    data () {
+        return {
+            pointer: false,
+            box: false,
+            slide: {}
+        };
+    },
+    mounted () {
+        console.log("coursewarepage");
+        this.$store.commit(RESET);
+        let { page } = this.$route.params;
+        if (page) {
+            this.$store.commit(SET_CURRENT_PAGE, { currentPage: parseInt(page) });
+        }
+        const _slideId = this.$route.params.slideId;
+        this.$apis.getSlideInfo({ slideId: _slideId }).then(res => {
+            this.slide = res;
+        }).catch(err => {
+            //this.$setErrorMessage(err.response.data.msg)
+        });
+        this.$apis.getSlideUrl({ slideId: _slideId }).then(res => {
+            console.log(this.$apis.getSlideUrl({ slideId: _slideId }));
+            this.$store.commit(SET_SRC, { src: res });
+        }).catch(err => {
+            //this.$setErrorMessage('获取课件链接的过程中:' + err.response.data.msg)
+        });
+        window.addEventListener("keydown", this.handleKey);
+    },
+    beforeUnmount () {
+        window.removeEventListener("keydown", this.handleKey);
+    },
+    methods: {
+        handleSelect(index) {
+            if (index === "0") {
+                this.$router.push("portal");
+            }
+            if (index === "1") {
+                document.getElementById("app").scrollIntoView({behavior: "smooth"});
+            }
+        },
+        handleKey (e) {
+            if (e.key === "Enter") {
+                !this.showDiscussion && this.$store.commit(TOGGLE_SHOW_DISCUSSION);
+                !this.focus && this.$store.commit(FOCUS_ON_INPUT);
+                return;
+            }
+            if (e.key === "Escape") {
+                if (this.focus) {
+                    this.$store.commit(USE_FOCUS);
+                } else {
+                    this.$store.commit(TOGGLE_SHOW_DISCUSSION);
+                }
+                return;
+            }
+            if (!this.showDiscussion || !this.focus) {
+                switch (e.key) {
+                    case "ArrowDown":
+                    case "ArrowRight":
+                    case "s":
+                    case "d":
+                    case " ":
+                        this.$store.commit(NEXT_PAGE);
+                        break;
+                    case "ArrowUp":
+                    case "ArrowLeft":
+                    case "w":
+                    case "a":
+                        this.$store.commit(PREVIOUS_PAGE);
+                        break;
+                    case "c":
+                        this.cleanCanvas();
+                        break;
+                    case "q":
+                    case "z":
+                        this.$refs.pointerCanvas.undo();
+                        break;
+                    case "e":
+                    case "y":
+                        this.$refs.pointerCanvas.redo();
+                        break;
+                    case "[":
+                    case "b":
+                        this.box = !this.box;
+                        break;
+                    case "p":
+                    case "v":
+                        this.pointer = !this.pointer;
+                        break;
+                }
+            }
+        },
+        cleanCanvas () {
+            this.$refs.pointerCanvas.cleanCanvas();
+        }
+    },
+};
 
 
 </script>
 
-<!--<style lang="scss" scoped>-->
-<!--    .pdf-reader {-->
-<!--        display: flex;-->
-<!--        align-items: center;-->
-<!--        justify-content: center;-->
-<!--        min-height: 100vh;-->
-<!--    }-->
+<style lang="scss" scoped>
+    .pdf-reader {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        min-height: 100vh;
+    }
 
-<!--    .icon-button {-->
-<!--        z-index: 2;-->
-<!--        position: absolute;-->
-<!--        left: 16px;-->
-<!--        top: 16px;-->
-<!--        background-color: rgba(218, 234, 250, 0.4);-->
-<!--        backdrop-filter: saturate(150%) blur(20px);-->
+    .icon-button {
+        z-index: 2;
+        position: absolute;
+        left: 16px;
+        top: 16px;
+        background-color: rgba(218, 234, 250, 0.4);
+        backdrop-filter: saturate(150%) blur(20px);
 
-<!--        &:hover {-->
-<!--            background-color: rgba(218, 234, 250, 0.67);-->
-<!--        }-->
-<!--    }-->
+        &:hover {
+            background-color: rgba(218, 234, 250, 0.67);
+        }
+    }
 
-<!--    .show-discussion, .hide-discussion {-->
-<!--        transition: .2s;-->
-<!--    }-->
+    .show-discussion, .hide-discussion {
+        transition: .2s;
+    }
 
-<!--    .hide-discussion {-->
-<!--        transform: translateY(100%);-->
-<!--        opacity: 0;-->
-<!--    }-->
+    .hide-discussion {
+        transform: translateY(100%);
+        opacity: 0;
+    }
 
-<!--    .pointer-actions {-->
-<!--        position: fixed;-->
-<!--        left: 6px;-->
-<!--        bottom: 8px;-->
+    .pointer-actions {
+        position: fixed;
+        left: 6px;
+        bottom: 8px;
 
-<!--        .c-button {-->
-<!--            background-color: white;-->
-<!--        }-->
-<!--    }-->
-<!--</style>-->
+        .c-button {
+            background-color: white;
+        }
+    }
+</style>

+ 4 - 4
src/views/ExamPage/ExamDetail.vue

@@ -392,10 +392,10 @@ export default {
     formatTimestamp,
     problemTypeToTagContent,
     jumpToCoderOnlineExam() {
-      ElMessage.info("跳转到coder进行在线考试");
-      let nextURL = "https://coder.seec.seecoder.cn/exam/" + this.exam.id + "?id_token=" + this.$store.state.user.token;
+      let firstQuestionId = this.exam.problems[0].id;
+      // let nextURL = "https://coder.seec.seecoder.cn/exam/" + this.exam.id + "?id_token=" + this.$store.state.user.token; //跳转到Coder
+      let nextURL = `https://ide-test.seec.seecoder.cn/?examId=${this.exam.id}&questionId=${firstQuestionId}&id_token=${this.$store.state.user.token}`;
       window.open(nextURL);
-      //TODO 在Coder中设置路由拦截器,进行token解析
     },
     goToDetect() {
       // ElMessage.error("暂不支持查看查重结果");
@@ -487,7 +487,7 @@ export default {
               message: "参加考试成功!",
               center: true
             });
-            console.log(_res);
+            console.log("参加考试接口返回信息", _res);
             this.fetchExamDetail();
           }).catch(_err => {
         this.$message.error({

+ 9 - 9
vue.config.js

@@ -5,12 +5,12 @@ module.exports = {
   publicPath: process.env.BASE_URL,
   chainWebpack: config => {
     config
-      .plugin("html")
-      .tap(args => {
-        // NOTE 确定系统正式名称
-        args[0].title = "SEEC门户系统";
-        return args;
-      });
+        .plugin("html")
+        .tap(args => {
+          // NOTE 确定系统正式名称
+          args[0].title = "SEEC门户系统";
+          return args;
+        });
   },
   css: {
     loaderOptions: {
@@ -33,8 +33,8 @@ module.exports = {
       port: 8000,
     },
     plugins: process.env.NODE_ENV === "development" ?
-      [
-        new WebpackBar(),
-      ] : []
+        [
+          new WebpackBar(),
+        ] : []
   },
 };

File diff suppressed because it is too large
+ 171 - 126
yarn.lock


Some files were not shown because too many files changed in this diff