Browse Source

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

# Conflicts:
#	package-lock.json
#	src/components/Basic/CButton.vue
#	src/components/Basic/CIcon.vue
#	src/components/Basic/CInput.vue
#	src/components/Basic/CTag.vue
#	src/components/Basic/IconButton.vue
#	src/components/Basic/Ripple.vue
#	src/components/PDF/Pdf.vue
#	src/components/PDF/PdfController.vue
#	src/components/PDF/PdfViewer.vue
#	src/components/PDF/PointerCanvas.vue
#	src/views/CourseWarePage/CourseWarePage.vue
#	yarn.lock
chillqi 3 years ago
parent
commit
85e8cfefe4

+ 14 - 0
src/api/course/course.js

@@ -86,6 +86,18 @@ function uploadCourseImage(name, image) {
   });
 }
 
+function uploadCarouselChart(input){
+  return axios.post(`${prefix}/uploadCarouseChart`,input);
+}
+
+function queryCarouselChart(){
+  return axios.get(`${prefix}/queryCarouselChart`,{
+    params:{
+
+    }
+  });
+}
+
 const courseAPIs = {
   createCourse,
   getAllCourses,
@@ -102,6 +114,8 @@ const courseAPIs = {
   checkCourseCodeUnique,
   getCourseByEvalId,
   uploadCourseImage,
+  uploadCarouselChart,
+  queryCarouselChart
 };
 
 export default courseAPIs;

+ 5 - 0
src/api/user.js

@@ -18,6 +18,10 @@ function resetAPI(data) {
   return axios.post(`${prefix}/resetPassword`, data);
 }
 
+function resetGitlabAPI(data) {
+  return axios.post(`${prefix}/resetGitlabPassword`, data);
+}
+
 function getUserAPI(data){
   return axios.get(`${prefix}/findUserById`, {
     params: {
@@ -59,6 +63,7 @@ const userAPIs = {
   registerAPI,
   sendMessageAPI,
   resetAPI,
+  resetGitlabAPI,
   getUserAPI,
   saveNameAPI,
   saveEmailAPI,

+ 92 - 93
src/components/Basic/CButton.vue

@@ -1,96 +1,95 @@
-<template>
-    <el-button></el-button>
-    <!--  <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>-->
+<!--  <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&#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";-->

+ 9 - 3
src/components/GlobalHeader.vue

@@ -2,7 +2,7 @@
   <div id="global-header-body">
     <el-backtop/>
     <img id="global-header-logo" alt="err" src="@/assets/seec-logo--full.png" @click="toPortal">
-    <el-menu :default-active="activeMenu" mode="horizontal" @select="handleMenuSelect">
+    <el-menu :default-active="activeMenu" mode="horizontal" @select="handleMenuSelect" id="menu">
       <el-menu-item index="1">
         首页
       </el-menu-item>
@@ -190,7 +190,7 @@ export default {
 
 #global-header-logo {
   height: 32px;
-  margin-left: 160px;
+  margin-left: 150px;
   cursor: pointer;
 }
 
@@ -210,9 +210,15 @@ export default {
   bottom: 5px;
 }
 
+#menu li{
+  color: black;
+  border-bottom: none;
+}
+
+
 #global-header-icon {
   width: 120px;
-  margin-right: 160px;
+  margin-right: 150px;
   display: flex;
   justify-content: space-around;
 }

+ 184 - 214
src/views/CourseWarePage/CourseWarePage.vue

@@ -1,231 +1,201 @@
 <template>
 <el-row id="manage-page-body">
-<!--    <div class="pdf-reader">-->
-<!--        <el-button type="info" circle @click="this.$router.go(-1)" class="mybuttton"><el-icon class="myicon"><Back /></el-icon></el-button>-->
-<!--        <div class="container">-->
-<!--            <iframe :src="pdfurl" width="100%" height="100%"></iframe>-->
-<!--        </div>-->
-
-<!--        <img :src="imageUrl" alt="" class="image">-->
-<!--        <canvas class="pdf pdf-canvas" id="pdf-canvas"></canvas>-->
-
-<!--        <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 :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>
-// 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";
-// 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: {
-//      //   CButton,
-//      //   PointerCanvas,
-//     //   PdfViewer
-//     },
-//     computed: {
-//         ...mapState({
-//             src: state => state.pdf.src,
-//             focus: state => state.pdf.focus,
-//             currentPage: state => state.pdf.currentPage,
-//             screenShot: state => state.pdf.screenShot,
-//         }),
-//         imageUrl() {
-//             //return "https://seec-portal.oss-cn-hangzhou.aliyuncs.com/1/1bc3ed2e423eec0.jpg" + "?t=" + Date.now().valueOf();
-//             return "https://seec-portal.oss-cn-hangzhou.aliyuncs.com/1/8610161.jpg";
-//         },
-//     },
-//     data () {
-//         return {
-//             pdfurl:"",
-//             courseWare: {}
-//         };
-//     },
-//     watch: {
-//         currentPage() {
-//             this.showPage();
-//         }
-//     },
-//     async mounted() {
-//         console.log("coursewarepage");
-//         console.log(this.$route.params.courseWareId);
-//         this.$store.commit(RESET);
-//         let {page} = this.$route.params.page;
-//         if (page) {
-//             this.$store.commit(SET_CURRENT_PAGE, {currentPage: parseInt(page)});
-//         }
-//         this.courseWare = (await this.$apis.getSlideInfo(this.$route.params.courseWareId)).data.data;
-//         this.pdfurl = (await this.$apis.getSlideUrl(this.$route.params.courseWareId)).data.data;
-//         this.$store.commit(SET_SRC, {src: this.pdfurl});
-//         window.addEventListener("keydown", this.handleKey);
-//
-//         this._canvas = document.getElementById("pdf-canvas");
-//         this._context = this._canvas.getContext("2d");
-//
-//         this.load(this.pdfurl);
-//     },
-//     beforeUnmount () {
-//         window.removeEventListener("keydown", this.handleKey);
-//     },
-//     methods: {
-//         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;
-//                 }
-//             }
-//         },
-//         load(src) {
-//             console.log("load:" + src.substring(48));
-//             const loadingTask = pdfJS.getDocument("/api/slide" + src.substring(48));
-//             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 当前页解析错误')
-//             });
-//         }
-//     },
-// };
+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;-->
-<!--    }-->
-
-<!--    .mybuttton {-->
-<!--        position: absolute;-->
-<!--        left: 16px;-->
-<!--        top: 16px;-->
-<!--        background-color: rgba(160, 180, 200, .1);-->
-<!--        color: #7a8a9a;-->
-<!--        align-items: center;-->
-<!--        justify-content: center;-->
-<!--        padding: 8px;-->
-<!--        width: 44px;-->
-<!--        height: 44px;-->
-<!--        &:hover {-->
-<!--            background-color: rgba(218, 234, 250, 0.67);-->
-<!--        }-->
-<!--    }-->
+</script>
 
-<!--    .myicon {-->
-<!--        font-size: 25px;-->
-<!--    }-->
+<style lang="scss" scoped>
+    .pdf-reader {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        min-height: 100vh;
+    }
 
-<!--    .show-discussion, .hide-discussion {-->
-<!--        transition: .2s;-->
-<!--    }-->
+    .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);
 
-<!--    .hide-discussion {-->
-<!--        transform: translateY(100%);-->
-<!--        opacity: 0;-->
-<!--    }-->
+        &:hover {
+            background-color: rgba(218, 234, 250, 0.67);
+        }
+    }
 
-<!--    .pointer-actions {-->
-<!--        position: fixed;-->
-<!--        left: 6px;-->
-<!--        bottom: 8px;-->
+    .show-discussion, .hide-discussion {
+        transition: .2s;
+    }
 
-<!--        .c-button {-->
-<!--            background-color: white;-->
-<!--        }-->
-<!--    }-->
-<!--</style>-->
+    .hide-discussion {
+        transform: translateY(100%);
+        opacity: 0;
+    }
 
+    .pointer-actions {
+        position: fixed;
+        left: 6px;
+        bottom: 8px;
 
+        .c-button {
+            background-color: white;
+        }
+    }
+</style>

+ 11 - 3
src/views/HomePage/HomePage.vue

@@ -21,25 +21,33 @@
             </el-icon>
             <span style="padding-left: 20px">身份认证</span>
           </el-menu-item>
+          <el-menu-item index="3">
+            <el-icon>
+              <Files/>
+            </el-icon>
+            <span style="padding-left: 20px">gitlab</span>
+          </el-menu-item>
         </el-menu>
       </el-card>
     </el-col>
     <el-col :span="2"/>
     <el-col :span="18">
       <InformationCard v-if="activeIndex==='1'"/>
-      <CertificationCard v-else/>
+      <CertificationCard v-else-if="activeIndex==='2'"/>
+      <GitlabCard v-else/>
     </el-col>
   </el-row>
 </template>
 
 <script>
-import { Back, Medal, User } from "@element-plus/icons-vue";
+import { Back, Medal, User , Files } from "@element-plus/icons-vue";
 import InformationCard from "@/views/HomePage/components/InformationCard";
 import CertificationCard from "@/views/HomePage/components/CertificationCard";
+import GitlabCard from "@/views/HomePage/components/GitlabCard";
 
 export default {
   name: "HomePage",
-  components: { Back, CertificationCard, InformationCard, Medal, User, },
+  components: { Back, CertificationCard, GitlabCard, InformationCard, Medal, User, Files},
   data() {
     return {
       activeIndex: "1",

+ 331 - 0
src/views/HomePage/components/GitlabCard.vue

@@ -0,0 +1,331 @@
+<template>
+  <el-form id="auth-card-form" ref="cardFormRef" :model="cardForm" :rules="cardFormRule" >
+
+  <el-card id="gitlab-card-body" >
+    <template #header>
+      <span style="font-weight: bold; font-size: larger">
+        gitlab基本信息
+      </span>
+    </template>
+
+    <div>
+      <el-form-item class="item" prop="username">
+      <el-row class="row">
+        <el-col :span="3" class="title">
+          用户名
+        </el-col>
+        <el-col :span="6">
+          <el-input v-model="user.username" class="content" disabled/>
+        </el-col>
+      </el-row>
+      </el-form-item>
+    </div>
+
+    <div>
+      <el-form-item class="item" prop="email">
+      <el-row class="row">
+        <el-col :span="3" class="title">
+          邮箱
+        </el-col>
+        <el-col :span="10">
+          <el-input v-model="user.email" class="content" disabled/>
+        </el-col>
+      </el-row>
+      </el-form-item>
+    </div>
+
+    <div>
+      <el-form-item class="item" prop="phone">
+      <el-row class="row">
+        <el-col :span="3" class="title">
+          手机号
+        </el-col>
+        <el-col :span="6">
+          <el-input v-model="cardForm.phone" class="content" placeholder="请输入手机号"/>
+        </el-col>
+      </el-row>
+      </el-form-item>
+    </div>
+
+    <div>
+      <el-form-item class="item" prop="password">
+      <el-row class="row">
+        <el-col :span="3" class="title">
+          新密码
+        </el-col>
+        <el-col :span="6">
+          <el-input v-model="cardForm.password" class="content" show-password placeholder="请输入新密码"/>
+        </el-col>
+      </el-row>
+      </el-form-item>
+    </div>
+
+    <div>
+      <el-form-item class="item" prop="passwordConfirm">
+      <el-row class="row">
+        <el-col :span="3" class="title">
+          确认密码
+        </el-col>
+        <el-col :span="6">
+          <el-input v-model="cardForm.passwordConfirm" class="content" show-password placeholder="请确认新密码" />
+        </el-col>
+      </el-row>
+      </el-form-item>
+    </div>
+
+    <div>
+      <el-form-item class="item" prop="identifyCode">
+      <el-row class="row">
+        <el-col :span="3" class="title">
+          验证码
+        </el-col>
+        <el-col :span="6">
+          <el-input v-model="cardForm.identifyCode" class="content" show-password placeholder="请输入验证码" />
+        </el-col>
+        <el-button class="button" id="auth-card-code-verifier-button" :disabled="cardButtonDisabled" @click="handleSendMessage">
+          {{ cardButtonText }}
+        </el-button>
+      </el-row>
+      </el-form-item>
+    </div>
+
+    <div class="row">
+      <el-button @click="handleReset">重置gitlab密码</el-button>
+    </div>
+  </el-card>
+    </el-form>
+</template>
+
+<script>
+
+export default {
+  name: "GitlabCard",
+  data() {
+    const inputNumberValidator = (rule, value, callback) => {
+      if (!(/(^[1-9]\d*$)/.test(value))) {
+        callback(new Error("请勿输入非数字"));
+      } else {
+        callback();
+      }
+    };
+    const passwordConfirmValidator = (rule, value, callback) => {
+      if (value !== this.cardForm.password) {
+        callback(new Error("请输入相同的密码"));
+      } else {
+        callback();
+      }
+    };
+    const phoneValidator = (rule, value, callback) => {
+      if (/^(13\d|14\d|15\d|166|18\d|19[6,9]|17\d)\d{8}$/i.test(value) === false) {
+        callback(new Error("请输入正确格式的手机号"));
+      } else {
+        callback();
+      }
+    };
+    const identifyCodeValidator = (rule, value, callback) => {
+      if (value.length !== 6) {
+        this.shakeElem("auth-card-code-verifier");
+        callback(new Error("请正确输入短信验证码"));
+      } else {
+        this.cardVerified = true;
+        callback();
+      }
+    };
+    return {
+      cardForm: {
+        phone: "",
+        name: "",
+        username: "",
+        email: "",
+        password: "",
+        passwordConfirm: "",
+        identifyCode: "",
+      },
+      cardButtonText: "获取验证码",
+      cardButtonDisabled: false,
+      cardVerified: false,
+      cardFormRule: {
+        phone: [
+          {required: true, message: "请输入手机号", trigger: "blur"},
+          {
+            validator: phoneValidator,
+            trigger: "blur"
+          },
+          {
+            validator: inputNumberValidator,
+            trigger: "change"
+          }
+        ],
+        password: [
+          {
+            required: true,
+            message: "请输入密码",
+            trigger: "blur",
+          },
+          {
+            min: 8,
+            max: 20,
+            message: "密码长度应为8-20个字符",
+            trigger: "blur",
+          }
+        ],
+        passwordConfirm: [
+          {required: true, message: "请再次输入密码", trigger: "blur"},
+          {
+            validator: passwordConfirmValidator,
+            trigger: "blur"
+          }
+        ],
+        identifyCode: [
+          {
+            validator: identifyCodeValidator,
+            trigger: "blur",
+          },
+          {
+            validator: inputNumberValidator,
+            trigger: "change",
+          }
+        ]
+      },
+    };
+  },
+  computed: {
+    user() {
+      return this.$store.state.user;
+    },
+    name() {
+      return this.$store.state.user.name;
+    },
+    email() {
+      return this.$store.state.user.email;
+    },
+  },
+  methods: {
+    handleSendMessage() {
+      const thatForm = this.$refs.cardFormRef;
+      thatForm.validateField("phone", v1 => {
+        if (!v1) {
+          this.cardButtonDisabled = true;
+          let time = 60;
+          const myScroll = setInterval(() => {
+            time--;
+            if (time >= 0) {
+              this.cardButtonText = time + "s后可重发";
+            } else {
+              this.cardButtonText = "获取验证码";
+              this.cardButtonDisabled = false;
+              clearTimeout(myScroll);
+              time = 60;
+            }
+          }, 1000);
+          const params = {
+            phone: this.cardForm.phone
+          };
+          console.log(params);
+          this.$apis.sendMessageAPI(params)
+              .then((res) => {
+                if (res.data.code === 0) {
+                  this.$message({
+                    showClose: true,
+                    message: "发送成功,请注意查收验证码",
+                    type: "success"
+                  });
+                } else {
+                  this.$message({
+                    showClose: true,
+                    message: res.data.message,
+                    type: "warning"
+                  });
+                }
+              })
+              .catch((e) => {
+                this.$message({
+                  showClose: true,
+                  message: e,
+                  type: "error"
+                });
+              });
+        }
+      });
+    },
+    shakeElem(elemId) {
+      let elem = document.getElementById(elemId);
+      elem.classList.add("shake");
+      setTimeout(() => {
+        elem.classList.remove("shake");
+      }, 800);
+    },
+    handleReset() {
+      const thatForm = this.$refs.cardFormRef;
+      thatForm.validateField("password", v1 => {
+        thatForm.validateField("passwordConfirm", v2 => {
+          thatForm.validateField("phone", v3 => {
+            thatForm.validateField("identifyCode", v4 => {
+              if (!v1 && !v2 && !v3 && !v4) {
+                if (this.cardVerified) {
+                  const params = {
+                    password: this.cardForm.password,
+                    identifyCode: this.cardForm.identifyCode,
+                    phone: this.cardForm.phone,
+                  };
+                  this.$apis.resetGitlabAPI(params)
+                      .then((res) => {
+                        if (res.data.code === 0) {
+                          this.$message({
+                            showClose: true,
+                            message: "重置成功",
+                            type: "success"
+                          });
+                        } else {
+                          this.$message({
+                            showClose: true,
+                            message: res.data.message,
+                            type: "warning"
+                          });
+                        }
+                      })
+                      .catch((e) => {
+                        this.$message({
+                          showClose: true,
+                          message: e,
+                          type: "error"
+                        });
+                      });
+                } else {
+                  this.shakeElem("auth-card-code-verifier");
+                }
+              }
+            });
+          });
+        });
+      });
+    },
+  }
+};
+</script>
+
+<style scoped>
+:deep(.el-card__body) {
+  padding: 48px;
+  display: grid;
+  grid-gap: 24px;
+}
+
+.title {
+  font-size: medium;
+}
+
+.row {
+  display: flex;
+  align-items: baseline;
+}
+
+.button {
+  margin-left: 24px;
+}
+
+.item {
+  padding: 0px;
+}
+
+</style>

+ 8 - 1
src/views/PortalPage/PortalPage.vue

@@ -1,4 +1,6 @@
 <template>
+
+  <PhotoChange></PhotoChange>
   <div id="portal-body">
 
     <CarouselCard style="grid-column-start: 1; grid-column-end: 3;"/>
@@ -171,6 +173,7 @@ import MyCourseCard from "@/views/PortalPage/components/MyCourseCard";
 import MyTestCard from "@/views/PortalPage/components/MyTestCard";
 import { FolderOpened, Lock, SetUp, ShoppingCart } from "@element-plus/icons-vue";
 import TestCard from "@/components/TestCard";
+import PhotoChange from "@/views/PortalPage/components/PhotoChange";
 
 export default {
   //数据
@@ -184,7 +187,8 @@ export default {
     MyTestCard,
     CourseCard,
     CarouselCard,
-    MyCourseCard
+    MyCourseCard,
+    PhotoChange
   },
   data() {
     return {
@@ -211,6 +215,9 @@ export default {
     isStudent() {
       return this.$store.getters.isStudent;
     },
+    isAdmin(){
+      return this.$store.state.user.role==="ADMIN";
+    },
     myTestList() {
       return []
         .concat(this.myEvalExamList)

+ 5 - 5
src/views/PortalPage/components/CarouselCard.vue

@@ -17,14 +17,14 @@ export default {
         require("@/assets/carousel-SE2.png"),
         require("@/assets/seec-banner.png"),
       ],
-      link:[]
+      link:[],
     };
   },
   async created() {
-    const exampleClasses = (await this.$apis.getExampleCourses()).data.data;
-    for (let i=0; i<Math.min(exampleClasses.length,3); i++){
-      this.contents[i]=exampleClasses[i].imageUrl;
-      this.link[i]=exampleClasses[i].id;
+    const rootPoint = (await this.$apis.queryCarouselChart()).data.data;
+    for (let i = 0; i < rootPoint.length; i++) {
+      this.contents[i] = rootPoint[i].imageUrl;
+      this.link[i] = rootPoint[i].id;
     }
     this.$forceUpdate();
   },

+ 58 - 0
src/views/PortalPage/components/PhotoChange.vue

@@ -0,0 +1,58 @@
+<template>
+  <el-card style="text-align: center;" v-if="isAdmin" @click="this.seeDialog=true">
+    点我修改轮播图
+  </el-card>
+  <el-dialog v-model="seeDialog">
+    <div>请慎重上传!上传到服务器后会直接覆盖原有信息!</div>
+    <div>
+      <el-input v-model="input[0]" placeholder="请输入课程名" style="margin: 10px;left: -10px;"></el-input>
+      <el-input v-model="input[1]" placeholder="请输入课程名" style="margin: 10px;left: -10px;"></el-input>
+      <el-input v-model="input[2]" placeholder="请输入课程名" style="margin: 10px;left: -10px;"></el-input>
+    </div>
+    <el-button style="margin: 10px;" size="small" type="success" @click="updatePictures" >上传到服务器</el-button>
+  </el-dialog>
+</template>
+
+<script>
+import {ElMessage} from "element-plus";
+
+export default {
+  name: "PhotoChange",
+  data() {
+    return {
+      fileList: [],
+      seeDialog: false,
+      input: ["","",""],
+    };
+  },
+  computed:{
+    isAdmin(){
+      return this.$store.state.user.role==="ADMIN";
+    },
+  },
+  methods: {
+    handleExceed(files, fileList) {
+      ElMessage.error("最多展示3个文件!");
+    },
+    async updatePictures() {
+      const message=await this.$apis.uploadCarouselChart(this.input);
+      if (message.data.code===-1){
+        ElMessage.error("课程不存在!");
+      }else if (message.data.data===true){
+        ElMessage.success("上传成功!");
+      }else {
+        ElMessage.error("上传失败!后端报错");
+      }
+      this.seeDialog=false;
+      this.input=["","",""];
+    },
+    handleChange(file, fileList) {
+      this.fileList = fileList;
+    }
+  }
+};
+</script>
+
+<style scoped>
+
+</style>