Tang 2 rokov pred
rodič
commit
fb76f4fc73

+ 30 - 22
src/apis/apply.js

@@ -1,24 +1,24 @@
 import request from '@/axios'
 export default {
-  //点击预约报考按钮
-  getApplysubscribe(data) {
-    return request({
-      url: '/apply/subscribe',
-      method: 'get',
-      params: data
-    })
-  },
+	//点击预约报考按钮
+	getApplysubscribe(data) {
+		return request({
+			url: '/apply/subscribe',
+			method: 'get',
+			params: data
+		})
+	},
 
-  //预约报考下一步按钮 1 进入有考陪有考试地点得预约考试 2进入无考陪有考试地点预约考试 3无考试次数购买商品
-  getApplysubscribeNext(data) {
-    return request({
-      url: '/apply/subscribeNext',
-      method: 'get',
-      params: data
-    })
-  },
+	//预约报考下一步按钮 1 进入有考陪有考试地点得预约考试 2进入无考陪有考试地点预约考试 3无考试次数购买商品
+	getApplysubscribeNext(data) {
+		return request({
+			url: '/apply/subscribeNext',
+			method: 'get',
+			params: data
+		})
+	},
 
-  //获得考试的考试地点
+	//获得考试的考试地点
 	getApplysubscribeApplySite(data) {
 		return request({
 			url: '/apply/subscribeApplySite',
@@ -26,7 +26,7 @@ export default {
 			params: data
 		})
 	},
-  //获得考试的考培地点
+	//获得考试的考培地点
 	getApplysubscribeApplySiteTrain(data) {
 		return request({
 			url: '/apply/subscribeApplySiteTrain',
@@ -35,7 +35,7 @@ export default {
 		})
 	},
 
-  //新增用户预约考试
+	//新增用户预约考试
 	addApply(data) {
 		return request({
 			// url: '/apply',
@@ -45,7 +45,7 @@ export default {
 		})
 	},
 
-  //查询报考数据列表
+	//查询报考数据列表
 	getApplylist(data) {
 		return request({
 			url: '/apply/list',
@@ -53,8 +53,16 @@ export default {
 			params: data
 		})
 	},
+	//考前须知
+	applybeforeknow(data) {
+		return request({
+			url: '/apply/before/know',
+			method: 'get',
+			params: data
+		})
+	},
+
 
-  
 	//修改用户预约考试
 	editApply(data) {
 		return request({
@@ -64,7 +72,7 @@ export default {
 		})
 	},
 
-  //查询报考数据列表
+	//查询报考数据列表
 	getApplylist(data) {
 		return request({
 			url: '/apply/list',

+ 20 - 2
src/apis/course.js

@@ -28,14 +28,14 @@ export default {
 			params: data
 		})
 	},
-	
+
 	/**
 	 * 
 	 * @param {*} data 
 	 * @returns 
 	 * 检查二建二造用户是否学完必修
 	 */
-	 goodsGradeCheckFinishRequiredCourse(data) {
+	goodsGradeCheckFinishRequiredCourse(data) {
 		return request({
 			url: '/grade/grade/checkFinishRequiredCourse',
 			method: 'get',
@@ -372,4 +372,22 @@ export default {
 			params: data
 		})
 	},
+	// 查询用户拥有的讲义商品
+	courseGoodsHandoutsList(data) {
+		return request({
+			url: '/course/goodsHandoutsList',
+			method: 'get',
+			params: data
+		})
+	},
+	//获取讲义列详细信息去地址
+	coursehandoutsfiledetail(data) {
+		return request({
+			url: '/app/common/course/handouts/file/detail',
+			method: 'get',
+			noToken: true,
+			params: data
+		})
+	},
+
 }

+ 104 - 69
src/apis/login.js

@@ -9,18 +9,18 @@ export default {
   login(data) {
     return request({
       url: '/app/common/account_login',
-			method: 'post',
-			data: data,
-			noToken: true
+      method: 'post',
+      data: data,
+      noToken: true
     })
   },
 
   skipLogin(data) {
     return request({
       url: '/app/common/telphone_login',
-			method: 'post',
-			data: data,
-			noToken: true
+      method: 'post',
+      data: data,
+      noToken: true
     })
   },
   /**
@@ -32,9 +32,9 @@ export default {
   getLoginSms(data) {
     return request({
       url: '/app/common/sms/login',
-			method: 'post',
-			data: data,
-			noToken: true
+      method: 'post',
+      data: data,
+      noToken: true
     })
   },
   /**
@@ -46,9 +46,9 @@ export default {
   loginSms(data) {
     return request({
       url: '/app/common/sms_login',
-			method: 'post',
-			data: data,
-			noToken: true
+      method: 'post',
+      data: data,
+      noToken: true
     })
   },
   /**
@@ -56,12 +56,12 @@ export default {
    * @returns 获取用户登录信息
    */
   getInfo(data) {
-		return request({
-			url: '/app/user/getInfo',
-			method: 'get',
-      params:data,
-		})
-	},
+    return request({
+      url: '/app/user/getInfo',
+      method: 'get',
+      params: data,
+    })
+  },
 
   /**
    * 
@@ -69,14 +69,14 @@ export default {
    * @returns 
    * 注册用户
    */
-	registerUser(data) {
-		return request({
-			url: '/app/common/register_small',
-			method: 'post',
-			data: data,
-			noToken: true
-		})
-	},
+  registerUser(data) {
+    return request({
+      url: '/app/common/register_small',
+      method: 'post',
+      data: data,
+      noToken: true
+    })
+  },
 
   /**
    * 
@@ -84,18 +84,18 @@ export default {
    * @returns 
    * 绑定身份证号信息
    */
-   bindIdCard(data) {
-		return request({
-      token:data.token,
-      headers:{
-        AuthorizationToken:"WX "+data.token
+  bindIdCard(data) {
+    return request({
+      token: data.token,
+      headers: {
+        AuthorizationToken: "WX " + data.token
       },
-      noToken:true,
-			url: '/app/user/bind_idcard',
-			method: 'post',
-			data: data
-		})
-	},
+      noToken: true,
+      url: '/app/user/bind_idcard',
+      method: 'post',
+      data: data
+    })
+  },
 
   /**
    * 
@@ -104,13 +104,13 @@ export default {
    * 获取注册短信
    */
   getRegisterSms(data) {
-		return request({
-			url: '/app/common/sms/register',
-			method: 'post',
-			data: data,
-			noToken: true
-		})
-	},
+    return request({
+      url: '/app/common/sms/register',
+      method: 'post',
+      data: data,
+      noToken: true
+    })
+  },
 
   /**
    * 
@@ -118,39 +118,74 @@ export default {
    * @returns 
    * 找回密码
    */
-	forgetUser(data) {
-		return request({
-			url: '/app/common/register_forget',
-			method: 'post',
-			data: data,
-			noToken: true
-		})
-	},
-  
+  forgetUser(data) {
+    return request({
+      url: '/app/common/register_forget',
+      method: 'post',
+      data: data,
+      noToken: true
+    })
+  },
+
   /**
    * 
    * @param {*} data 
    * @returns 
    * 获取找回密码短信
    */
-   getRegisterSmsforget(data) {
-		return request({
-			url: '/app/common/sms/forget',
-			method: 'post',
-			data: data,
-			noToken: true
-		})
-	},
+  getRegisterSmsforget(data) {
+    return request({
+      url: '/app/common/sms/forget',
+      method: 'post',
+      data: data,
+      noToken: true
+    })
+  },
   /**
    * 
    * @returns 获取用户登录是否需要验证码
    */
-   dualAuth(data) {
-		return request({
-			url: '/app/common/dual_auth',
-			method: 'get',
-      params:data,
-			noToken: true
-		})
-	},
+  dualAuth(data) {
+    return request({
+      url: '/app/common/dual_auth',
+      method: 'get',
+      params: data,
+      noToken: true
+    })
+  },
+  /**
+   * 
+   * @returns 刷新令牌
+   */
+  refreshTokendata(data) {
+    return request({
+      url: '/refreshToken/' + data,
+      method: 'get',
+      noToken: true
+    })
+  },
+  /**
+   * 
+   * @returns 获取7个工作日后的时间戳
+   */
+  get7dayAfterTime(data) {
+    return request({
+      url: '/app/common/live/time',
+      method: 'get',
+      noToken: true
+    })
+  },
+  /**
+   * 
+   * @returns 免登
+   */
+  account_login(data) {
+    return request({
+      url: '/app/common/automatic/account_login',
+      method: 'post',
+      data: data,
+      noToken: true
+    })
+  },
+
 }

+ 397 - 0
src/assets/css/quill.core.css

@@ -0,0 +1,397 @@
+/*!
+ * Quill Editor v1.3.7
+ * https://quilljs.com/
+ * Copyright (c) 2014, Jason Chen
+ * Copyright (c) 2013, salesforce.com
+ */
+.ql-container {
+  box-sizing: border-box;
+  font-family: Helvetica, Arial, sans-serif;
+  font-size: 13px;
+  height: 100%;
+  margin: 0px;
+  position: relative;
+}
+.ql-container.ql-disabled .ql-tooltip {
+  visibility: hidden;
+}
+.ql-container.ql-disabled .ql-editor ul[data-checked] > li::before {
+  pointer-events: none;
+}
+.ql-clipboard {
+  left: -100000px;
+  height: 1px;
+  overflow-y: hidden;
+  position: absolute;
+  top: 50%;
+}
+.ql-clipboard p {
+  margin: 0;
+  padding: 0;
+}
+.ql-editor {
+  box-sizing: border-box;
+  line-height: 1.42;
+  height: 100%;
+  outline: none;
+  overflow-y: auto;
+  padding: 12px 15px;
+  tab-size: 4;
+  -moz-tab-size: 4;
+  text-align: left;
+  white-space: pre-wrap;
+  word-wrap: break-word;
+}
+.ql-editor > * {
+  cursor: text;
+}
+.ql-editor p,
+.ql-editor ol,
+.ql-editor ul,
+.ql-editor pre,
+.ql-editor blockquote,
+.ql-editor h1,
+.ql-editor h2,
+.ql-editor h3,
+.ql-editor h4,
+.ql-editor h5,
+.ql-editor h6 {
+  margin: 0;
+  padding: 0;
+  counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
+}
+.ql-editor ol,
+.ql-editor ul {
+  padding-left: 1.5em;
+}
+.ql-editor ol > li,
+.ql-editor ul > li {
+  list-style-type: none;
+}
+.ql-editor ul > li::before {
+  content: '\2022';
+}
+.ql-editor ul[data-checked=true],
+.ql-editor ul[data-checked=false] {
+  pointer-events: none;
+}
+.ql-editor ul[data-checked=true] > li *,
+.ql-editor ul[data-checked=false] > li * {
+  pointer-events: all;
+}
+.ql-editor ul[data-checked=true] > li::before,
+.ql-editor ul[data-checked=false] > li::before {
+  color: #777;
+  cursor: pointer;
+  pointer-events: all;
+}
+.ql-editor ul[data-checked=true] > li::before {
+  content: '\2611';
+}
+.ql-editor ul[data-checked=false] > li::before {
+  content: '\2610';
+}
+.ql-editor li::before {
+  display: inline-block;
+  white-space: nowrap;
+  width: 1.2em;
+}
+.ql-editor li:not(.ql-direction-rtl)::before {
+  margin-left: -1.5em;
+  margin-right: 0.3em;
+  text-align: right;
+}
+.ql-editor li.ql-direction-rtl::before {
+  margin-left: 0.3em;
+  margin-right: -1.5em;
+}
+.ql-editor ol li:not(.ql-direction-rtl),
+.ql-editor ul li:not(.ql-direction-rtl) {
+  padding-left: 1.5em;
+}
+.ql-editor ol li.ql-direction-rtl,
+.ql-editor ul li.ql-direction-rtl {
+  padding-right: 1.5em;
+}
+.ql-editor ol li {
+  counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
+  counter-increment: list-0;
+}
+.ql-editor ol li:before {
+  content: counter(list-0, decimal) '. ';
+}
+.ql-editor ol li.ql-indent-1 {
+  counter-increment: list-1;
+}
+.ql-editor ol li.ql-indent-1:before {
+  content: counter(list-1, lower-alpha) '. ';
+}
+.ql-editor ol li.ql-indent-1 {
+  counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
+}
+.ql-editor ol li.ql-indent-2 {
+  counter-increment: list-2;
+}
+.ql-editor ol li.ql-indent-2:before {
+  content: counter(list-2, lower-roman) '. ';
+}
+.ql-editor ol li.ql-indent-2 {
+  counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
+}
+.ql-editor ol li.ql-indent-3 {
+  counter-increment: list-3;
+}
+.ql-editor ol li.ql-indent-3:before {
+  content: counter(list-3, decimal) '. ';
+}
+.ql-editor ol li.ql-indent-3 {
+  counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
+}
+.ql-editor ol li.ql-indent-4 {
+  counter-increment: list-4;
+}
+.ql-editor ol li.ql-indent-4:before {
+  content: counter(list-4, lower-alpha) '. ';
+}
+.ql-editor ol li.ql-indent-4 {
+  counter-reset: list-5 list-6 list-7 list-8 list-9;
+}
+.ql-editor ol li.ql-indent-5 {
+  counter-increment: list-5;
+}
+.ql-editor ol li.ql-indent-5:before {
+  content: counter(list-5, lower-roman) '. ';
+}
+.ql-editor ol li.ql-indent-5 {
+  counter-reset: list-6 list-7 list-8 list-9;
+}
+.ql-editor ol li.ql-indent-6 {
+  counter-increment: list-6;
+}
+.ql-editor ol li.ql-indent-6:before {
+  content: counter(list-6, decimal) '. ';
+}
+.ql-editor ol li.ql-indent-6 {
+  counter-reset: list-7 list-8 list-9;
+}
+.ql-editor ol li.ql-indent-7 {
+  counter-increment: list-7;
+}
+.ql-editor ol li.ql-indent-7:before {
+  content: counter(list-7, lower-alpha) '. ';
+}
+.ql-editor ol li.ql-indent-7 {
+  counter-reset: list-8 list-9;
+}
+.ql-editor ol li.ql-indent-8 {
+  counter-increment: list-8;
+}
+.ql-editor ol li.ql-indent-8:before {
+  content: counter(list-8, lower-roman) '. ';
+}
+.ql-editor ol li.ql-indent-8 {
+  counter-reset: list-9;
+}
+.ql-editor ol li.ql-indent-9 {
+  counter-increment: list-9;
+}
+.ql-editor ol li.ql-indent-9:before {
+  content: counter(list-9, decimal) '. ';
+}
+.ql-editor .ql-indent-1:not(.ql-direction-rtl) {
+  padding-left: 3em;
+}
+.ql-editor li.ql-indent-1:not(.ql-direction-rtl) {
+  padding-left: 4.5em;
+}
+.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right {
+  padding-right: 3em;
+}
+.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right {
+  padding-right: 4.5em;
+}
+.ql-editor .ql-indent-2:not(.ql-direction-rtl) {
+  padding-left: 6em;
+}
+.ql-editor li.ql-indent-2:not(.ql-direction-rtl) {
+  padding-left: 7.5em;
+}
+.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right {
+  padding-right: 6em;
+}
+.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right {
+  padding-right: 7.5em;
+}
+.ql-editor .ql-indent-3:not(.ql-direction-rtl) {
+  padding-left: 9em;
+}
+.ql-editor li.ql-indent-3:not(.ql-direction-rtl) {
+  padding-left: 10.5em;
+}
+.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right {
+  padding-right: 9em;
+}
+.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right {
+  padding-right: 10.5em;
+}
+.ql-editor .ql-indent-4:not(.ql-direction-rtl) {
+  padding-left: 12em;
+}
+.ql-editor li.ql-indent-4:not(.ql-direction-rtl) {
+  padding-left: 13.5em;
+}
+.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right {
+  padding-right: 12em;
+}
+.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right {
+  padding-right: 13.5em;
+}
+.ql-editor .ql-indent-5:not(.ql-direction-rtl) {
+  padding-left: 15em;
+}
+.ql-editor li.ql-indent-5:not(.ql-direction-rtl) {
+  padding-left: 16.5em;
+}
+.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right {
+  padding-right: 15em;
+}
+.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right {
+  padding-right: 16.5em;
+}
+.ql-editor .ql-indent-6:not(.ql-direction-rtl) {
+  padding-left: 18em;
+}
+.ql-editor li.ql-indent-6:not(.ql-direction-rtl) {
+  padding-left: 19.5em;
+}
+.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right {
+  padding-right: 18em;
+}
+.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right {
+  padding-right: 19.5em;
+}
+.ql-editor .ql-indent-7:not(.ql-direction-rtl) {
+  padding-left: 21em;
+}
+.ql-editor li.ql-indent-7:not(.ql-direction-rtl) {
+  padding-left: 22.5em;
+}
+.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right {
+  padding-right: 21em;
+}
+.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right {
+  padding-right: 22.5em;
+}
+.ql-editor .ql-indent-8:not(.ql-direction-rtl) {
+  padding-left: 24em;
+}
+.ql-editor li.ql-indent-8:not(.ql-direction-rtl) {
+  padding-left: 25.5em;
+}
+.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right {
+  padding-right: 24em;
+}
+.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right {
+  padding-right: 25.5em;
+}
+.ql-editor .ql-indent-9:not(.ql-direction-rtl) {
+  padding-left: 27em;
+}
+.ql-editor li.ql-indent-9:not(.ql-direction-rtl) {
+  padding-left: 28.5em;
+}
+.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right {
+  padding-right: 27em;
+}
+.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right {
+  padding-right: 28.5em;
+}
+.ql-editor .ql-video {
+  display: block;
+  max-width: 100%;
+}
+.ql-editor .ql-video.ql-align-center {
+  margin: 0 auto;
+}
+.ql-editor .ql-video.ql-align-right {
+  margin: 0 0 0 auto;
+}
+.ql-editor .ql-bg-black {
+  background-color: #000;
+}
+.ql-editor .ql-bg-red {
+  background-color: #e60000;
+}
+.ql-editor .ql-bg-orange {
+  background-color: #f90;
+}
+.ql-editor .ql-bg-yellow {
+  background-color: #ff0;
+}
+.ql-editor .ql-bg-green {
+  background-color: #008a00;
+}
+.ql-editor .ql-bg-blue {
+  background-color: #06c;
+}
+.ql-editor .ql-bg-purple {
+  background-color: #93f;
+}
+.ql-editor .ql-color-white {
+  color: #fff;
+}
+.ql-editor .ql-color-red {
+  color: #e60000;
+}
+.ql-editor .ql-color-orange {
+  color: #f90;
+}
+.ql-editor .ql-color-yellow {
+  color: #ff0;
+}
+.ql-editor .ql-color-green {
+  color: #008a00;
+}
+.ql-editor .ql-color-blue {
+  color: #06c;
+}
+.ql-editor .ql-color-purple {
+  color: #93f;
+}
+.ql-editor .ql-font-serif {
+  font-family: Georgia, Times New Roman, serif;
+}
+.ql-editor .ql-font-monospace {
+  font-family: Monaco, Courier New, monospace;
+}
+.ql-editor .ql-size-small {
+  font-size: 0.75em;
+}
+.ql-editor .ql-size-large {
+  font-size: 1.5em;
+}
+.ql-editor .ql-size-huge {
+  font-size: 2.5em;
+}
+.ql-editor .ql-direction-rtl {
+  direction: rtl;
+  text-align: inherit;
+}
+.ql-editor .ql-align-center {
+  text-align: center;
+}
+.ql-editor .ql-align-justify {
+  text-align: justify;
+}
+.ql-editor .ql-align-right {
+  text-align: right;
+}
+.ql-editor.ql-blank::before {
+  color: rgba(0,0,0,0.6);
+  content: attr(data-placeholder);
+  font-style: italic;
+  left: 15px;
+  pointer-events: none;
+  position: absolute;
+  right: 15px;
+}

+ 2 - 0
src/common/eventBus.js

@@ -0,0 +1,2 @@
+import Vue from "vue"
+export default new Vue

+ 7 - 1
src/components/goodsItem/index.vue

@@ -100,6 +100,11 @@ export default {
             path: "/live-detail/" + res.goodsId,
           });
         }
+        if (res.goodsType === 8) {
+          this.$router.push({
+            path: "/handout-detail/" + res.goodsId,
+          });
+        }
       });
     },
 
@@ -129,11 +134,12 @@ export default {
     },
     toPayment(goodsId) {
       this.getGoodsDetail(goodsId).then((res) => {
+        console.log(res,'res')
         if (res.templateType) {
           if (res.goodsType === 1) {
             this.$refs.selectClassModal.showModal(res);
           }
-          if (res.goodsType === 2 || res.goodsType === 6) {
+          if (res.goodsType === 2 || res.goodsType === 6 || res.goodsType === 8) {
             this.goPayment(res);
           }
         } else {

+ 193 - 0
src/components/handoutItem/index.vue

@@ -0,0 +1,193 @@
+<template>
+  <div>
+    <div class="course-item" @click="goodsDetail(item)">
+      <div class="course-item__img">
+        <!-- <div
+          class="note"
+          :class="{ note__yellow: item.goodsType == 6 }"
+          v-if="item.year"
+        >
+          {{ item.year }}
+        </div> -->
+        <img
+          v-if="item.coverUrl"
+          :src="$tools.splitImgHost(item.coverUrl)"
+          alt=""
+        />
+      </div>
+      <div class="course-item__title">
+        {{ item.goodsName }}
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: ["item"],
+  data() {
+    return {
+      selectClassModal: false,
+      skuModal: false,
+      isCarOrBuy: 1 // 1加入购物车 2立即购买
+    };
+  },
+  mounted() {},
+  methods: {
+    /**
+     * 查看商品详情
+     */
+    goodsDetail(item) {
+      window.open(
+        `/my-handout-detail/${item.goodsId}?orderGoodsId=${item.orderGoodsId}`,
+        "_blank"
+      );
+    }
+  }
+};
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped lang="scss">
+.course-item {
+  cursor: pointer;
+  margin: 94px 7px 10px;
+  width: 240px;
+  background: #ffffff;
+  box-shadow: 0px 3px 6px 0px rgba(213, 218, 224, 0.8);
+  border-radius: 10px;
+  position: relative;
+  background: #fff;
+  padding-top: 70px;
+
+  &__img {
+    width: 224px;
+    height: 125px;
+    border-radius: 10px 8px 8px 8px;
+    background: #ffffff;
+    position: absolute;
+    left: 8px;
+    top: -62px;
+    overflow: hidden;
+
+    .note {
+      position: absolute;
+      top: 0px;
+      left: 0px;
+      z-index: 2;
+      width: 80px;
+      height: 24px;
+      background: #d94404;
+      box-shadow: 0px 1px 1px 0px rgba(248, 78, 5, 0.4);
+      border-radius: 10px 0px 20px 0px;
+      text-align: center;
+      line-height: 24px;
+      color: #fff;
+
+      &__yellow {
+        background: #ffb001;
+      }
+    }
+
+    img {
+      width: 100%;
+      height: 100%;
+    }
+  }
+
+  &__title {
+    margin: 0 8px;
+    font-size: 16px;
+    font-weight: bold;
+    font-family: Microsoft YaHei;
+    color: #333333;
+    line-height: 24px;
+    height: 48px;
+    overflow: hidden;
+
+    .note {
+      display: inline-block;
+      width: 48px;
+      height: 20px;
+      background: #fff8e8;
+      border: 1px solid #ffb001;
+      border-radius: 10px;
+      text-align: center;
+      color: #ffb001;
+      line-height: 18px;
+      font-size: 12px;
+    }
+  }
+
+  &__desc {
+    height: 32px;
+    margin-left: 8px;
+    display: flex;
+    align-items: center;
+
+    .price {
+      font-size: 18px;
+      font-family: Microsoft YaHei;
+      font-weight: bold;
+      color: #ff2d55;
+      line-height: 32px;
+
+      span {
+        font-size: 18px;
+        &::before {
+          content: "¥";
+          font-size: 14px;
+          font-weight: bold;
+        }
+      }
+      i {
+        // font-size: 18px;
+        font-style: normal;
+      }
+    }
+
+    .linePrice {
+      color: #999999;
+      font-size: 16px;
+      text-decoration: line-through;
+      margin-left: 10px;
+    }
+  }
+
+  &__btns {
+    margin: 0 8px;
+    display: flex;
+    justify-content: space-between;
+
+    .add {
+      display: block;
+      width: 108px;
+      height: 32px;
+      line-height: 30px;
+      border: 1px solid #bfbfbf;
+      background: #fff;
+      border-radius: 8px;
+      font-size: 16px;
+      color: #333333;
+      text-align: center;
+    }
+
+    .buynow {
+      display: block;
+      width: 108px;
+      height: 32px;
+      line-height: 30px;
+      background: #3f8dfd;
+      border-radius: 8px;
+      font-size: 16px;
+      color: #fff;
+      text-align: center;
+      transition: all 0.3s;
+
+      &:hover {
+        background: #2b6dd6;
+      }
+    }
+  }
+}
+</style>

+ 6 - 0
src/components/header/index.vue

@@ -38,6 +38,12 @@
               :style="$route.path === '/bank-list' ? 'color:red;' : ''"
               >题库</a
             >
+            <a
+              v-if="item.name == '讲义资料'"
+              @click="go('/handout-list')"
+              :style="$route.path === '/handout-list' ? 'color:red;' : ''"
+              >讲义资料</a
+            >
             <a
               v-if="item.name == '积分商城'"
               @click="go('/points-list')"

+ 3 - 0
src/main.js

@@ -16,6 +16,8 @@ import moment from "moment"
 import vueEsign from 'vue-esign'
 import axios from './axios.js'
 import 'moment/locale/zh-cn'
+import "./assets/css/quill.core.css";
+import bus from '@/common/eventBus'
 
 Vue.config.productionTip = false
 Vue.prototype.$store = store
@@ -23,6 +25,7 @@ Vue.prototype.$request = request
 Vue.prototype.$axios = axios
 Vue.prototype.$tools = tools
 Vue.prototype.$upload = upload
+Vue.prototype.$bus = bus
 Vue.prototype.$moment = moment
 
 Vue.use(ElementUI);

+ 37 - 8
src/pages/course-detail/components/HandOut.vue

@@ -11,7 +11,14 @@
         size="mini"
         v-if="showId"
         @click="showId = null"
-        >收起当前PDF</el-button
+        >收起</el-button
+      >
+      <el-button
+        class="header__btn"
+        size="mini"
+        v-if="showId"
+        @click="openBigPage(activeItem)"
+        >最大化</el-button
       >
     </div>
     <div
@@ -33,15 +40,17 @@
         :filter-node-method="filterNode"
       >
         <span class="custom-tree-node" slot-scope="{ node, data }">
-          <span :class="data.type === 1 ? 'node_label1' : 'node_label2'">{{
-            node.label
-          }}</span>
+          <span
+            :class="data.type === 1 ? 'node_label1' : 'node_label2'"
+            @click="data.type === 1 && data.url ? loadSeePdf(data) : null"
+            >{{ node.label }}</span
+          >
           <div>
             <el-button
               v-if="data.type === 1 && data.url"
               type="text"
-              @click="loadSeePdf(data)"
-              >预览</el-button
+              @click="openBigPage(data)"
+              >最大化</el-button
             >
             <el-button
               type="text"
@@ -268,7 +277,7 @@ export default {
           .then(res => {
             this.courseHandoutsData = res.data || {};
             if (res.data.fileList && res.data.fileList.length > 0) {
-              this.loadSeePdf(this.getFirstPdf(res.data.fileList));
+              // this.loadSeePdf(this.getFirstPdf(res.data.fileList));
             }
           })
           .catch(err => {});
@@ -291,6 +300,26 @@ export default {
       }
       return obj;
     },
+    openBigPage(item) {
+      if (Object.keys(item).length == 0) {
+        this.$message.error("当前选择文件不存在");
+        return;
+      }
+      var str = item.urlName.slice(item.urlName.indexOf(".") + 1);
+      if (str === "docx" || str === "xlsx") {
+        window.open(
+          ` https://view.officeapps.live.com/op/view.aspx?src=${this.$tools.splitImgHost(
+            item.url
+          )}`,
+          "_blank"
+        );
+        return;
+      }
+      if (str === "pdf") {
+        window.open(this.$tools.splitImgHost(item.url), "_blank");
+        return;
+      }
+    },
     //点击预览加载
     loadSeePdf(item) {
       this.readerResult = null;
@@ -368,7 +397,7 @@ export default {
     }
     &__btn {
       flex-shrink: 0;
-      margin: 0px 10px;
+      margin: 0px 2px;
     }
   }
   .content_flex {

+ 116 - 80
src/pages/course-detail/index.vue

@@ -189,27 +189,46 @@
                             ></div>
                           </div>
                         </div>
-                        <div class="right-box">
-                          <div class="title">
-                            推荐课程
-                            <a class="more" @click="go('/course-list')"
-                              >更多></a
-                            >
-                          </div>
-                          <ul class="list">
-                            <li
-                              class="course-item"
-                              v-for="(itemy, index) in compyRecommend(
-                                recommendList.goodsList
-                              )"
-                              :key="index"
-                            >
-                              <GoodsItem :item="itemy"></GoodsItem>
-                            </li>
-                          </ul>
-                        </div>
                       </div>
                     </template>
+                    <template v-else-if="item.label == '讲义资料'">
+                      <p
+                        v-if="compyRecommend(handoutList).length === 0"
+                        style="text-align: center;"
+                      >
+                        暂未拥有其他讲义资料
+                      </p>
+                      <ul class="list">
+                        <li
+                          class="course-item"
+                          v-for="(itemy, index) in compyRecommend(handoutList)"
+                          :key="index"
+                        >
+                          <HandoutItem :item="itemy"></HandoutItem>
+                        </li>
+                      </ul>
+                    </template>
+                    <template v-else-if="item.label == '推荐课程'">
+                      <p
+                        v-if="
+                          compyRecommend(recommendList.goodsList).length === 0
+                        "
+                        style="text-align: center;"
+                      >
+                        暂无推荐课程
+                      </p>
+                      <ul class="list">
+                        <li
+                          class="course-item"
+                          v-for="(itemy, index) in compyRecommend(
+                            recommendList.goodsList
+                          )"
+                          :key="index"
+                        >
+                          <GoodsItem :item="itemy"></GoodsItem>
+                        </li>
+                      </ul>
+                    </template>
                   </el-tab-pane>
                 </el-tabs>
               </div>
@@ -499,7 +518,14 @@
                     : ''
                 "
               >
-                <div class="upload-box" :id="item.fieldKey === 'idcard_face_photo'?'idcard_face_photo':null">
+                <div
+                  class="upload-box"
+                  :id="
+                    item.fieldKey === 'idcard_face_photo'
+                      ? 'idcard_face_photo'
+                      : null
+                  "
+                >
                   <div
                     :style="
                       item.fieldKey === 'recent_photos'
@@ -884,11 +910,12 @@
 </template>
 
 <script>
-import { Loading } from 'element-ui';
+import { Loading } from "element-ui";
 import axios from "axios";
 import Footer from "@/components/footer/index";
 import Header from "@/components/header/index";
 import ToolBar from "@/components/toolbar/index";
+import HandoutItem from "@/components/handoutItem/index";
 import GoodsItem from "@/components/goodsItem/index";
 import * as imageConversion from "image-conversion";
 import { mapGetters, mapMutations, mapActions } from "vuex";
@@ -911,6 +938,7 @@ export default {
     Footer,
     Header,
     ToolBar,
+    HandoutItem,
     GoodsItem,
     CourseTree,
     AnswerQuestions,
@@ -1257,7 +1285,8 @@ export default {
       confirmStatus: false,
       failToRegister: false, //报名是否不通过
       openPhotoStatus: 0,
-      readerResult: null
+      readerResult: null,
+      handoutList: []
     };
   },
   watch: {
@@ -1293,14 +1322,8 @@ export default {
     compyRecommend: function() {
       return function(array) {
         let ary = [];
-        if (array) {
-          for (let i = 0; i < array.length; i++) {
-            if (i >= 5) {
-              break;
-            } else {
-              ary.push(array[i]);
-            }
-          }
+        if (array && array.length > 0) {
+          ary = array.filter((i, index) => index < 5);
         }
         return ary;
       };
@@ -1344,11 +1367,11 @@ export default {
       return menuTab;
     }
   },
-  created(){
-    Loading.service().close()
+  created() {
+    Loading.service().close();
   },
   async mounted() {
-    console.log(1)
+    console.log(1);
     this.courseId = this.$route.query.courseId || "";
     this.goodsId = this.$route.params.goodsId;
     this.orderGoodsId = this.$route.query.orderGoodsId;
@@ -1357,20 +1380,22 @@ export default {
     let isOther = this.$route.query.isOther || "";
     this.nowTime = Number(new Date().getTime() / 1000).toFixed(0);
     if (isOther) {
-      this.isOtherFunc()
+      this.isOtherFunc();
     }
     if (this.$route.query.rebuild) {
       this.courseTabIndex = "2";
     }
     await this.getGoodsDetail(); //商品详情
-    this.dictList();//获取字典
+    this.dictList(); //获取字典
 
+    this.getUserHandOutList();
+    this.getRecommend();
     this.getbaseprofiletplists().then(async res => {
       await this.courseCourseList();
       this.getRebuildCourse();
     });
     document.addEventListener("visibilitychange", this.pauseVideo);
-    console.log(3)
+    console.log(3);
   },
   beforeDestroy() {
     clearTimeout(this.takeSetInt);
@@ -1400,7 +1425,18 @@ export default {
   methods: {
     ...mapMutations(["getCartCount"]),
     ...mapActions(["getUserInfo"]),
-    isOtherFunc(){
+    /**
+     *
+     获取用户讲义列表
+     */
+    getUserHandOutList() {
+      this.$request
+        .courseGoodsHandoutsList({ pageSize: 99, pageNum: 1 })
+        .then(res => {
+          this.handoutList = res.rows;
+        });
+    },
+    isOtherFunc() {
       const confirmText = [
         "您的学习账号已经开通,请按照步骤操作,进行学习。",
         "1.点击【跳转学习网址】按钮",
@@ -1736,7 +1772,7 @@ export default {
     },
 
     async changePhotoListHeader2(params, fileList) {
-      console.log('err1')
+      console.log("err1");
       let file = await this.uploadRules(params);
       if (fileList.length == 1) {
         fileList.splice(0, 1);
@@ -1748,23 +1784,23 @@ export default {
         return;
       }
 
-        if (this.infoForm.name) {
-          if (this.infoForm.name != res.data.IdName) {
-            this.$message.warning(
-              "输入的姓名和身份证人像面照片姓名不匹配,请联系客服"
-            );
-            return;
-          }
+      if (this.infoForm.name) {
+        if (this.infoForm.name != res.data.IdName) {
+          this.$message.warning(
+            "输入的姓名和身份证人像面照片姓名不匹配,请联系客服"
+          );
+          return;
         }
-        if (this.infoForm.idcard) {
-          if (this.infoForm.idcard != res.data.IdNum) {
-            this.$message.warning(
-              "输入的身份证号和身份证人像面照片身份证号不匹配,请联系客服"
-            );
-            return;
-          }
+      }
+      if (this.infoForm.idcard) {
+        if (this.infoForm.idcard != res.data.IdNum) {
+          this.$message.warning(
+            "输入的身份证号和身份证人像面照片身份证号不匹配,请联系客服"
+          );
+          return;
         }
-        this.$refs.idcard_face_photo[0].clearFiles();
+      }
+      this.$refs.idcard_face_photo[0].clearFiles();
 
       this.$set(this.infoForm, "idcard_face_photo", res.data.IdImgPath);
       this.fileList2 = [
@@ -2140,30 +2176,29 @@ export default {
     async uploadDatas(data) {
       let self = this;
       if (this.infoForm.recent_photos && this.infoForm.idcard_face_photo) {
-        
         let resData = {};
         try {
           let base = await this.$tools.imageToBase64(
-          this.$tools.splitImgHost(this.infoForm.idcard_face_photo)
-        );
+            this.$tools.splitImgHost(this.infoForm.idcard_face_photo)
+          );
           resData = await this.$request.faceCertificationIDCardOCR({
             cardSide: 1, //1人像  2 国徽
             cardImageBase64: base,
             gradeId: this.gradeId
           });
         } catch (err) {
-      //生成唯一ID定位Start
-      document.getElementById("idcard_face_photo").scrollIntoView(true);
-      //生成唯一ID定位End
+          //生成唯一ID定位Start
+          document.getElementById("idcard_face_photo").scrollIntoView(true);
+          //生成唯一ID定位End
           self.$message.warning("身份证人像面照片异常,请重新上传");
           self.uploading = false;
           return;
         }
 
         if (!resData.data) {
-      //生成唯一ID定位Start
-      document.getElementById("idcard_face_photo").scrollIntoView(true);
-      //生成唯一ID定位End
+          //生成唯一ID定位Start
+          document.getElementById("idcard_face_photo").scrollIntoView(true);
+          //生成唯一ID定位End
           this.$message.warning("身份证人像面照片异常,请重新上传");
           this.uploading = false;
           return;
@@ -2172,10 +2207,9 @@ export default {
         this.veryIdName = resData.data.IdName;
         if (this.infoForm.name) {
           if (this.infoForm.name != this.veryIdName) {
-            
-      //生成唯一ID定位Start
-      document.getElementById("idcard_face_photo").scrollIntoView(true);
-      //生成唯一ID定位End
+            //生成唯一ID定位Start
+            document.getElementById("idcard_face_photo").scrollIntoView(true);
+            //生成唯一ID定位End
             this.$message.warning(
               "输入的姓名和身份证人像面照片姓名不匹配,请联系客服"
             );
@@ -2185,9 +2219,9 @@ export default {
         }
         if (this.infoForm.idcard) {
           if (this.infoForm.idcard != this.veryIdCard) {
-      //生成唯一ID定位Start
-      document.getElementById("idcard_face_photo").scrollIntoView(true);
-      //生成唯一ID定位End
+            //生成唯一ID定位Start
+            document.getElementById("idcard_face_photo").scrollIntoView(true);
+            //生成唯一ID定位End
             this.$message.warning(
               "输入的身份证号和身份证人像面照片身份证号不匹配,请联系客服"
             );
@@ -3311,7 +3345,7 @@ export default {
         let self = this;
         this.$request.goodsDetail(this.goodsId).then(res => {
           self.goodsData = res.data;
-          console.log("tanglian1",self.goodsData.erJianErZao);
+          console.log("tanglian1", self.goodsData.erJianErZao);
           self.gradeId = self.goodsData.gradeId;
           if (this.goodsData.categoryName) {
             this.infoForm.apply_post = this.goodsData.categoryName;
@@ -3325,16 +3359,14 @@ export default {
           }
           if (this.goodsData.buyNote) {
             this.tabList = [
-              { name: "1", label: "学员须知" }
-              // { name: "2", label: "课程答疑" },
-              // { name: "3", label: "笔记讲义" },
+              { name: "1", label: "讲义资料" },
+              { name: "2", label: "推荐课程" },
+              { name: "3", label: "学员须知" }
             ];
-            console.log(res, "res111");
-            this.getRecommend();
           } else {
             this.tabList = [
-              // { name: "1", label: "课程答疑" },
-              // { name: "2", label: "笔记讲义" },
+              { name: "1", label: "讲义资料" },
+              { name: "2", label: "推荐课程" }
             ];
           }
           this.courseBusiness();
@@ -3635,7 +3667,7 @@ export default {
         this.player.on("s2j_onVideoPause", () => {
           clearInterval(this.postTimer);
           if (this.sectionItem.learning != 1 && this.goodsData.erJianErZao) {
-            console.log(123)
+            console.log(123);
             this.videoPause = setTimeout(() => {
               if (!this.takePhotoModal) {
                 if (this.isFullScreen()) {
@@ -4520,7 +4552,7 @@ export default {
           gradeId: this.gradeId
         })
         .then(async res => {
-          if(res.data.length > 0){
+          if (res.data.length > 0) {
             this.rebuildCourseList = [res.data[0]];
           }
         });
@@ -4550,7 +4582,7 @@ export default {
           .courseCourseList({ goodsId: this.goodsId, gradeId: this.gradeId })
           .then(async res => {
             this.courseList = res.rows;
-            console.error("res.rows",res.rows)
+            console.error("res.rows", res.rows);
             if (!this.courseId) {
               this.courseId = this.courseList[0].courseId;
             }
@@ -4701,6 +4733,10 @@ export default {
 
 <!-- Add "scoped" attribute to limit CSS to this component only -->
 <style scoped lang="scss">
+.course-item {
+  float: left;
+  margin-bottom: 6px;
+}
 /deep/ .docx-wrapper {
   padding: 0px;
 }

+ 1 - 1
src/pages/course-list/index.vue

@@ -149,7 +149,7 @@ import ToolBar from "@/components/toolbar/index";
 import GoodsItem from "@/components/goodsItem/index";
 import { mapMutations } from "vuex";
 export default {
-  name: "PaymentSuccess",
+  name: "handoutList",
   components: {
     Footer,
     Header,

+ 2 - 2
src/pages/goods-detail/course-detail.vue

@@ -75,7 +75,7 @@
               <div class="goods-info__body">
                 <el-tabs v-model="activeName">
                   <el-tab-pane label="课程详情" name="1">
-                    <div class="detail" v-html="goodsDetail.pcDetailHtml"></div>
+                    <div class="detail ql-editor" style="white-space: pre-wrap"  v-html="goodsDetail.pcDetailHtml"></div>
                   </el-tab-pane>
                   <el-tab-pane label="章节目录" name="2">
                     <div slot="label" style="position: relative">
@@ -338,7 +338,7 @@
                     </div>
                   </el-tab-pane>
                   <el-tab-pane label="学员须知" name="3">
-                    <div
+                    <div class="ql-editor" style="white-space: pre-wrap" 
                       v-html="
                         goodsDetail.buyNote &&
                         goodsDetail.buyNote.replace(/\n|\r\n/g, '<br>')

+ 638 - 0
src/pages/goods-detail/handout-detail.vue

@@ -0,0 +1,638 @@
+<template>
+  <div class="goods-detail">
+    <Header></Header>
+    <section class="section">
+      <div class="container">
+        <div class="section__header">
+          <div class="container">
+            <el-breadcrumb separator="/">
+              <el-breadcrumb-item :to="{ path: '/index' }"
+                >首页</el-breadcrumb-item
+              >
+              <el-breadcrumb-item>商品详情</el-breadcrumb-item>
+            </el-breadcrumb>
+          </div>
+        </div>
+        <div class="section__body">
+          <div class="container">
+            <div class="goods-info">
+              <div class="goods-info__header">
+                <div class="img">
+                  <img
+                    :src="$tools.splitImgHost(goodsDetail.coverUrl, false)"
+                    alt=""
+                  />
+                </div>
+                <div class="text">
+                  <div class="title">
+                    {{ goodsDetail.goodsName }}
+                  </div>
+                  <div
+                    class="price"
+                    v-if="
+                      !goodsDetail.specTemplateId ||
+                        (!goodsDetail.maxPrice && !goodsDetail.minPrice)
+                    "
+                  >
+                    {{
+                      goodsDetail.standPrice === 0
+                        ? "免费"
+                        : `¥${goodsDetail.standPrice}`
+                    }}
+                  </div>
+                  <div v-else class="price">
+                    <span>{{ goodsDetail.minPrice }}</span>
+                    <template
+                      v-if="goodsDetail.minPrice != goodsDetail.maxPrice"
+                    >
+                      <i>-</i>
+                      <span>{{ goodsDetail.maxPrice }}</span>
+                    </template>
+                  </div>
+                  <div class="btns">
+                    <el-button
+                      type="primary"
+                      round
+                      class="buynow"
+                      @click="buyNow()"
+                      >立即购买</el-button
+                    >
+                    <el-button
+                      type="primary"
+                      round
+                      plain
+                      class="add"
+                      @click="addCart()"
+                      >加入购物车</el-button
+                    >
+                  </div>
+                </div>
+              </div>
+              <div class="goods-info__body">
+                <el-tabs v-model="activeName">
+                  <el-tab-pane label="课程详情" name="1">
+                    <div
+                      class="detail ql-editor"
+                      style="white-space: pre-wrap"
+                      v-html="goodsDetail.pcDetailHtml"
+                    ></div>
+                  </el-tab-pane>
+                  <el-tab-pane label="章节目录" name="2">
+                    <h2 style="font-size: 18px;">
+                      讲义标题:{{ courseHandoutsData.handoutsName }}
+                    </h2>
+                    <el-tree
+                      :data="courseHandoutsData.fileList"
+                      :props="defaultProps"
+                    ></el-tree>
+                  </el-tab-pane>
+                  <el-tab-pane label="学员须知" name="3">
+                    <div
+                      class="ql-editor"
+                      style="white-space: pre-wrap"
+                      v-html="
+                        goodsDetail.buyNote &&
+                          goodsDetail.buyNote.replace(/\n|\r\n/g, '<br>')
+                      "
+                    ></div>
+                  </el-tab-pane>
+                </el-tabs>
+              </div>
+            </div>
+          </div>
+        </div>
+
+        <div
+          class="section__footer"
+          v-if="
+            recommendList.goodsList &&
+              recommendList.goodsList.length &&
+              (activeName == 1 || activeName == 3)
+          "
+        >
+          <div class="recommend">
+            <div class="recommend__header">
+              <div class="title">相关推荐</div>
+            </div>
+            <div class="recommend__body">
+              <ul class="list clearfix">
+                <li
+                  class="recommend-item"
+                  v-for="(itemy, index) in compyRecommend(
+                    recommendList.goodsList
+                  )"
+                  :key="index"
+                >
+                  <GoodsItem :item="itemy"></GoodsItem>
+                </li>
+              </ul>
+            </div>
+
+            <div class="recommend__footer">
+              <div class="btn" @click="comeMoreList">查看更多</div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </section>
+
+    <ToolBar></ToolBar>
+    <Footer></Footer>
+  </div>
+</template>
+
+<script>
+import Footer from "@/components/footer/index";
+import Header from "@/components/header/index";
+import ToolBar from "@/components/toolbar/index";
+import GoodsItem from "@/components/goodsItem/index";
+import { mapMutations } from "vuex";
+export default {
+  name: "GoodsDetail",
+  components: {
+    Footer,
+    Header,
+    ToolBar,
+    GoodsItem
+  },
+  data() {
+    return {
+      defaultProps: {
+        children: "children",
+        label: "urlName"
+      },
+      goodsDetail: {
+        standPrice: 0
+      },
+      courseHandoutsData: [],
+      goodsId: "",
+      textarea: "",
+      activeName: "1",
+      recommendList: {}, //推荐课程
+      isCarOrBuy: 1 // 1加入购物车 2立即购买
+    };
+  },
+  mounted() {
+    this.goodsId = this.$route.params.goodsId;
+    this.getGoodsDetail();
+  },
+  computed: {
+    compyRecommend: function() {
+      return function(array) {
+        let ary = [];
+        if (array) {
+          for (let i = 0; i < array.length; i++) {
+            if (i >= 5) {
+              break;
+            } else {
+              ary.push(array[i]);
+            }
+          }
+        }
+        return ary;
+      };
+    }
+  },
+  methods: {
+    ...mapMutations(["setCurrentRouter", "getCartCount"]),
+    /**
+     * 查看更多
+     */
+    comeMoreList() {
+      this.$router.push({
+        path: "/course-list",
+        query: {
+          educationId: this.goodsDetail.educationTypeId,
+          projectId: this.goodsDetail.projectId,
+          businessId: this.goodsDetail.businessId
+        }
+      });
+    },
+    /**
+     * 
+     获取推荐列表
+     */
+    getRecommend() {
+      this.$request
+        .appCommonActivityRecommendList({
+          businessId: this.goodsDetail.businessId,
+          type: 1
+        })
+        .then(res => {
+          if (res.rows.length) {
+            this.recommendList = res.rows[0];
+          }
+        });
+    },
+    buyNow() {
+      if (this.$tools.isLogin()) {
+        this.toPayment(this.goodsDetail);
+      } else {
+        this.setCurrentRouter(this.$route);
+        this.$router.push({
+          path: "/login"
+        });
+        return;
+      }
+    },
+    toPayment(goodsDetail) {
+      localStorage.setItem("checkGoodsList", JSON.stringify([goodsDetail]));
+      this.$router.push({
+        path: "/payment"
+      });
+    },
+    addCart(status, goodsId) {
+      if (!this.$tools.isLogin()) {
+        this.setCurrentRouter(this.$route);
+        this.$router.push({
+          path: "/login"
+        });
+        return;
+      }
+      this.getAddCar(this.goodsId);
+    },
+    getAddCar(goodsIds) {
+      if (!Array.isArray(goodsIds)) {
+        goodsIds = [goodsIds];
+      }
+      this.$request
+        .addCart({ goodsIds })
+        .then(res => {
+          this.getCartCount();
+          this.$message({
+            message: "加入购物车成功",
+            type: "success"
+          });
+        })
+        .catch(err => {
+          if (err.code == 500) {
+            this.$message({
+              message: err.msg,
+              type: "warning"
+            });
+          }
+        });
+    },
+    /**
+     * 获取商品详情
+     */
+    getGoodsDetail() {
+      this.$request.commonGoodsDetail(this.goodsId).then(res => {
+        if (res.data.pcDetailHtml) {
+          res.data.pcDetailHtml =
+            res.data.pcDetailHtml &&
+            res.data.pcDetailHtml.replace(
+              /<img/gi,
+              '<img style="max-width:100%;height:100%;display:block;margin:0px auto;"'
+            );
+        }
+        this.goodsDetail = res.data;
+        this.getRecommend();
+        this.goodshandoutList();
+      });
+    },
+    /**
+     * 获取讲义资料列表
+     */
+    goodshandoutList() {
+      if (this.goodsDetail.handoutsId) {
+        this.$request
+          .coursehandoutsfiledetail({ handoutsId: this.goodsDetail.handoutsId })
+          .then(res => {
+            this.courseHandoutsData = res.data || {};
+          })
+          .catch(err => {});
+      }
+    }
+  }
+};
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped lang="scss">
+/deep/ .el-tree-node__label {
+  font-size: 16px;
+}
+.goods-detail {
+  .section {
+    &__header {
+      height: 40px;
+      display: flex;
+      align-items: center;
+      padding: 0 20px;
+    }
+
+    &__body {
+      .goods-info {
+        &__header {
+          width: 100%;
+          height: 288px;
+          background: #f5f7fa;
+          border-radius: 10px;
+          padding: 20px;
+          display: flex;
+
+          .img {
+            width: 442px;
+            height: 248px;
+            border-radius: 10px;
+            overflow: hidden;
+
+            img {
+              max-width: 100%;
+              max-height: 100%;
+              width: 100%;
+              height: 100%;
+            }
+          }
+
+          .text {
+            flex: 1;
+            margin-left: 24px;
+            .title {
+              font-size: 18px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #333333;
+              line-height: 24px;
+            }
+
+            .desc {
+              padding: 1px 5px;
+              display: inline-block;
+              border: 1px solid #333333;
+              border-radius: 4px;
+              font-size: 12px;
+              font-family: Microsoft YaHei;
+              font-weight: 400;
+              color: #333333;
+            }
+
+            .price {
+              margin-top: 10px;
+              font-size: 24px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #ff2d55;
+              line-height: 24px;
+              span {
+                font-size: 32px;
+                &::before {
+                  content: "¥";
+                  font-size: 24px;
+                  font-weight: bold;
+                }
+              }
+              i {
+                font-size: 32px;
+              }
+            }
+
+            .btns {
+              margin-top: 124px;
+              display: flex;
+
+              .buynow {
+                margin-right: 16px;
+                width: 160px;
+                height: 40px;
+                padding: 0;
+                border-radius: 20px;
+                text-align: center;
+                line-height: 40px;
+              }
+
+              .add {
+                padding: 0;
+                width: 128px;
+                height: 40px;
+                border-radius: 20px;
+                text-align: center;
+                line-height: 40px;
+              }
+            }
+          }
+        }
+
+        &__body {
+          /deep/ .el-tabs__item {
+            padding: 0 20px !important;
+            height: 80px;
+            line-height: 80px;
+            font-size: 18px;
+          }
+
+          .label {
+            font-size: 18px;
+          }
+
+          .view-note {
+            width: 40px;
+            height: 24px;
+            background: #ff3b30;
+            border-radius: 4px 4px 0px 4px;
+            border: 1px solid #ff3b30;
+            text-align: center;
+            line-height: 22px;
+            color: #fff;
+            position: absolute;
+            right: -10px;
+            top: 5px;
+          }
+
+          .detail {
+            img {
+              max-width: 100% !important;
+            }
+          }
+
+          .goods-img {
+            width: 100%;
+          }
+
+          .goods-menu {
+            margin-top: 15px;
+            .left-box {
+              width: 948px;
+              float: left;
+
+              &__body {
+                .course-list-item {
+                  margin-top: 24px;
+                  padding: 16px;
+                  background: #f5f7fa;
+                  border-radius: 10px;
+                  &__title {
+                    font-size: 18px;
+                    color: #333;
+                    font-weight: bold;
+                    cursor: pointer;
+                  }
+
+                  .item {
+                    overflow: hidden;
+                    background: #fff;
+                    margin-top: 12px;
+                    &__title {
+                      padding: 10px 0;
+                      cursor: pointer;
+                      font-size: 16px;
+                      font-family: Microsoft YaHei;
+                      font-weight: bold;
+                      color: #333333;
+
+                      .note {
+                        display: inline-block;
+                        margin-left: 20px;
+                        width: 40px;
+                        height: 24px;
+                        border: 1px solid #ff3b30;
+                        border-radius: 8px;
+                        line-height: 22px;
+                        color: #ff3b30;
+                        text-align: center;
+                      }
+                    }
+
+                    &__content {
+                      background: #fff;
+
+                      .bank-chapter {
+                        margin-left: 4px;
+
+                        &__item {
+                          padding-top: 20px;
+                          padding-bottom: 20px;
+                          border-bottom: 1px solid #eeeeee;
+                          font-size: 16px;
+
+                          &__text {
+                            cursor: pointer;
+                            flex: 1;
+                          }
+                        }
+                      }
+
+                      .bank-section {
+                        margin-left: 40px;
+
+                        &__item {
+                          padding-top: 20px;
+                          padding-bottom: 20px;
+                          border-bottom: 1px solid #eeeeee;
+                          font-size: 16px;
+                          display: flex;
+
+                          &__text {
+                            flex: 1;
+                          }
+
+                          .btn {
+                            margin-right: 20px;
+                            width: 40px;
+                            height: 24px;
+                            border: 1px solid #ff3b30;
+                            border-radius: 8px;
+                            line-height: 22px;
+                            color: #ff3b30;
+                            text-align: center;
+                            cursor: pointer;
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+
+            .right-box {
+              width: 255px;
+              float: right;
+              .title {
+                margin-left: 10px;
+                font-size: 16px;
+                font-family: Microsoft YaHei;
+                font-weight: 400;
+                color: #333333;
+                text-shadow: 0px 6px 6px rgba(85, 158, 255, 0.08);
+                position: relative;
+
+                .more {
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #999999;
+                  position: absolute;
+                  right: 10px;
+                  top: 0;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    &__footer {
+      .recommend {
+        padding-top: 40px;
+
+        &__header {
+          display: flex;
+          align-items: center;
+
+          .title {
+            font-size: 24px;
+            font-family: YouSheBiaoTiHei;
+            font-weight: 400;
+            color: #333333;
+            text-shadow: 0px 6px 6px rgba(249, 113, 13, 0.08);
+          }
+        }
+
+        &__body {
+          .list {
+            width: 100%;
+
+            .recommend-item {
+              float: left;
+            }
+          }
+        }
+
+        &__footer {
+          overflow: hidden;
+          .btn {
+            cursor: pointer;
+            width: 146px;
+            height: 40px;
+            background: #e3eaf7;
+            border-radius: 8px;
+            margin: 20px auto 40px;
+            color: #3f8dfd;
+            text-align: center;
+            line-height: 40px;
+
+            &:hover {
+              color: #fff;
+              box-shadow: 0px 8px 4px 0px rgba(7, 82, 208, 0.08);
+              background: #3f8dfd;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  .select-class {
+    &__content {
+      .selection {
+        .el-select {
+          width: 100%;
+        }
+      }
+    }
+  }
+}
+</style>

+ 2 - 2
src/pages/goods-detail/live-detail.vue

@@ -75,7 +75,7 @@
               <div class="goods-info__body">
                 <el-tabs v-model="activeName">
                   <el-tab-pane label="课程详情" name="1">
-                    <div class="detail" v-html="goodsDetail.pcDetailHtml"></div>
+                    <div class="detail ql-editor" style="white-space: pre-wrap"  v-html="goodsDetail.pcDetailHtml"></div>
                   </el-tab-pane>
                   <el-tab-pane label="章节目录" name="2">
                     <div slot="label" style="position: relative">
@@ -357,7 +357,7 @@
                     </div>
                   </el-tab-pane>
                   <el-tab-pane label="学员须知" name="3">
-                    <div
+                    <div class="ql-editor" style="white-space: pre-wrap" 
                       v-html="
                         goodsDetail.buyNote &&
                         goodsDetail.buyNote.replace(/\n|\r\n/g, '<br>')

+ 352 - 0
src/pages/handout-detail/components/HandOut.vue

@@ -0,0 +1,352 @@
+<template>
+  <div class="lecture-notesjy">
+    <div class="header">
+      <div class="header__name">
+        {{ courseHandoutsData.handoutsName }}
+      </div>
+    </div>
+    <div
+      v-show="
+        courseHandoutsData.fileList && courseHandoutsData.fileList.length > 0
+      "
+      class="content_flex"
+    >
+      <el-input placeholder="输入关键字进行过滤" v-model="filterText" clearable>
+      </el-input>
+      <el-tree
+        ref="tree"
+        :data="courseHandoutsData.fileList"
+        node-key="fileId"
+        draggable
+        :props="defaultProps"
+        :filter-node-method="filterNode"
+        default-expand-all
+      >
+        <span class="custom-tree-node" slot-scope="{ node, data }">
+          <span
+            :class="data.type === 1 ? 'node_label1' : 'node_label2'"
+            :style="activefileId == data.fileId ? 'color:red' : null"
+            @click="data.type === 1 && data.url ? loadSeePdf(data) : null"
+            >{{ node.label }}</span
+          >
+          <div>
+            <el-button
+              v-if="data.type === 1 && data.url"
+              type="text"
+              @click="openBigPage(data)"
+              >最大化</el-button
+            >
+            <el-button
+              type="text"
+              v-if="
+                data.type === 1 &&
+                data.url &&
+                courseHandoutsData.canDownload == 1
+                  ? true
+                  : false
+              "
+              @click="printView($tools.splitImgHost(data.url), data.urlName)"
+              >打印</el-button
+            >
+            <el-button
+              type="text"
+              v-if="
+                data.type === 1 &&
+                data.url &&
+                courseHandoutsData.canDownload == 1
+                  ? true
+                  : false
+              "
+              @click="download($tools.splitImgHost(data.url), data.urlName)"
+              >下载</el-button
+            >
+          </div>
+        </span>
+      </el-tree>
+    </div>
+    <p
+      class="no_center"
+      v-show="
+        !courseHandoutsData.fileList || courseHandoutsData.fileList.length === 0
+      "
+    >
+      暂无讲义列表
+    </p>
+  </div>
+</template>
+
+<script>
+import Print from "print-js";
+export default {
+  props: {
+    goodsData: {
+      type: Object,
+      default: () => {
+        return {};
+      }
+    }
+  },
+  data() {
+    return {
+      readerResult: null,
+      filterText: "",
+      defaultProps: {
+        children: "children",
+        label: "urlName"
+      },
+      courseHandoutsData: {},
+      activefileId: ""
+    };
+  },
+  watch: {
+    filterText(val) {
+      this.$refs.tree.filter(val);
+    },
+    goodsData: {
+      handler(newVal, oldVal) {
+        if (newVal.handoutsId != oldVal.handoutsId) {
+          this.courseHandouts();
+        }
+      },
+      deep: true
+    }
+  },
+  methods: {
+    filterNode(value, data, node) {
+      let parentNode = node.parent; // 父级node
+      let labels = [node.label]; // 当前node的名字
+      let level = 1; // 层级
+      while (level < node.level) {
+        labels = [...labels, parentNode.label]; // 当前node名字,父级node的名字
+        parentNode = parentNode.parent;
+        level++;
+      }
+      return labels.some(d => d.indexOf(value) !== -1);
+    },
+    /**
+     * 打印
+     */
+    printView(url, name) {
+      console.log("触发打印", url);
+      var a = name.slice(name.indexOf(".") + 1);
+      if (a !== "pdf") {
+        this.$message.error("当前类型不支持打印功能");
+        return;
+      }
+      Print({
+        printable: url,
+        type: a,
+        header: null,
+        targetStyles: ["*"],
+        style: "@page {margin:0 10mm}"
+      });
+    },
+    //下载
+    download(url, fileName) {
+      let xhr = new XMLHttpRequest();
+      xhr.open("get", url, true);
+      xhr.setRequestHeader("Content-Type", `application/pdf`);
+      xhr.responseType = "blob";
+      let that = this;
+      xhr.onload = function() {
+        if (this.status == 200) {
+          //接受二进制文件流
+          var blob = this.response;
+          that.downloadExportFile(blob, fileName);
+        }
+      };
+      xhr.send();
+    },
+
+    downloadExportFile(blob, tagFileName) {
+      let downloadElement = document.createElement("a");
+      let href = "";
+      if (typeof blob == "string") {
+        downloadElement.target = "_blank";
+      } else {
+        href = window.URL.createObjectURL(blob); //创建下载的链接
+      }
+      downloadElement.href = href;
+      downloadElement.download = tagFileName;
+      //下载后文件名
+      document.body.appendChild(downloadElement);
+      downloadElement.click(); //点击下载
+      document.body.removeChild(downloadElement); //下载完成移除元素
+      if (typeof blob != "string") {
+        window.URL.revokeObjectURL(href); //释放掉blob对象
+      }
+    },
+    /**
+     * 获取讲义权限
+     */
+    courseHandouts() {
+      if (this.goodsData.handoutsId) {
+        this.$request
+          .courseHandoutsdetail({ handoutsId: this.goodsData.handoutsId })
+          .then(res => {
+            this.courseHandoutsData = res.data || {};
+            if (res.data.fileList && res.data.fileList.length > 0) {
+              this.loadSeePdf(this.getFirstPdf(res.data.fileList));
+            }
+          })
+          .catch(err => {});
+      }
+    },
+    //递归查询第一个PDF
+    getFirstPdf(array) {
+      let obj = {};
+      for (let i = 0; i < array.length; i++) {
+        if (array[i].type === 1 && array[i].url) {
+          obj = array[i];
+          break;
+        }
+        if (array[i].type === 2) {
+          obj = this.getFirstPdf(array[i].children || []);
+          if (Object.keys(obj).length != 0) {
+            break;
+          }
+        }
+      }
+      return obj;
+    },
+    openBigPage(item) {
+      if (Object.keys(item).length == 0) {
+        this.$message.error("当前选择文件不存在");
+        return;
+      }
+      var str = item.urlName.slice(item.urlName.indexOf(".") + 1);
+      if (str === "docx" || str === "xlsx") {
+        window.open(
+          ` https://view.officeapps.live.com/op/view.aspx?src=${this.$tools.splitImgHost(
+            item.url
+          )}`,
+          "_blank"
+        );
+        return;
+      }
+      if (str === "pdf") {
+        window.open(this.$tools.splitImgHost(item.url), "_blank");
+        return;
+      }
+    },
+    //点击预览加载
+    loadSeePdf(item) {
+      console.log(item, "item");
+      if (Object.keys(item).length == 0) {
+        this.$message.error("当前选择文件不存在");
+        return;
+      }
+      var str = item.urlName.slice(item.urlName.indexOf(".") + 1);
+      if (str === "docx" || str === "xlsx" || str === "pdf") {
+        this.activefileId = item.fileId;
+        this.$emit("backSwitchOfficeData", item);
+        return;
+      }
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+/deep/ .vue-office-pdf-wrapper {
+  & > canvas {
+    width: 100% !important;
+  }
+}
+.el-tree {
+  background-color: #3f4449;
+  color: #fff;
+}
+/deep/ .el-input__inner {
+  background-color: #3f4449;
+  color: #fff;
+  border-radius: 0px;
+  border: none;
+  border-bottom: 1px solid #dcdfe6;
+}
+/deep/ .el-tree-node__content:hover,
+/deep/ .el-tree-node:focus > .el-tree-node__content {
+  background-color: #0005;
+}
+.custom-tree-node {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding-right: 8px;
+
+  & > .node_label1 {
+    flex: 1;
+    width: 1px;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+  }
+  & > .node_label2 {
+    width: 408px;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+  }
+}
+.lecture-notesjy {
+  max-height: 416px;
+  .header {
+    display: flex;
+    align-items: center;
+    border-bottom: 1px solid #fff;
+    height: 40px;
+    &__name {
+      flex: 1;
+      color: #fff;
+      padding: 10px;
+    }
+    &__btn {
+      flex-shrink: 0;
+      margin: 0px 10px;
+    }
+  }
+  .content_flex {
+    flex: 1;
+    height: 1px;
+    display: flex;
+    flex-direction: column;
+    & > .el-input {
+      height: 40px;
+    }
+    & > .el-tree {
+      background-color: #3f4449;
+      color: #fff;
+      height: 336px;
+      overflow: auto;
+    }
+  }
+  .no_center {
+    text-align: center;
+    color: #fff;
+    padding: 10px;
+  }
+  .center {
+    flex: 1;
+    overflow: auto;
+    .centerLi {
+      padding: 4px 10px;
+      & > .centerLibox {
+        display: flex;
+        align-items: center;
+        color: #fff;
+        & > .centerLiboxName {
+          flex: 1;
+        }
+        & > .centerLiboxBtnBox {
+          flex-shrink: 0;
+        }
+      }
+    }
+  }
+  .office_box {
+    flex: 1;
+    overflow: auto;
+  }
+}
+</style>

+ 1646 - 0
src/pages/handout-detail/index.vue

@@ -0,0 +1,1646 @@
+<template>
+  <div class="course-detail">
+    <Header></Header>
+    <section class="section">
+      <div class="container">
+        <div class="section__header">
+          <div class="container">
+            <el-breadcrumb separator="/">
+              <el-breadcrumb-item :to="{ path: '/index' }"
+                >首页</el-breadcrumb-item
+              >
+              <el-breadcrumb-item>讲义资料详情</el-breadcrumb-item>
+            </el-breadcrumb>
+          </div>
+        </div>
+        <div class="section__body">
+          <div class="container">
+            <div class="course-info">
+              <div class="course-info__header clearfix">
+                <div class="title">
+                  <span>{{ goodsData.goodsName }}</span>
+                </div>
+                <el-main
+                  class="left-box"
+                  :style="{
+                    backgroundColor: '#f4f4f4',
+                    padding: 0
+                  }"
+                  v-loading="loading"
+                  element-loading-text="资源加载中"
+                  element-loading-spinner="el-icon-loading"
+                  element-loading-background="rgba(0, 0, 0, 0.8)"
+                >
+                  <vue-office-docx
+                    style="width:100%;height: 452px!important;"
+                    v-if="ShowAlist === 'docx'"
+                    :src="readerResult"
+                  />
+                  <vue-office-excel
+                    style="width:100%;height: 452px!important;"
+                    v-else-if="ShowAlist === 'xlsx'"
+                    :src="readerResult"
+                  />
+                  <vue-office-pdf
+                    style="width:100%;height: 452px!important;"
+                    v-else-if="ShowAlist === 'pdf'"
+                    :src="readerResult"
+                  />
+                </el-main>
+                <div class="right-box">
+                  <div class="right-box__header">
+                    <div class="tabs">
+                      <el-tabs v-model="courseTabIndex">
+                        <el-tab-pane
+                          :name="tab.name"
+                          v-for="(tab, index) in menuTab"
+                          :key="index"
+                        >
+                          <div slot="label">
+                            <span class="label">{{ tab.label }}</span>
+                          </div>
+                          <Hand-out
+                            ref="handOut"
+                            :goodsData="goodsData"
+                            @backSwitchOfficeData="backSwitchOfficeData"
+                          ></Hand-out>
+                        </el-tab-pane>
+                      </el-tabs>
+                    </div>
+                  </div>
+                </div>
+              </div>
+              <div class="course-info__body">
+                <el-tabs v-model="activeName">
+                  <el-tab-pane
+                    v-for="(item, index) in tabList"
+                    :key="index"
+                    :name="item.name"
+                    :label="item.label"
+                  >
+                    <template v-if="item.label == '学员须知'">
+                      <div class="course-menu clearfix">
+                        <div class="left-box">
+                          <div class="left-box__body">
+                            <div
+                              class="buy-note"
+                              v-html="
+                                goodsData.buyNote &&
+                                  goodsData.buyNote.replace(/\n|\r\n/g, '<br>')
+                              "
+                            ></div>
+                          </div>
+                        </div>
+                      </div>
+                    </template>
+                    <template v-else-if="item.label == '讲义资料'">
+                      <p
+                        v-if="compyHandout(handoutList).length === 0"
+                        style="text-align: center;"
+                      >
+                        暂未拥有其他讲义资料
+                      </p>
+                      <ul class="list">
+                        <li
+                          class="course-item"
+                          v-for="(itemy, index) in compyHandout(handoutList)"
+                          :key="index"
+                        >
+                          <HandoutItem :item="itemy"></HandoutItem>
+                        </li>
+                      </ul>
+                    </template>
+                    <template v-else-if="item.label == '推荐课程'">
+                      <p
+                        v-if="
+                          compyRecommend(recommendList.goodsList).length === 0
+                        "
+                        style="text-align: center;"
+                      >
+                        暂无推荐课程
+                      </p>
+                      <ul class="list">
+                        <li
+                          class="course-item"
+                          v-for="(itemy, index) in compyRecommend(
+                            recommendList.goodsList
+                          )"
+                          :key="index"
+                        >
+                          <GoodsItem :item="itemy"></GoodsItem>
+                        </li>
+                      </ul>
+                    </template>
+                  </el-tab-pane>
+                </el-tabs>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </section>
+    <Footer></Footer>
+  </div>
+</template>
+
+<script>
+import HandoutItem from "@/components/handoutItem/index";
+import GoodsItem from "@/components/goodsItem/index";
+import Footer from "@/components/footer/index";
+import Header from "@/components/header/index";
+import axios from "axios";
+import HandOut from "./components/HandOut.vue";
+//引入VueOfficeDocx组件
+import VueOfficeDocx from "@vue-office/docx";
+//引入VueOfficeExcel组件
+import VueOfficeExcel from "@vue-office/excel";
+//引入VueOfficePdf组件
+import VueOfficePdf from "@vue-office/pdf";
+//引入相关样式
+import "@vue-office/docx/lib/index.css";
+import "@vue-office/excel/lib/index.css";
+export default {
+  components: {
+    HandoutItem,
+    GoodsItem,
+    Header,
+    Footer,
+    HandOut,
+    VueOfficeDocx,
+    VueOfficeExcel,
+    VueOfficePdf
+  },
+  data() {
+    return {
+      loading: false,
+      goodsData: {},
+      goodsId: "",
+      orderGoodsId: "",
+      tabList: [],
+      activeName: "1",
+      courseTabIndex: "1",
+      switchPdf: {}, //pdf数据
+      readerResult: null,
+      recommendList: [],
+      handoutList: [],
+      sysTime: null,
+      menuTab: [
+        {
+          name: "1",
+          label: "讲义"
+        }
+      ]
+    };
+  },
+  computed: {
+    ShowAlist() {
+      if (this.switchPdf.urlName) {
+        console.log(
+          this.switchPdf.urlName.slice(this.switchPdf.urlName.indexOf(".") + 1)
+        );
+        return this.switchPdf.urlName.slice(
+          this.switchPdf.urlName.indexOf(".") + 1
+        );
+      }
+      return "";
+    },
+    compyHandout: function() {
+      return function(array) {
+        let ary = [];
+        if (array && array.length > 0) {
+          ary = array.filter((i, index) => {
+            return (
+              i.goodsId !== this.goodsData.goodsId &&
+              index < 5 &&
+              i.validityStartTime <= this.sysTime &&
+              i.validityEndTime > this.sysTime
+            );
+          });
+        }
+        return ary;
+      };
+    },
+    compyRecommend: function() {
+      return function(array) {
+        let ary = [];
+        if (array && array.length > 0) {
+          ary = array.filter((i, index) => index < 5);
+        }
+        return ary;
+      };
+    }
+  },
+  async mounted() {
+    this.sysTime = this.$tools.timest();
+    this.goodsId = this.$route.params.goodsId;
+    this.orderGoodsId = this.$route.query.orderGoodsId;
+    await this.getGoodsDetail();
+    this.getUserHandOutList();
+    this.getRecommend();
+  },
+  methods: {
+    /**
+     *
+     获取用户讲义列表
+     */
+    getUserHandOutList() {
+      this.$request
+        .courseGoodsHandoutsList({ pageSize: 99, pageNum: 1 })
+        .then(res => {
+          this.handoutList = res.rows;
+        });
+    },
+    /**
+     *
+     获取推荐列表
+     */
+    getRecommend() {
+      this.$request
+        .appCommonActivityRecommendList({
+          businessId: this.goodsData.businessId,
+          type: 1
+        })
+        .then(res => {
+          if (res.rows.length) {
+            this.recommendList = res.rows[0];
+          }
+        });
+    },
+    backSwitchOfficeData(item) {
+      this.switchPdf = item;
+      this.readerResult = null;
+      this.officeRender(this.$tools.splitImgHost(item.url));
+    },
+    //渲染xlsx
+    officeRender(url, fileName) {
+      this.loading = true;
+      axios({
+        method: "get",
+        responseType: "blob", // 设置响应文件格式
+        url: url
+      })
+        .then(({ data }) => {
+          var file = new File([data], fileName, {
+            type: "application/json",
+            lastModified: Date.now()
+          });
+          this.beforeUpload(file);
+        })
+        .catch(() => {
+          this.loading = false;
+        });
+    },
+    beforeUpload(file) {
+      let reader = new FileReader();
+      reader.readAsArrayBuffer(file);
+      reader.onload = loadEvent => {
+        let arrayBuffer = loadEvent.target.result;
+        this.readerResult = arrayBuffer;
+      };
+      reader.onloadend = e => {
+        this.loading = false;
+      };
+      return false;
+    },
+    getGoodsDetail() {
+      return new Promise(resolve => {
+        let self = this;
+        this.$request.goodsDetail(this.goodsId).then(res => {
+          self.goodsData = res.data;
+          if (this.goodsData.buyNote) {
+            this.tabList = [
+              { name: "1", label: "讲义资料" },
+              { name: "2", label: "推荐课程" },
+              { name: "3", label: "学员须知" }
+            ];
+          } else {
+            this.tabList = [
+              { name: "1", label: "讲义资料" },
+              { name: "2", label: "推荐课程" }
+            ];
+          }
+          resolve();
+        });
+      });
+    }
+  }
+};
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped lang="scss">
+.course-item {
+  float: left;
+  margin-bottom: 6px;
+}
+/deep/ .docx-wrapper {
+  padding: 0px;
+}
+/deep/ .docx-wrapper > section.docx {
+  padding: 4px !important;
+  width: auto !important;
+  min-height: auto !important;
+}
+.course-detail {
+  .section {
+    padding-bottom: 30px;
+
+    &__header {
+      height: 40px;
+      display: flex;
+      align-items: center;
+      padding: 0 20px;
+    }
+
+    &__body {
+      .course-info {
+        &__header {
+          .title {
+            height: 40px;
+            border-bottom: 1px solid #999;
+            // color: #fff;
+
+            /deep/ .el-input__icon {
+              width: 20px;
+              height: 20px;
+              border: 1px solid #eee;
+              border-radius: 4px;
+              margin-top: 10px;
+              line-height: 20px;
+            }
+
+            /deep/ .el-input__inner {
+              // color: #fff;
+              font-size: 16px;
+              background: none;
+              border: 0;
+            }
+          }
+
+          .left-box {
+            width: 810px;
+            height: 455px;
+            float: left;
+            background-size: cover;
+            background-position: center center;
+            background-repeat: no-repeat;
+            position: relative;
+            .smallBox {
+              position: absolute;
+              width: 162px;
+              height: 91px;
+              border-radius: 4px;
+              background: #fff;
+              right: 20px;
+              bottom: 75px;
+              z-index: 1998;
+              overflow: hidden;
+              /deep/ .pv-video-player {
+                // width: 100%!important;
+                // height: 100%!important;
+                transform-origin: 0 0;
+                transform: scale(0.2);
+              }
+            }
+            .overStyle {
+              overflow: auto !important;
+            }
+            .switch {
+              position: absolute;
+              right: 22px;
+              bottom: 77px;
+              z-index: 1999;
+              font-size: 30px;
+              transition: all 0.3;
+              border-radius: 50%;
+              overflow: hidden;
+              padding: 4px;
+              cursor: pointer;
+              &:hover {
+                color: #000;
+                background-color: rgba(225, 225, 225, 0.8);
+              }
+            }
+            .hideSwitchBox {
+              position: absolute;
+              right: 22px;
+              bottom: 126px;
+              z-index: 1999;
+              font-size: 30px;
+              transition: all 0.3;
+              border-radius: 50%;
+              overflow: hidden;
+              padding: 4px;
+              cursor: pointer;
+              opacity: 0.5;
+              &:hover {
+                opacity: 1;
+                color: #000;
+                background-color: rgba(225, 225, 225, 0.9);
+              }
+            }
+            .switchPdf {
+              width: 810px;
+              height: 455px;
+              overflow: auto;
+              border: 1px solid #666;
+            }
+            .video {
+              width: 100%;
+              height: 100%;
+            }
+          }
+
+          .recordStyle {
+            position: absolute;
+            bottom: 90px;
+            padding: 6px 12px;
+            left: 8px;
+            background-color: rgba(0, 0, 0, 0.4);
+            color: #fff;
+            border-radius: 24px;
+            user-select: none;
+
+            .btn_sty {
+              cursor: pointer;
+            }
+          }
+
+          .right-box {
+            width: 462px;
+            height: 455px;
+            background: #3f4449;
+            border-radius: 0px;
+            float: right;
+
+            &__header {
+              .tabs {
+                /deep/.el-tabs__nav-wrap::after {
+                  background-color: #999;
+                }
+
+                /deep/ .el-tabs__header {
+                  margin: 0;
+                }
+
+                .label {
+                  color: #fff;
+                  height: 40px;
+                  line-height: 40px;
+                  padding: 0 20px;
+                }
+
+                .item {
+                  &__title {
+                    padding-left: 12px;
+                    height: 40px;
+                    line-height: 40px;
+                    cursor: pointer;
+                    font-size: 14px;
+                    font-family: Microsoft YaHei;
+                    font-weight: bold;
+                    color: #fff;
+
+                    .el-icon-caret-right,
+                    .el-icon-caret-bottom {
+                      color: #999;
+                    }
+                  }
+                }
+              }
+
+              .title {
+                height: 40px;
+                border-bottom: 1px solid #999;
+                color: #fff;
+
+                .select {
+                  width: 100%;
+                }
+
+                /deep/ .el-input__icon {
+                  width: 20px;
+                  height: 20px;
+                  border: 1px solid #fff;
+                  border-radius: 4px;
+                  margin-top: 10px;
+                  line-height: 20px;
+                }
+
+                /deep/ .el-input__inner {
+                  color: #fff;
+                  font-size: 16px;
+                  background: none;
+                  border: 0;
+                }
+              }
+            }
+
+            &__body {
+              height: 374px;
+              overflow-y: scroll;
+
+              &::-webkit-scrollbar {
+                // width: 6px;
+                display: none;
+              }
+
+              &::-webkit-scrollbar-track {
+                background-color: #060e1a;
+                -webkit-border-radius: 2em;
+                -moz-border-radius: 2em;
+                border-radius: 2em;
+              }
+
+              &::-webkit-scrollbar-thumb {
+                background-color: #eeeeee;
+                -webkit-border-radius: 2em;
+                -moz-border-radius: 2em;
+                border-radius: 2em;
+              }
+            }
+          }
+        }
+
+        &__body {
+          /deep/ .el-tabs__item {
+            padding: 0 20px !important;
+            height: 80px;
+            line-height: 80px;
+          }
+
+          .course-img {
+            width: 100%;
+          }
+
+          .course-menu {
+            margin-top: 25px;
+
+            .left-box {
+              width: 948px;
+              float: left;
+
+              &__header {
+                padding-right: 50px;
+                position: relative;
+
+                .item {
+                  width: auto;
+                  margin-right: 24px;
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #333333;
+                  background: #eeeeee;
+                  border-radius: 8px;
+                  padding: 12px;
+                  position: relative;
+
+                  &.canlearn {
+                    background: #3f8dfd;
+                    color: #fff;
+                  }
+                }
+              }
+
+              &__body {
+                .buy-note {
+                  margin-right: 50px;
+                }
+
+                .item {
+                  margin-top: 24px;
+                  padding: 16px;
+                  background: #eee;
+                  border-radius: 10px;
+
+                  &__title {
+                    font-size: 16px;
+                    font-family: Microsoft YaHei;
+                    font-weight: bold;
+                    color: #333333;
+
+                    .note {
+                      display: inline-block;
+                      margin-left: 20px;
+                      width: 40px;
+                      height: 24px;
+                      border: 1px solid #ff3b30;
+                      border-radius: 8px;
+                      line-height: 22px;
+                      color: #ff3b30;
+                      text-align: center;
+                    }
+                  }
+
+                  &__content {
+                    margin-top: 12px;
+                    background: #f5f7fa;
+                  }
+                }
+              }
+            }
+
+            .right-box {
+              width: 255px;
+              float: right;
+
+              .title {
+                font-size: 16px;
+                font-family: Microsoft YaHei;
+                font-weight: 400;
+                color: #333333;
+                text-shadow: 0px 6px 6px rgba(85, 158, 255, 0.08);
+                position: relative;
+
+                .more {
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #999999;
+                  position: absolute;
+                  right: 0;
+                }
+              }
+            }
+          }
+
+          .answer-question {
+            &__header {
+              border-bottom: 1px solid #eee;
+
+              .textarea-wrap {
+                background: #f9f9f9;
+                border: 1px solid #eeeeee;
+                border-radius: 8px;
+
+                .textarea {
+                  height: 100%;
+                }
+              }
+
+              .submit {
+                padding: 10px 20px;
+                border-radius: 20px;
+                text-align: center;
+                font-size: 16px;
+                margin: 10px 0;
+                float: right;
+              }
+            }
+
+            &__body {
+              .question-list {
+                &__item {
+                  padding: 20px 0;
+                  display: flex;
+
+                  &__avatar {
+                    width: 40px;
+                    height: 40px;
+                    display: table-cell;
+                    border-radius: 50%;
+                    text-align: center;
+
+                    img {
+                      display: inline-block;
+                      vertical-align: middle;
+                      max-width: 100%;
+                      max-height: 100%;
+                    }
+                  }
+
+                  &__content {
+                    flex: 1;
+                    border-bottom: 1px solid #ccc;
+                    margin-left: 10px;
+
+                    .nickname {
+                      font-size: 14px;
+                      font-family: Microsoft YaHei;
+                      font-weight: bold;
+                      color: #fff;
+                      line-height: 24px;
+                    }
+
+                    .desc {
+                      font-size: 14px;
+                      font-family: Microsoft YaHei;
+                      font-weight: 400;
+                      color: #666666;
+                      line-height: 24px;
+                    }
+
+                    .time {
+                      font-size: 14px;
+                      font-family: Microsoft YaHei;
+                      font-weight: 400;
+                      color: #999999;
+                      line-height: 24px;
+
+                      .replay {
+                        float: right;
+                        font-size: 14px;
+                        font-family: Microsoft YaHei;
+                        font-weight: 400;
+                        color: #3f8dfd;
+                        line-height: 24px;
+                        margin-right: 20px;
+                      }
+
+                      .del {
+                        float: right;
+                        cursor: pointer;
+                        font-size: 14px;
+                        font-family: Microsoft YaHei;
+                        font-weight: 400;
+                        color: #ff3b30;
+                        line-height: 24px;
+                        margin-right: 20px;
+                      }
+                    }
+
+                    .reply-list {
+                      margin: 20px 0;
+                      width: 100%;
+                      background: #f9f9f9;
+                      border-radius: 8px;
+                      padding: 0 0 0 20px;
+
+                      &__item {
+                        padding: 20px 0;
+                        display: flex;
+                        border-bottom: 1px solid #ccc;
+
+                        &:nth-last-of-type(1) {
+                          border: 0;
+                        }
+
+                        &__avatar {
+                          width: 40px;
+                          height: 40px;
+                          display: table-cell;
+                          border-radius: 50%;
+                          text-align: center;
+
+                          img {
+                            display: inline-block;
+                            vertical-align: middle;
+                            max-width: 100%;
+                            max-height: 100%;
+                          }
+                        }
+
+                        &__content {
+                          border-radius: 8px;
+                          flex: 1;
+                          margin-left: 10px;
+
+                          .nickname {
+                            font-size: 14px;
+                            font-family: Microsoft YaHei;
+                            font-weight: bold;
+                            color: #fff;
+                            line-height: 24px;
+                          }
+
+                          .desc {
+                            font-size: 14px;
+                            font-family: Microsoft YaHei;
+                            font-weight: 400;
+                            color: #666666;
+                            line-height: 24px;
+                          }
+
+                          .time {
+                            font-size: 14px;
+                            font-family: Microsoft YaHei;
+                            font-weight: 400;
+                            color: #999999;
+                            line-height: 24px;
+
+                            .reply {
+                              float: right;
+                              font-size: 14px;
+                              font-family: Microsoft YaHei;
+                              font-weight: 400;
+                              color: #3f8dfd;
+                              line-height: 24px;
+                              margin-right: 20px;
+                              cursor: pointer;
+                              user-select: none;
+                            }
+
+                            .del {
+                              cursor: pointer;
+                              margin-right: 20px;
+                              float: right;
+                              font-size: 14px;
+                              font-family: Microsoft YaHei;
+                              font-weight: 400;
+                              color: #ff3b30;
+                              line-height: 24px;
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+
+          .lecture-notes {
+            &__content {
+              .left-box {
+                float: left;
+                width: 462px;
+
+                .textarea {
+                  border-bottom: 1px solid #eee;
+
+                  .submit {
+                    float: right;
+                    width: 138px;
+                    padding: 10px 0;
+                    margin: 10px 0 25px 0;
+                    border-radius: 20px;
+                    text-align: center;
+                    font-size: 16px;
+                  }
+                }
+
+                .note-list {
+                  &__content {
+                    border-bottom: 1px solid #eee;
+
+                    &__title {
+                      width: 216px;
+                      height: 24px;
+                      background: #ccc;
+                      border-radius: 24px;
+                      font-size: 14px;
+                      color: #666666;
+                      text-align: center;
+                      line-height: 24px;
+                      margin: 20px 0;
+                    }
+                  }
+
+                  &__item {
+                    display: flex;
+                    padding: 15px;
+
+                    .el-icon-video-play {
+                      cursor: pointer;
+                      font-size: 20px;
+                      color: #3f8dfd;
+                    }
+
+                    &__content {
+                      flex: 1;
+                      margin-left: 10px;
+
+                      .title {
+                        cursor: pointer;
+                        font-size: 14px;
+                        font-family: Microsoft YaHei;
+                        font-weight: bold;
+                        color: #3f8dfd;
+                        line-height: 24px;
+                      }
+
+                      .desc {
+                        font-size: 14px;
+                        font-family: Microsoft YaHei;
+                        font-weight: 400;
+                        color: #666666;
+                        line-height: 24px;
+                      }
+
+                      .time {
+                        font-size: 14px;
+                        font-family: Microsoft YaHei;
+                        font-weight: 400;
+                        color: #999999;
+                        line-height: 24px;
+                      }
+                    }
+                  }
+                }
+
+                .pagination {
+                  margin-top: 30px;
+                  text-align: center;
+                }
+              }
+
+              .right-box {
+                width: 786px;
+                float: right;
+
+                .lecture-list {
+                  background: #f5f7fa;
+                  border-radius: 8px;
+
+                  &__header {
+                    padding: 0 16px;
+                    height: 40px;
+                    line-height: 40px;
+                    font-size: 18px;
+                    font-family: Microsoft YaHei;
+                    font-weight: bold;
+                    color: #333333;
+
+                    .slide-btn {
+                      cursor: pointer;
+                      float: right;
+                      font-size: 14px;
+                      font-family: Microsoft YaHei;
+                      font-weight: 400;
+                      color: #999999;
+                    }
+                  }
+
+                  &__body {
+                    .list {
+                      &__item {
+                        border-top: 1px solid #fff;
+                        padding: 0 8px 0 16px;
+                        height: 56px;
+                        line-height: 55px;
+                        display: flex;
+                        align-items: center;
+
+                        .title {
+                          flex: 1;
+                          font-size: 16px;
+                          font-family: Microsoft YaHei;
+                          font-weight: 400;
+                          color: #333333;
+                        }
+
+                        .btns {
+                          .btn {
+                            cursor: pointer;
+                            display: inline-block;
+                            vertical-align: middle;
+                            width: 80px;
+                            height: 32px;
+                            background: #ffffff;
+                            border: 1px solid #3f8dfd;
+                            border-radius: 16px;
+                            text-align: center;
+                            line-height: 30px;
+                            color: #3f8dfd;
+                            margin: 0 8px;
+                          }
+                        }
+                      }
+                    }
+                  }
+
+                  &__footer {
+                    margin-top: 24px;
+
+                    .lecture-scan {
+                      background: #f5f7fa;
+                      border-radius: 8px;
+                      overflow: hidden;
+
+                      &__header {
+                        height: 40px;
+                        line-height: 40px;
+                        padding: 0 16px;
+                        font-size: 16px;
+                        font-family: Microsoft YaHei;
+                        font-weight: bold;
+                        color: #333333;
+                      }
+
+                      &__body {
+                        height: 800px;
+                        text-align: center;
+                        overflow-y: scroll;
+
+                        .iframe {
+                          width: 100%;
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  .take-photo {
+    /deep/ .el-dialog__header {
+      display: none;
+    }
+
+    /deep/ .el-dialog__body {
+      padding: 0;
+      overflow: unset;
+    }
+
+    &__close {
+      cursor: pointer;
+      position: absolute;
+      right: 0;
+      top: -28px;
+      width: 24px;
+      height: 24px;
+      line-height: 24px;
+      text-align: center;
+      color: #eee;
+      border: 1px solid #eee;
+      border-radius: 50%;
+    }
+
+    &__header {
+      height: 40px;
+      border-bottom: 1px solid #eee;
+      line-height: 40px;
+      font-size: 16px;
+      font-family: Microsoft YaHei;
+      font-weight: bold;
+      color: #333333;
+      padding-left: 24px;
+    }
+
+    &__body {
+      // height: 400px;
+      padding: 40px 24px;
+
+      .left-box {
+        width: 336px;
+        float: left;
+
+        .title {
+          font-size: 16px;
+          font-family: Microsoft YaHei;
+          font-weight: bold;
+          color: #ff3b30;
+          line-height: 24px;
+        }
+
+        .content {
+          font-size: 14px;
+          font-family: Microsoft YaHei;
+          font-weight: 400;
+          color: #333333;
+          line-height: 28px;
+          margin-top: 32px;
+        }
+      }
+
+      .right-box {
+        float: right;
+        width: 400px;
+        height: 400px;
+        position: relative;
+        overflow: hidden;
+
+        video {
+          width: 100%;
+          height: 100%;
+        }
+
+        .mask {
+          width: 55%;
+          height: 200px;
+          position: absolute;
+          top: 0;
+          left: 0;
+          right: 0;
+          bottom: 0;
+          margin: 30px auto 0;
+          box-shadow: 0 0 0 2000px rgba(0, 0, 0, 0.4);
+        }
+      }
+    }
+
+    &__footer {
+      height: 90px;
+      border-top: 1px solid #eee;
+      text-align: center;
+
+      .take {
+        display: inline-block;
+        width: 200px;
+        height: 40px;
+        padding: 0;
+        border-radius: 20px;
+        text-align: center;
+        line-height: 40px;
+        margin: 24px auto;
+      }
+    }
+  }
+
+  .info {
+    &__content {
+      height: 500px;
+      overflow-y: scroll;
+
+      .handCenter {
+        width: 600px;
+        height: 300px;
+        background: #ccc;
+      }
+
+      .upload-box {
+        display: inline-block;
+        vertical-align: top;
+
+        .el-icon-error {
+          cursor: pointer;
+          z-index: 99;
+          position: absolute;
+          left: 100%;
+          bottom: 100%;
+          font-size: 20px;
+          color: red;
+        }
+      }
+    }
+  }
+}
+
+.answer-question {
+  max-height: 416px;
+  overflow-y: auto;
+  padding: 16px;
+  background: rgb(63, 68, 73);
+
+  &::-webkit-scrollbar {
+    display: none;
+  }
+
+  &__header {
+    border-bottom: 1px solid #555;
+
+    .textarea-wrap {
+      // background: #65696D;
+      border: 1px solid #555;
+      border-radius: 8px;
+
+      .textarea {
+        height: 100%;
+
+        &::placeholder {
+          color: red;
+        }
+      }
+    }
+
+    .submit {
+      padding: 10px 20px;
+      border-radius: 2px;
+      text-align: center;
+      font-size: 16px;
+      margin: 10px 0;
+      float: right;
+    }
+  }
+
+  &__body {
+    .question-list {
+      &__item {
+        padding: 20px 0;
+        display: flex;
+
+        &__avatar {
+          width: 40px;
+          height: 40px;
+          display: table-cell;
+          border-radius: 50%;
+          text-align: center;
+          overflow: hidden;
+
+          img {
+            display: inline-block;
+            vertical-align: middle;
+            max-width: 100%;
+            max-height: 100%;
+          }
+        }
+
+        &__content {
+          flex: 1;
+          border-bottom: 1px solid #555555;
+          margin-left: 10px;
+
+          .nickname {
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #f5f5f5;
+            line-height: 24px;
+          }
+
+          .desc {
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: 400;
+            color: #cccccc;
+            line-height: 24px;
+          }
+
+          .time {
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: 400;
+            color: #999999;
+            line-height: 24px;
+
+            .replay {
+              float: right;
+              font-size: 14px;
+              font-family: Microsoft YaHei;
+              font-weight: 400;
+              color: #3f8dfd;
+              line-height: 24px;
+              margin-right: 20px;
+            }
+
+            .del {
+              float: right;
+              cursor: pointer;
+              font-size: 14px;
+              font-family: Microsoft YaHei;
+              font-weight: 400;
+              color: #fa8c16;
+              line-height: 24px;
+              margin-right: 20px;
+            }
+          }
+
+          .reply-list {
+            margin: 20px 0;
+            width: 100%;
+            background-color: #2f3236;
+            border-radius: 8px;
+            padding: 0 0 0 20px;
+
+            &__item {
+              padding: 20px 0;
+              display: flex;
+              border-bottom: 1px solid #555555;
+
+              &:nth-last-of-type(1) {
+                border: 0;
+              }
+
+              &__avatar {
+                width: 40px;
+                height: 40px;
+                display: table-cell;
+                border-radius: 50%;
+                text-align: center;
+                border-radius: 50%;
+                overflow: hidden;
+
+                img {
+                  display: inline-block;
+                  vertical-align: middle;
+                  max-width: 100%;
+                  max-height: 100%;
+                }
+              }
+
+              &__content {
+                border-radius: 8px;
+                flex: 1;
+                margin-left: 10px;
+
+                .nickname {
+                  font-size: 14px;
+                  font-family: Microsoft YaHei;
+                  font-weight: bold;
+                  color: #f5f5f5;
+                  line-height: 24px;
+                }
+
+                .desc {
+                  font-size: 14px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #666666;
+                  line-height: 24px;
+                }
+
+                .time {
+                  font-size: 14px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #999999;
+                  line-height: 24px;
+
+                  .reply {
+                    float: right;
+                    font-size: 14px;
+                    font-family: Microsoft YaHei;
+                    font-weight: 400;
+                    color: #3f8dfd;
+                    line-height: 24px;
+                    margin-right: 20px;
+                    cursor: pointer;
+                    user-select: none;
+                  }
+
+                  .del {
+                    cursor: pointer;
+                    margin-right: 20px;
+                    float: right;
+                    font-size: 14px;
+                    font-family: Microsoft YaHei;
+                    font-weight: 400;
+                    color: #ff3b30;
+                    line-height: 24px;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+.lecture-notes {
+  &::-webkit-scrollbar {
+    display: none;
+  }
+
+  max-height: 416px;
+  overflow-y: auto;
+  padding: 16px;
+  background: rgb(63, 68, 73);
+
+  &__content {
+    .left-boxs {
+      // float: left;
+      // width: 462px;
+
+      .textarea {
+        border-bottom: 1px solid #555555;
+
+        .submit {
+          padding: 10px 20px;
+          border-radius: 2px;
+          text-align: center;
+          font-size: 16px;
+          margin: 10px 0;
+          float: right;
+        }
+      }
+
+      .note-list {
+        &__content {
+          border-bottom: 1px solid #555555;
+
+          &__title {
+            width: 216px;
+            height: 24px;
+            background: #ccc;
+            border-radius: 24px;
+            font-size: 14px;
+            color: #666666;
+            text-align: center;
+            line-height: 24px;
+            margin: 20px 0;
+          }
+        }
+
+        &__item {
+          display: flex;
+          padding: 15px;
+
+          .el-icon-video-play {
+            cursor: pointer;
+            font-size: 20px;
+            color: #3f8dfd;
+          }
+
+          &__content {
+            flex: 1;
+            margin-left: 10px;
+
+            .title {
+              cursor: pointer;
+              font-size: 14px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #3f8dfd;
+              line-height: 24px;
+            }
+
+            .desc {
+              font-size: 14px;
+              font-family: Microsoft YaHei;
+              font-weight: 400;
+              color: #666666;
+              line-height: 24px;
+            }
+
+            .time {
+              font-size: 14px;
+              font-family: Microsoft YaHei;
+              font-weight: 400;
+              color: #999999;
+              line-height: 24px;
+            }
+          }
+        }
+      }
+
+      .pagination {
+        margin-top: 30px;
+        text-align: center;
+      }
+    }
+
+    .right-box {
+      width: 786px;
+      float: right;
+
+      .lecture-list {
+        background: #f5f7fa;
+        border-radius: 8px;
+
+        &__header {
+          padding: 0 16px;
+          height: 40px;
+          line-height: 40px;
+          font-size: 18px;
+          font-family: Microsoft YaHei;
+          font-weight: bold;
+          color: #333333;
+
+          .slide-btn {
+            cursor: pointer;
+            float: right;
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: 400;
+            color: #999999;
+          }
+        }
+
+        &__body {
+          .list {
+            &__item {
+              border-top: 1px solid #fff;
+              padding: 0 8px 0 16px;
+              height: 56px;
+              line-height: 55px;
+              display: flex;
+              align-items: center;
+
+              .title {
+                flex: 1;
+                font-size: 16px;
+                font-family: Microsoft YaHei;
+                font-weight: 400;
+                color: #333333;
+              }
+
+              .btns {
+                .btn {
+                  cursor: pointer;
+                  display: inline-block;
+                  vertical-align: middle;
+                  width: 80px;
+                  height: 32px;
+                  background: #ffffff;
+                  border: 1px solid #3f8dfd;
+                  border-radius: 16px;
+                  text-align: center;
+                  line-height: 30px;
+                  color: #3f8dfd;
+                  margin: 0 8px;
+                }
+              }
+            }
+          }
+        }
+
+        &__footer {
+          margin-top: 24px;
+
+          .lecture-scan {
+            background: #f5f7fa;
+            border-radius: 8px;
+            overflow: hidden;
+
+            &__header {
+              height: 40px;
+              line-height: 40px;
+              padding: 0 16px;
+              font-size: 16px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #333333;
+            }
+
+            &__body {
+              height: 800px;
+              text-align: center;
+              overflow-y: scroll;
+
+              .iframe {
+                width: 100%;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+.user_notes {
+  border-bottom: 1px solid #555;
+
+  .p1 {
+    margin: 8px 0px;
+    color: #3f8dfd;
+    font-size: 14px;
+
+    span {
+      float: right;
+      color: #999;
+      font-size: 12px;
+    }
+  }
+
+  .p2 {
+    margin-bottom: 8px;
+    font-size: 14px;
+    color: #ccc;
+  }
+}
+
+/deep/ textarea {
+  background: #65696d;
+  color: #c7c7c7;
+  border-color: transparent;
+}
+
+/deep/ .el-input__count {
+  color: #999;
+  background: transparent;
+}
+
+.lecture-notesjy {
+  display: flex;
+  flex-direction: column;
+  max-height: 416px;
+
+  .listItem {
+    padding-bottom: 14px;
+    margin-bottom: 10px;
+    border-bottom: 1px solid #eee;
+
+    .titles {
+      color: #fff;
+      font-weight: bold;
+      text-align: center;
+      padding: 10px;
+    }
+
+    .btns {
+      display: flex;
+      justify-content: space-around;
+      align-items: center;
+
+      .btn {
+        border-radius: 8px;
+        background-color: #fff;
+        padding: 6px 16px;
+        user-select: none;
+        cursor: pointer;
+        transition: all 0.2s;
+
+        &:hover {
+          background-color: #f2f7ff;
+          color: #3f8dfd;
+        }
+      }
+    }
+  }
+
+  .lecture-listFooter {
+    flex: 1;
+    overflow: auto;
+  }
+}
+</style>

+ 483 - 0
src/pages/handout-list/index.vue

@@ -0,0 +1,483 @@
+<template>
+  <div class="payment">
+    <Header @search="search($event)"></Header>
+    <section class="section">
+      <div class="section__header">
+        <div class="container">
+          <el-breadcrumb separator="/">
+            <el-breadcrumb-item :to="{ path: '/index' }"
+              >首页</el-breadcrumb-item
+            >
+            <el-breadcrumb-item>课程</el-breadcrumb-item>
+          </el-breadcrumb>
+        </div>
+      </div>
+      <div class="section__body">
+        <div class="container">
+          <div class="course-classify">
+            <div class="course-classify__list">
+              <div class="left-item">教育类型:</div>
+              <div class="right-item">
+                <div class="list">
+                  <!-- <div
+                    class="item"
+                    :class="{ active: typeKey == '' }"
+                    @click="changeType('')"
+                  >
+                    全部
+                  </div> -->
+                  <div
+                    class="item"
+                    v-for="(item, index) in typeList"
+                    :key="index"
+                    :class="{ active: params.educationTypeId == item.id }"
+                    @click="changeType(item)"
+                  >
+                    {{ item.educationName }}
+                  </div>
+                </div>
+              </div>
+            </div>
+            <div
+              class="course-classify__list"
+              v-if="businessList.length > 0 && params.educationTypeId"
+            >
+              <div class="left-item">培训项目:</div>
+              <div class="right-item">
+                <div class="list">
+                  <!-- <div class="item active">全部</div> -->
+                  <div
+                    class="item"
+                    v-for="(item, index) in businessList"
+                    :key="index"
+                    :class="{ active: params.businessId == item.id }"
+                    @click="changeBusiness(item)"
+                  >
+                    {{ item.aliasName }}
+                  </div>
+                </div>
+              </div>
+            </div>
+            <div class="course-classify__list" v-if="subjectList.length > 0">
+              <div class="left-item">科目分类:</div>
+              <div class="right-item">
+                <div class="list">
+                  <div
+                    class="item"
+                    v-for="(item, index) in subjectList"
+                    :key="index"
+                    :class="{ active: params.subjectId == item.id }"
+                    @click="changeSubject(item)"
+                  >
+                    {{ item.subjectName }}
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="section__footer">
+        <div class="container">
+          <div class="course-list">
+            <div class="course-list__header">
+              <div class="sort-list">
+                <div
+                  class="sort-list__item"
+                  @click="changeSort(1)"
+                  :class="{ active: params.sortType == 1 ? true : false }"
+                >
+                  综合排序
+                </div>
+                <div
+                  class="sort-list__item"
+                  @click="changeSort(2)"
+                  :class="{ active: params.sortType == 2 ? true : false }"
+                >
+                  低价优先
+                </div>
+                <div
+                  class="sort-list__item"
+                  @click="changeSort(3)"
+                  :class="{ active: params.sortType == 3 ? true : false }"
+                >
+                  高价优先
+                </div>
+              </div>
+            </div>
+            <div class="course-list__body">
+              <LoadingBox v-if="loading"></LoadingBox>
+              <ul v-else class="list clearfix">
+                <li
+                  class="course-item"
+                  v-for="(item, index) in goodsList"
+                  :key="index"
+                >
+                  <GoodsItem :item="item"></GoodsItem>
+                </li>
+              </ul>
+            </div>
+          </div>
+
+          <div class="pagination">
+            <el-pagination
+              @current-change="currentChange"
+              background
+              layout="prev, pager, next"
+              :total="total"
+              :pager-count="5"
+              :page-size="params.pageSize"
+            >
+            </el-pagination>
+          </div>
+        </div>
+      </div>
+    </section>
+
+    <ToolBar></ToolBar>
+    <Footer></Footer>
+  </div>
+</template>
+
+<script>
+import { cancel } from "@/apis/common.js";
+import LoadingBox from "@/components/loadingBox/index";
+import Footer from "@/components/footer/index";
+import Header from "@/components/header/index";
+import ToolBar from "@/components/toolbar/index";
+import GoodsItem from "@/components/goodsItem/index";
+import { mapMutations } from "vuex";
+export default {
+  name: "PaymentSuccess",
+  components: {
+    Footer,
+    Header,
+    ToolBar,
+    GoodsItem,
+    LoadingBox
+  },
+  data() {
+    return {
+      projectId: "",
+      typeList: [],
+      businessList: [],
+      subjectList: [],
+      total: 0,
+      params: {
+        projectId: "",
+        educationTypeId: "",
+        businessId: "",
+        subjectId: "",
+        pageNum: 1,
+        pageSize: 15,
+        goodsStatus: 1,
+        goodsType: 8,
+        sortType: 1,
+        searchKey: "",
+        showStatus: 1
+      },
+      goodsList: [],
+      loading: false
+    };
+  },
+  mounted() {
+    this.params.goodsName = this.$route.query.searchKey || "";
+    // this.params.searchKey = this.$route.query.searchKey || "";
+    this.params.educationTypeId = this.$route.query.educationId || "";
+    // this.params.projectId = this.$route.query.projectId || "";
+    this.params.businessId = this.$route.query.businessId || "";
+    if (this.params.businessId) {
+      this.getSubjectList();
+    }
+    this.getEducationTypeList();
+  },
+  methods: {
+    ...mapMutations(["getCartCount"]),
+    search(key) {
+      this.params.goodsName = key || "";
+      // this.params.searchKey = key || "";
+      this.params.projectId = "";
+      this.params.educationTypeId = "";
+      this.params.businessId = "";
+      this.params.subjectId = "";
+      this.changeSubject();
+    },
+    changeSort(sortType) {
+      if (this.params.sortType == sortType) return;
+      this.params.sortType = sortType;
+      this.changeSubject();
+    },
+    currentChange(e) {
+      this.params.pageNum = e;
+      this.changeSubject();
+    },
+    toGoodsDetail(item) {
+      this.$router.push({
+        path: "/course-detail/" + item.goodsId
+      });
+    },
+
+    addCart(item) {
+      this.$request
+        .addCart({ goodsId: item.goodsId })
+        .then(res => {
+          this.getCartCount();
+          this.$message({
+            message: "加入购物车成功",
+            type: "success"
+          });
+        })
+        .catch(err => {
+          if (err.code == 500) {
+            this.$message({
+              message: err.msg,
+              type: "warning"
+            });
+          }
+        });
+    },
+
+    /**
+     * 切换教育类型
+     */
+    changeType(item) {
+      if (this.params.educationTypeId == item.id) {
+        return;
+      }
+      this.params.projectId = "";
+      this.params.educationTypeId = item.id;
+      this.params.businessId = "";
+      this.businessList = [];
+      this.params.subjectId = "";
+      this.subjectList = [];
+      this.params.pageNum = 1;
+      this.getBusinessList();
+      this.changeSubject();
+    },
+
+    /**
+     * 切换科目分类
+     */
+    changeSubject(item) {
+      if (item) {
+        if (this.params.subjectId != item.id) {
+          this.params.subjectId = item.id;
+          this.params.pageNum = 1;
+        }
+      }
+      if (cancel) {
+        cancel("取消请求");
+      }
+      this.loading = true;
+      this.$request
+        .goodsList(this.params)
+        .then(res => {
+          this.goodsList = res.rows;
+          this.total = res.total;
+        })
+        .finally(() => {
+          this.loading = false;
+        });
+    },
+
+    /**
+     * 获取科目分类
+     */
+    getSubjectList() {
+      this.$request
+        .subjectList({
+          businessId: this.params.businessId,
+          projectId: this.projectId,
+          educationId: this.params.educationTypeId
+        })
+        .then(res => {
+          this.subjectList = res.rows;
+          this.subjectList.unshift({ id: 0, subjectName: "全部" });
+          this.params.subjectId = 0;
+
+          this.changeSubject(this.subjectList[0]);
+        });
+    },
+
+    /**
+     * 切换业务层级
+     */
+    changeBusiness(item) {
+      if (this.params.subjectId == item.id) {
+        return;
+      }
+      this.params.businessId = item.id;
+      this.projectId = item.projectId;
+      this.params.subjectId = "";
+      this.subjectList = [];
+      this.params.pageNum = 1;
+      this.getSubjectList();
+    },
+
+    /**
+     * 获取业务层级
+     */
+    getBusinessList() {
+      this.$request
+        .businessList({ educationId: this.params.educationTypeId })
+        .then(res => {
+          this.businessList = res.rows.filter(item => item.aliasName);
+          this.projectId = this.businessList[0].projectId;
+        });
+    },
+
+    /**
+     * 获取教育类型
+     */
+    getEducationTypeList() {
+      let alls = {
+        educationName: "全部",
+        id: "",
+        status: 1,
+        sort: 0
+      };
+      this.$request.educationTypeList().then(res => {
+        res.rows.unshift(alls);
+        this.typeList = res.rows;
+
+        //有传入教育类型
+        if (this.params.educationTypeId) {
+          this.getBusinessList();
+        } else {
+          this.params.educationTypeId = res.rows[0].id;
+          this.getBusinessList();
+        }
+        this.changeSubject();
+      });
+    }
+  }
+};
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped lang="scss">
+.payment {
+  .section {
+    &__header {
+      height: 40px;
+      display: flex;
+      align-items: center;
+      padding: 0 20px;
+    }
+
+    &__body {
+      background: #ebf2fc;
+      .course-classify {
+        overflow: hidden;
+
+        &__list {
+          display: flex;
+          margin: 6px 0;
+          align-items: flex-start;
+          .left-item {
+            margin-top: 10px;
+            padding: 8px 0;
+            width: 80px;
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: 400;
+            color: #333333;
+          }
+
+          .right-item {
+            flex: 1;
+            .list {
+              display: flex;
+              flex-wrap: wrap;
+              .item {
+                cursor: pointer;
+                border-radius: 8px;
+                margin: 10px;
+                padding: 8px 16px;
+                color: #666666;
+                font-size: 16px;
+                background: #f7f9fc;
+                color: #999;
+
+                &.active {
+                  color: #fff;
+                  background: #3f8dfd;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    &__footer {
+      .course-list {
+        &__header {
+          margin-top: 32px;
+          .sort-list {
+            display: flex;
+            align-items: center;
+            &__item {
+              cursor: pointer;
+              width: 96px;
+              height: 32px;
+              border-radius: 16px;
+              background: #ffffff;
+              border: 1px solid #bfbfbf;
+              border-radius: 16px;
+              text-align: center;
+              line-height: 30px;
+              font-size: 16px;
+              margin-right: 20px;
+
+              &.active {
+                background: #ebf2fc;
+                border: 1px solid #3f8dfd;
+                border-radius: 16px;
+                color: #3f8dfd;
+              }
+            }
+          }
+        }
+
+        &__body {
+          .list {
+            width: 100%;
+
+            .course-item {
+              float: left;
+            }
+          }
+        }
+
+        &__footer {
+          overflow: hidden;
+          .btn {
+            cursor: pointer;
+            width: 146px;
+            height: 40px;
+            background: #e3eaf7;
+            border-radius: 8px;
+            margin: 20px auto 40px;
+            color: #3f8dfd;
+            text-align: center;
+            line-height: 40px;
+
+            &:hover {
+              color: #fff;
+              box-shadow: 0px 8px 4px 0px rgba(7, 82, 208, 0.08);
+              background: #3f8dfd;
+            }
+          }
+        }
+      }
+
+      .pagination {
+        padding: 30px 0;
+        text-align: center;
+      }
+    }
+  }
+}
+</style>

+ 7 - 0
src/pages/home/index.vue

@@ -137,6 +137,13 @@
               @click="go('/live-list')"
               >直播</a
             >
+            <a
+              v-if="item.name === '讲义资料'"
+              :key="index"
+              class="tab"
+              @click="go('/handout-list')"
+              >讲义资料</a
+            >
             <a
               v-if="item.name === '积分商城'"
               :key="index"

+ 1 - 1
src/pages/live-detail/index.vue

@@ -1371,7 +1371,7 @@
                         <div class="left-box">
                           <div class="left-box__body">
                             <div
-                              class="buy-note"
+                              class="buy-note ql-editor" style="white-space: pre-wrap" 
                               v-html="
                                 goodsData.buyNote &&
                                 goodsData.buyNote.replace(/\n|\r\n/g, '<br>')

+ 1 - 1
src/pages/living-room/index.vue

@@ -335,7 +335,7 @@ export default {
     // 获取直播间跳转参数的接口
     getParam() {
       let decodeValue = decodeURIComponent(location.search.slice(5))
-      let paramArr = Base64.decode(decodeValue).split('&')
+      let paramArr = Base64.decode(decodeValue.split('&')[0]).split('&')
       console.log('paramArr:',paramArr)
       let paramObj = {}
       for (let i = 0; i < paramArr.length; i++) {

+ 8 - 0
src/pages/person-center/index.vue

@@ -102,6 +102,14 @@
                 </router-link>
               </div>
             </div>
+            <div class="nav__section">
+              <div class="title">我的讲义资料</div>
+              <div class="list">
+                <router-link to="/person-center/my-handout">
+                  <div class="item">开始学习</div>
+                </router-link>
+              </div>
+            </div>
             <div class="nav__section">
               <div class="title">个人管理</div>
               <div class="list">

+ 208 - 95
src/pages/person-center/my-course/components/AppointTest.vue

@@ -1,20 +1,31 @@
 <template>
-    <div class="appoint_test">
-        <el-dialog
-            title="预约考试"
-            :visible.sync="appointModal"
-            width="600px"
-            class="appoint-modal"
-            :close-on-click-modal="false"
-            :close-on-press-escape="false"
-            :before-close="cancel"
+  <div class="appoint_test">
+    <el-dialog
+      title="预约考试"
+      :visible.sync="appointModal"
+      width="800px"
+      class="appoint-modal"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      :before-close="cancel"
+    >
+      <div
+        v-if="
+          appointItem.examApplyGoodsList &&
+            appointItem.examApplyGoodsList.length &&
+            false
+        "
+        class="appoint-modal"
+      >
+        <div
+          v-for="(appointChild, appointIndex) in appointItem.examApplyGoodsList"
+          :key="appointIndex"
+          class="appoint_item"
         >
-            <div v-if="appointItem.examApplyGoodsList && appointItem.examApplyGoodsList.length" class="appoint-modal">
-                <div v-for="(appointChild, appointIndex) in appointItem.examApplyGoodsList" :key="appointIndex"  class="appoint_item" >
-                    <div class="names">{{ appointChild.applyName }}</div>
-                    <div class="btns" @click="confirmAppoint(appointChild)">预约</div>
-                </div>
-                <!-- <el-radio
+          <div class="names">{{ appointChild.applyName }}</div>
+          <div class="btns" @click="confirmAppoint(appointChild)">预约</div>
+        </div>
+        <!-- <el-radio
                     v-for="(appointChild, appointIndex) in appointItem.examApplyGoodsList"
                     v-model="applyId"
                     :key="appointIndex"
@@ -22,99 +33,201 @@
                 >
                     {{ appointChild.applyName }}
                 </el-radio> -->
-            </div>
-            <div v-else class="no_data">暂无考试预约~</div>
-            <!-- <span slot="footer" class="dialog-footer">
+      </div>
+      <el-calendar
+        v-model="getTimes"
+        v-if="
+          appointItem.examApplyGoodsList &&
+            appointItem.examApplyGoodsList.length
+        "
+        ><template slot="dateCell" slot-scope="{ date, data }"
+          ><p style="text-align: center;">
+            {{
+              data.day
+                .split("-")
+                .slice(1)
+                .join("-")
+            }}
+          </p>
+          <template
+            v-for="(item, index) in getDayData(appointItem.examApplyGoodsList)"
+          >
+            <p
+              v-if="item.applyTime == new Date(date).getTime() / 1000"
+              class="liTime"
+              @click="confirmAppoint(item)"
+            >
+              {{ item.applyMoment }}
+            </p>
+          </template>
+        </template>
+      </el-calendar>
+      <div v-else class="no_data">暂无考试预约~</div>
+      <!-- <span slot="footer" class="dialog-footer">
                 <el-button @click="cancel()">取 消</el-button>
                 <el-button type="primary" @click="confirmAppoint">立即预约</el-button>
             </span> -->
-        </el-dialog>
-    </div>
+    </el-dialog>
+    <dialogForm
+      ref="dialogForm"
+      :dialogVisible.sync="dialogVisible"
+      :info="dialogInfo"
+      :listData="dialogList"
+    />
+  </div>
 </template>
 
 <script>
+import dialogForm from "./dialogForm.vue";
 export default {
-    name: 'appoint_test',
-    props: {
-        appointModal: {
-            type: Boolean,
-            default: false,
-        },
-        appointItem: {
-            type: Object,
-            default: () => {}
-        },
+  name: "appoint_test",
+  components: { dialogForm },
+  props: {
+    appointModal: {
+      type: Boolean,
+      default: false
     },
-    data() {
-        return {
-            applyId: "",
-        }
+    appointItem: {
+      type: Object,
+      default: () => {}
+    }
+  },
+  data() {
+    return {
+      applyId: "",
+      getTimes: "",
+      dialogInfo: {},
+      dialogList:{},
+      dialogVisible: false
+    };
+  },
+  computed: {
+    getDayData: function() {
+      return function(array) {
+        return array;
+      };
+    }
+  },
+  methods: {
+    cancel() {
+      this.$emit("update:appointModal", false);
+    },
+    openBoxs() {
+      this.$request.get7dayAfterTime().then(res => {
+        this.getTimes = res.data * 1000;
+      });
     },
-    methods: {
-        cancel() {
-            this.$emit('update:appointModal', false)
-        },
-        confirmAppoint(item) {
-            // if (!this.applyId) {
-            //     this.$message.warning("请选择要预约的考试");
-            //     return;
-            // }
-            var data = {
-                goodsId: this.appointItem.goodsId,
-                gradeId: this.appointItem.gradeId,
-                applyId: item.applyId,
-                orderGoodsId: this.appointItem.orderGoodsId,
-            };
-            this.$request.getApplysubscribe(data).then((res) => {
-                this.$router.push({
-                    path: "/person-center/my-examination/appointment",
-                    query: {
-                    goodsId: this.appointItem.goodsId,
-                    gradeId: this.appointItem.gradeId,
-                    orderGoodsId: this.appointItem.orderGoodsId,
-                    applyId: item.applyId,
-                    },
-                });
-            }).catch((err) => {
-                this.$message({
-                    type: "warning",
-                    message: err.msg,
-                });
+    confirmAppoint(item) {
+      var data = {
+        goodsId: this.appointItem.goodsId,
+        gradeId: this.appointItem.gradeId,
+        applyId: item.applyId,
+        orderGoodsId: this.appointItem.orderGoodsId
+      };
+      this.$request
+        .getApplysubscribe(data)
+        .then(res => {
+          if (res.data.applyStatus) {
+            res.data.applyStatus = res.data.applyStatus.split(",");
+          }
+          this.dialogList = res.data
+          this.dialogInfo = data;
+          this.dialogVisible = true;
+        })
+        .catch(err => {
+          this.$message.warning(err.msg);
+        });
+      return;
+      // if (!this.applyId) {
+      //     this.$message.warning("请选择要预约的考试");
+      //     return;
+      // }
+      this.$confirm("确定预约" + item.applyName, "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      })
+        .then(() => {
+          var data = {
+            goodsId: this.appointItem.goodsId,
+            gradeId: this.appointItem.gradeId,
+            applyId: item.applyId,
+            orderGoodsId: this.appointItem.orderGoodsId
+          };
+          this.$request
+            .getApplysubscribe(data)
+            .then(res => {
+              this.$router.push({
+                path: "/person-center/my-examination/appointment",
+                query: {
+                  goodsId: this.appointItem.goodsId,
+                  gradeId: this.appointItem.gradeId,
+                  orderGoodsId: this.appointItem.orderGoodsId,
+                  applyId: item.applyId
+                }
+              });
+            })
+            .catch(err => {
+              this.$message({
+                type: "warning",
+                message: err.msg
+              });
             });
-        },
+        })
+        .catch(() => {});
     }
-}
+  }
+};
 </script>
 
 <style lang="scss" scoped>
 .appoint_item {
-    width: 100%;
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    height: 84px;
-    border-bottom: 1px solid #F0F0F0;
-    .names {
-        font-size: 14px;
-        font-weight: 500;
-        color: #303030;
-    }
-    .btns {
-        width: 54px;
-        height: 28px;
-        line-height: 28px;
-        text-align: center;
-        background: #FFF5EC;
-        border-radius: 4px;
-        font-size: 12px;
-        font-weight: 500;
-        color: #F67205;
-        cursor: pointer;
-    }
-    .no_data {
-        text-align: center;
-        font-size: 16px;
-        margin-bottom: 20px;
-    }
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  height: 84px;
+  border-bottom: 1px solid #f0f0f0;
+  .names {
+    font-size: 14px;
+    font-weight: 500;
+    color: #303030;
+  }
+  .btns {
+    width: 54px;
+    height: 28px;
+    line-height: 28px;
+    text-align: center;
+    background: #fff5ec;
+    border-radius: 4px;
+    font-size: 12px;
+    font-weight: 500;
+    color: #f67205;
+    cursor: pointer;
+  }
+  .no_data {
+    text-align: center;
+    font-size: 16px;
+    margin-bottom: 20px;
+  }
+}
+.liTime {
+  color: #fff;
+  background: deepskyblue;
+  padding: 2px;
+  text-align: center;
+  margin-bottom: 4px;
+  cursor: pointer;
+  &:last-child {
+    margin-bottom: 0px;
+  }
+}
+/deep/ .el-calendar-day {
+  min-height: 85px;
+  height: auto!important;
+}
+/deep/ .el-calendar-table .el-calendar-day:hover {
+  background-color: transparent;
+  cursor: default;
 }
-</style>
+</style>

+ 339 - 0
src/pages/person-center/my-course/components/dialogForm.vue

@@ -0,0 +1,339 @@
+<template>
+  <div class="dislogTipBox">
+    <el-dialog
+      title="预约考试"
+      :visible.sync="isShow"
+      width="800px"
+      class="appoint-modal"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      ><el-form
+        class="invoice-content"
+        ref="listData"
+        :model="listData"
+        label-width="100px"
+      >
+        <div class="invoice-content__header">
+          <el-descriptions :title="listData.applyName" :column="1">
+            <el-descriptions-item label="报名时间"
+              >{{ $tools.timestampToTime(listData.applyStartTime) || "" }} ~
+              {{
+                $tools.timestampToTime(listData.applyEndTime) || ""
+              }}</el-descriptions-item
+            >
+            <el-descriptions-item label="温馨提示">{{
+              listData.applyIntroduce || ""
+            }}</el-descriptions-item>
+            <el-descriptions-item label="报考专业" :span="2">{{
+              listData.major
+            }}</el-descriptions-item>
+            <el-descriptions-item label="姓名">
+              {{ listData.realname }}
+            </el-descriptions-item>
+            <el-descriptions-item label="身份证">{{
+              listData.idCard
+            }}</el-descriptions-item>
+          </el-descriptions>
+        </div>
+
+        <div class="invoice-content__body">
+          <el-form-item label="学员类型:">
+            <el-radio
+              v-for="(item, index) in radiolist"
+              :key="index"
+              v-model="radio"
+              :label="item.name"
+              v-if="
+                listData.applyStatus &&
+                  listData.applyStatus.indexOf(item.name) !== -1
+              "
+              >{{ item.label }}</el-radio
+            >
+          </el-form-item>
+        </div>
+        <div class="invoice-content__footer">
+          <div class="btns">
+            <el-button
+              style="width:120px"
+              round
+              size="small"
+              @click="isShow = false"
+              >取消</el-button
+            >
+            <el-button
+              style="width:120px"
+              round
+              size="small"
+              @click="submit"
+              type="primary"
+              :loading="loading"
+              >确定预约</el-button
+            >
+          </div>
+        </div>
+      </el-form>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    dialogVisible: {
+      type: Boolean,
+      default: false
+    },
+    info: {
+      type: Object,
+      default: () => {
+        return {};
+      }
+    },
+    listData: {
+      type: Object,
+      default: () => {
+        return {};
+      }
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      radiolist: [
+        { name: "1", label: "非补考学员" },
+        { name: "2", label: "补考学员" }
+      ],
+      radio: ""
+    };
+  },
+
+  mounted() {},
+
+  methods: {
+    init() {
+      this.loading = false;
+      this.radio = "";
+    },
+    submit() {
+      if (!this.radio) {
+        this.$message({
+          type: "warning",
+          message: "请选择您的考试身份"
+        });
+        return;
+      }
+      let data = JSON.parse(JSON.stringify(this.info));
+      data.applyStatus = this.radio;
+      this.loading = true;
+      this.$request
+        .getApplysubscribeNext(data)
+        .then(res => {
+          if (res.data === 1 || res.data === 2) {
+            data.studentType = this.radio;
+            this.$request
+              .addApply(data)
+              .then(res => {
+                if (res.code == 200) {
+                  this.$bus.$emit("getNewGoodsList");
+                  this.$message.success("预约成功");
+                  this.isShow = false;
+                  this.notifyFunc();
+                  this.$parent.cancel();
+                  //预约成功
+                } else {
+                  this.$message.warning(res.msg || "预约失败,请重新预约");
+                }
+              })
+              .finally(() => {
+                this.loading = false;
+              });
+          }
+          if (res.data === 3) {
+            this.$request
+              .goodsList({
+                makeGoodsId: data.goodsId,
+                goodsType: 3,
+                orderGoodsId: data.orderGoodsId
+              })
+              .then(res => {
+                if (res.rows.length) {
+                  var goodsIdBK = res.rows[0].goodsId;
+                }
+                this.$confirm(
+                  "您所报考的" +
+                    (this.listData.major || "") +
+                    "专业,考试次数已经用完。需要预约考试的" +
+                    (this.radio == 1 ? "考试" : "补考") +
+                    "学员,请先购买" +
+                    (this.radio == 1 ? "考试" : "补考") +
+                    "机会。",
+                  "提示",
+                  {
+                    confirmButtonText: "缴费",
+                    cancelButtonText: "知道了"
+                  }
+                )
+                  .then(_ => {
+                    if (!goodsIdBK) {
+                      this.$message.warning("请联系管理员配置补考商品");
+                    } else {
+                      this.$request
+                        .commonGoodsDetail(goodsIdBK)
+                        .then(result => {
+                          let detail = result.data;
+                          detail.learnOrderGoodsId = data.orderGoodsId;
+                          detail.learnGradeId = data.gradeId;
+                          detail.learnGoodsId = data.goodsId;
+                          let selectGoodsList = JSON.parse(
+                            JSON.stringify([detail])
+                          );
+
+                          localStorage.setItem(
+                            "checkGoodsList",
+                            JSON.stringify(selectGoodsList)
+                          );
+                          this.$router.push({
+                            path: "/payment",
+                            query: {
+                              isBK: "1"
+                            }
+                          });
+                        });
+                    }
+                    // this.$router.push({
+                    //   path: "/payment-success",
+                    // });
+                  })
+                  .catch(_ => {});
+              })
+              .finally(() => {
+                this.loading = false;
+              });
+          }
+        })
+        .catch(err => {
+          this.loading = false;
+          this.$message({
+            type: "warning",
+            message: err.msg
+          });
+        });
+    },
+    notifyFunc() {
+      this.$notify({
+        customClass: "notifyStyle",
+        duration: 5000,
+        type: "success",
+        title: "预约成功",
+        dangerouslyUseHTMLString: true,
+        message: `<p>考试时间:${this.listData.applyName.slice(
+          0,
+          this.listData.applyName.length - 3
+        )}</p>
+        <p>考试地址: ${this.listData.applySite}</p>
+        <p>考试时长:2小时</p>
+        <p>考试形式:机考 </p>
+        <p>考试成绩:提交试卷后即刻显示成绩,60 分以上合格。</p>
+        <p>学校咨询电话:${this.$store.state.userInfo.eduPhone}</p>
+        <br />
+        <p>注意事项:考试当天请学员携带本人身份证提前 30 分钟到达考场,迟到将不得进入考场,并被认定为缺考处理。 `
+      });
+    }
+  },
+  computed: {
+    isShow: {
+      get() {
+        if (this.dialogVisible) {
+          this.init();
+        }
+        return this.dialogVisible;
+      },
+      set(val) {
+        this.$emit("update:dialogVisible", false);
+      }
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.invoice-content {
+  &__header {
+    margin-top: 20px;
+    padding: 10px 12px;
+    background: #fafbfc;
+    border: 1px solid #eeeeee;
+    box-shadow: 0px 0px 7px 1px rgba(0, 0, 0, 0.04);
+    border-radius: 8px;
+
+    .select {
+      width: 1000px;
+    }
+
+    .total {
+      margin-top: 10px;
+      margin-left: 80px;
+      font-size: 14px;
+
+      .note {
+        color: #ff3b30;
+      }
+    }
+  }
+
+  &__body {
+    margin-top: 20px;
+    background: #fafbfc;
+    border: 1px solid #eeeeee;
+    box-shadow: 0px 0px 7px 1px rgba(0, 0, 0, 0.04);
+    border-radius: 8px;
+
+    .el-form-item {
+      margin-bottom: 0;
+    }
+  }
+
+  &__footer {
+    margin-top: 20px;
+    padding-bottom: 40px;
+
+    .btns {
+      text-align: center;
+      margin-top: 20px;
+      .cancel {
+        display: inline-block;
+        margin: 0 10px;
+        cursor: pointer;
+        width: 122px;
+        height: 32px;
+        background: #ffffff;
+        border: 1px solid #3f8dfd;
+        border-radius: 16px;
+        text-align: center;
+        font-size: 16px;
+        line-height: 30px;
+        color: #3f8dfd;
+      }
+
+      .ok {
+        display: inline-block;
+        margin: 0 10px;
+        cursor: pointer;
+        width: 122px;
+        height: 32px;
+        background: #3f8dfd;
+        border-radius: 16px;
+        color: #fff;
+        text-align: center;
+        line-height: 32px;
+        font-size: 16px;
+      }
+    }
+  }
+}
+</style>
+<style lang="scss">
+.notifyStyle {
+  width: 620px;
+}
+</style>

+ 84 - 8
src/pages/person-center/my-course/index.vue

@@ -391,12 +391,7 @@
                     @click="goCourseDetail(item)"
                     >进入学习
                   </el-button>
-
-                  <el-button
-                    type="primary"
-                    class="btn"
-                    @click="appointment(item)"
-                    v-if="
+                  <!-- v-if="
                       item.applyStatus === 1 &&
                         !(
                           sysTime <= item.serviceStartTime ||
@@ -410,7 +405,15 @@
                             sysTime < item.learningTimeStart) ||
                           !item.examApplyGoodsList.length
                         )
+                    " -->
+                  <el-button
+                    v-if="
+                      item.examApplyGoodsList &&
+                        item.examApplyGoodsList.length > 0
                     "
+                    type="primary"
+                    class="btn"
+                    @click="appointment(item)"
                     >预约考试</el-button
                   >
 
@@ -552,6 +555,7 @@
     <appoint-test
       :appointModal.sync="appointModal"
       :appointItem="appointItem"
+      ref="appoint"
     ></appoint-test>
 
     <!-- 选班重学弹窗 -->
@@ -608,6 +612,23 @@
         >
       </span>
     </el-dialog>
+    <el-dialog
+      title="考前须知"
+      :visible.sync="applyBeforeKnow"
+      width="800px"
+      class="showconfirm"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      ><div
+        class="ql-editor"
+        style="white-space: pre-wrap"
+        v-html="applyBeforeKnowValue"
+      ></div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="applyBeforeKnow = false">取 消</el-button>
+        <el-button type="primary" @click="appointmentYes()">确 定</el-button>
+      </span></el-dialog
+    >
   </div>
 </template>
 
@@ -629,6 +650,8 @@ export default {
   },
   data() {
     return {
+      applyBeforeKnow: false,
+      applyBeforeKnowValue: "",
       studyStatusList: [
         {
           label: "全部",
@@ -720,6 +743,10 @@ export default {
     this.sysTime = this.$tools.timest();
     await this.orderUserEduList();
     this.courseGoodsList();
+    this.$bus.$on("getNewGoodsList", () => {
+      console.log(87632783);
+      this.courseGoodsList();
+    });
   },
   methods: {
     ...mapActions(["getUserInfo"]),
@@ -1214,22 +1241,71 @@ export default {
         .then(res => {
           this.courseList = res.rows;
           this.total = res.total;
+          //判断是否有商品可以预约考试
+          this.getGoodsApply(res.rows);
         })
         .finally(() => {
           this.loading = false;
         });
     },
+    getGoodsApply(array) {
+      const Goods = array.find(
+        i => i.subscribeSign == 1 || i.subscribeSign == 3
+      );
+      if (Goods) {
+        this.$confirm(
+          Goods.subscribeSign == 1
+            ? `您七大员新考【${Goods.goodsName}】课程已学完,可以预约考试了!`
+            : `您七大员新考【${Goods.goodsName}】课程考试未通过,请重新预约考试!`,
+          "提示",
+          {
+            confirmButtonText: "前往",
+            cancelButtonText: "关闭",
+            type: "warning"
+          }
+        )
+          .then(() => {
+            this.appointment(Goods);
+          })
+          .catch(() => {});
+      }
+    },
     progressText(item) {
       return (
         item.stuAllNum + item.recordNum + "/" + (item.secAllNum + item.examNum)
       );
     },
-
     appointment(item) {
-      this.applyId = "";
       this.appointItem = item;
+      this.$request.applybeforeknow().then(res => {
+        if (res.data.type == "Y") {
+          this.applyBeforeKnow = true;
+          if (res.data.value) {
+            res.data.value =
+              res.data.value &&
+              res.data.value.replace(
+                /<img/gi,
+                '<img style="max-width:100%;height:100%;display:block;margin:0px auto;"'
+              );
+          }
+          this.applyBeforeKnowValue = res.data.value;
+        } else {
+          this.appointmentYes();
+        }
+      });
+    },
+    appointmentYes() {
+      this.applyBeforeKnow = false;
+      this.applyId = "";
       this.appointModal = true;
+      this.$refs.appoint.openBoxs();
     }
+  },
+  /**
+   * 销毁公交
+   */
+  beforeDestroy() {
+    this.$bus.$off("getNewGoodsList");
   }
 };
 </script>

+ 96 - 57
src/pages/person-center/my-examination/index/index.vue

@@ -44,7 +44,11 @@
                 </div>
                 <!--  -->
                 <el-button
-                  v-if="item.applyReportStatus == 1 && item.reportStatus == 0 && false"
+                  v-if="
+                    item.applyReportStatus == 1 &&
+                      item.reportStatus == 0 &&
+                      false
+                  "
                   type="primary"
                   plain
                   round
@@ -53,7 +57,11 @@
                   >签署疫情承诺书</el-button
                 >
                 <el-button
-                  v-if="isShowFun(item) && item.subscribeStatus == 1"
+                  v-if="
+                    isShowFun(item) &&
+                      item.subscribeStatus == 1 &&
+                      timeDisAbout(item)
+                  "
                   type="primary"
                   plain
                   round
@@ -100,7 +108,7 @@
                     <!-- seatNumber 有座位号就显示roomAddress,否则显示applySiteAddress -->
                     <div class="desc-list__item">
                       考试地点:<span class="note">{{
-                        item.seatNumber ? (item.roomAddress || '') : (item.applySiteAddress || '')
+                        item.applySiteAddress
                       }}</span>
                     </div>
                     <div class="desc-list__item">
@@ -111,9 +119,11 @@
                       >
                     </div>
                     <div class="desc-list__item">
-                      座位号:<span class="note">{{ item.seatNumber || '' }}</span>
+                      座位号:<span class="note">{{
+                        item.seatNumber || ""
+                      }}</span>
                     </div>
-                    <div class="desc-list__item">
+                    <div class="desc-list__item" v-if="false">
                       考前培训地点:<span class="note">{{
                         item.applySiteAddressTrain
                       }}</span>
@@ -122,8 +132,8 @@
                       class="desc-list__item"
                       v-if="
                         item.applySiteExamTrainTime &&
-                        item.applySiteStartTrainTime &&
-                        item.applySiteEndTrainTime
+                          item.applySiteStartTrainTime &&
+                          item.applySiteEndTrainTime && false
                       "
                     >
                       考前培训时间:<span class="note"
@@ -135,11 +145,26 @@
                       >
                     </div>
                     <div class="desc-list__item">
-                      准考证号:<span class="note">{{ item.examineeCode || ''}}</span>
+                      准考证号:<span class="note">{{
+                        item.examineeCode || ""
+                      }}</span>
                     </div>
                     <!-- applyReportStatus是否显示签署承诺书 1是,0否 -->
-                    <div v-if="item.applyReportStatus == 1 && false" class="desc-list__item">
-                      疫情防控承诺书:<span class="note unSign" @click="toSignUp(item)">{{ item.reportStatus == 1 ? '已签署' : item.reportStatus == 0 ? '未签署' : '' }}</span>
+                    <div
+                      v-if="item.applyReportStatus == 1 && false"
+                      class="desc-list__item"
+                    >
+                      疫情防控承诺书:<span
+                        class="note unSign"
+                        @click="toSignUp(item)"
+                        >{{
+                          item.reportStatus == 1
+                            ? "已签署"
+                            : item.reportStatus == 0
+                            ? "未签署"
+                            : ""
+                        }}</span
+                      >
                     </div>
                   </div>
                 </div>
@@ -242,7 +267,9 @@
                       >
                     </div>
                     <div class="desc-list__item">
-                      座位号:<span class="note">{{ item.seatNumber || '' }}</span>
+                      座位号:<span class="note">{{
+                        item.seatNumber || ""
+                      }}</span>
                     </div>
                     <div
                       class="desc-list__item"
@@ -256,16 +283,16 @@
                       class="desc-list__item"
                       v-if="
                         item.applySiteExamTrainTime &&
-                        item.applySiteStartTrainTime &&
-                        item.applySiteEndTrainTime
+                          item.applySiteStartTrainTime &&
+                          item.applySiteEndTrainTime
                       "
                     >
                       考前培训时间:<span class="note">{{
                         $tools.timestampToTime(item.applySiteExamTrainTime) +
-                        " " +
-                        item.applySiteStartTrainTime +
-                        "~" +
-                        item.applySiteEndTrainTime
+                          " " +
+                          item.applySiteStartTrainTime +
+                          "~" +
+                          item.applySiteEndTrainTime
                       }}</span>
                     </div>
                   </div>
@@ -314,18 +341,22 @@
     </div>
 
     <!-- 疫情承诺书 -->
-    <sign-commit :appointModal.sync="appointModal" :commitItem="commitItem" @successSign="successSign"></sign-commit>
+    <sign-commit
+      :appointModal.sync="appointModal"
+      :commitItem="commitItem"
+      @successSign="successSign"
+    ></sign-commit>
   </div>
 </template>
 
 <script>
 import { mapGetters, mapActions } from "vuex";
-import SignCommit from '../components/SignCommit.vue'
+import SignCommit from "../components/SignCommit.vue";
 export default {
   name: "MyExamination",
   components: { SignCommit },
   computed: {
-    ...mapGetters(["sysTime"]),
+    ...mapGetters(["sysTime"])
   },
   data() {
     return {
@@ -339,42 +370,42 @@ export default {
         {
           label: "通过",
           count: 0,
-          result: 1,
+          result: 1
         },
         {
           label: "未通过",
           count: 0,
-          result: 0,
-        },
+          result: 0
+        }
       ],
       examList: [
         {
           label: "已预约",
           count: 0,
           subscribeStatus: 1,
-          exceedExamExpend: 2,
+          exceedExamExpend: 2
         },
         {
           label: "已取消",
           count: 0,
           subscribeStatus: 2,
-          exceedExamExpend: "",
+          exceedExamExpend: ""
         },
         {
           label: "已过期",
           count: 0,
           subscribeStatus: 1,
-          exceedExamExpend: 1,
-        },
+          exceedExamExpend: 1
+        }
       ],
       total: 0,
       param: {
         pageNum: 1,
-        pageSize: 10,
+        pageSize: 10
       },
       listData: [],
       appointModal: false, // 疫情承诺书弹窗
-      commitItem: {},
+      commitItem: {}
     };
   },
   mounted() {
@@ -385,9 +416,9 @@ export default {
     ...mapActions(["setSystemTime"]),
     // 签署成功刷新列表
     successSign() {
-      console.log('成功--')
-      this.getApplylist()
-      this.getCount()
+      console.log("成功--");
+      this.getApplylist();
+      this.getCount();
     },
     getCount() {
       this.$request
@@ -395,9 +426,9 @@ export default {
           pageNum: 1,
           pageSize: 1,
           subscribeStatus: 1,
-          exceedExamExpend: 2,
+          exceedExamExpend: 2
         })
-        .then((res) => {
+        .then(res => {
           this.examList[0].count = res.total;
         });
 
@@ -406,9 +437,9 @@ export default {
           pageNum: 1,
           pageSize: 1,
           subscribeStatus: 2,
-          exceedExamExpend: "",
+          exceedExamExpend: ""
         })
-        .then((res) => {
+        .then(res => {
           this.examList[1].count = res.total;
         });
 
@@ -417,9 +448,9 @@ export default {
           pageNum: 1,
           pageSize: 1,
           subscribeStatus: 1,
-          exceedExamExpend: 1,
+          exceedExamExpend: 1
         })
-        .then((res) => {
+        .then(res => {
           this.examList[2].count = res.total;
         });
 
@@ -427,9 +458,9 @@ export default {
         .getApplylist({
           pageNum: 1,
           pageSize: 1,
-          result: 1,
+          result: 1
         })
-        .then((res) => {
+        .then(res => {
           this.resultList[0].count = res.total;
         });
 
@@ -437,9 +468,9 @@ export default {
         .getApplylist({
           pageNum: 1,
           pageSize: 1,
-          result: 0,
+          result: 0
         })
-        .then((res) => {
+        .then(res => {
           this.resultList[1].count = res.total;
         });
     },
@@ -489,14 +520,22 @@ export default {
           pageSize: this.param.pageSize,
           subscribeStatus: this.subscribeStatus,
           exceedExamExpend: this.exceedExamExpend,
-          result: this.result,
+          result: this.result
         })
-        .then((res) => {
+        .then(res => {
           this.listData = res.rows;
           this.total = res.total;
           this.setSystemTime();
         });
     },
+    timeDisAbout(item) {
+      var timestamp = parseInt(new Date().getTime() / 1000);
+      if (timestamp > item.applyEndTime) {
+        return false;
+      } else {
+        return true;
+      }
+    },
     isShowFun(item) {
       // var timestamp = parseInt(new Date().getTime() / 1000);
       var newDataAge = parseInt(
@@ -547,7 +586,7 @@ export default {
         "每次考试均有名额限制,",
         "取消预约后,您可能无法再次预约本次考试。",
         "请慎重考虑。",
-        "您确定要取消本次考试预约吗?",
+        "您确定要取消本次考试预约吗?"
       ];
       const newDatas = [];
       const h = this.$createElement;
@@ -560,34 +599,34 @@ export default {
         closeOnClickModal: false,
         closeOnPressEscape: false,
         distinguishCancelAndClose: false,
-        showClose: false,
+        showClose: false
       })
-        .then((_) => {
+        .then(_ => {
           var bols = this.isShowFun(item);
           console.log(bols);
           if (!bols) {
             this.$message({
               type: "warning",
-              message: "当前已无法取消预约",
+              message: "当前已无法取消预约"
             });
             return;
           }
           this.$request
             .editApply({
               subscribeId: item.subscribeId,
-              subscribeStatus: 2,
+              subscribeStatus: 2
             })
-            .then((res) => {
+            .then(res => {
               this.$request
                 .getApplylist({ subscribeStatus: 1, exceedExamExpend: 2 })
-                .then((res) => {
+                .then(res => {
                   this.listData = res.rows;
                   this.getApplylist();
                   this.getCount();
                 });
             });
         })
-        .catch((_) => {
+        .catch(_ => {
           console.log(_);
         });
     },
@@ -597,11 +636,11 @@ export default {
       this.getApplylist();
     },
     toSignUp(item) {
-      console.log('item', item)
-      this.commitItem = item
-      this.appointModal = true
-    },
-  },
+      console.log("item", item);
+      this.commitItem = item;
+      this.appointModal = true;
+    }
+  }
 };
 </script>
 

+ 363 - 0
src/pages/person-center/my-handout/index.vue

@@ -0,0 +1,363 @@
+<template>
+  <div id="courseData">
+    <div class="my-course">
+      <div style="padding-top: 14px;">
+        <strong style="font-size: 18px;">我的讲义资料</strong>
+        <el-divider></el-divider>
+      </div>
+
+      <div class="my-course__body">
+        <el-main class="list" v-loading="loading">
+          <el-empty
+            description="请前往购买商品"
+            v-if="courseList.length === 0"
+          ></el-empty>
+          <div
+            class="course-item"
+            v-for="(item, index) in courseList"
+            :key="index"
+          >
+            <div class="course-item__header"></div>
+            <div class="course-item__body clearfix">
+              <div class="img">
+                <img :src="$tools.splitImgHost(item.coverUrl, true)" alt="" />
+              </div>
+              <div class="text">
+                <div class="title" style="margin-bottom:14px;">
+                  {{ item.goodsName }}
+                </div>
+                <div class="progress" style="margin-bottom:14px;">
+                  <span v-if="item.validityStartTime && item.validityEndTime">
+                    商品有效期:<span
+                      :style="
+                        sysTime <= item.validityStartTime ||
+                        sysTime >= item.validityEndTime
+                          ? 'text-decoration:line-through'
+                          : null
+                      "
+                    >
+                      {{
+                        $tools.timestampToTime(item.validityStartTime, false)
+                      }}
+                      至
+                      {{ $tools.timestampToTime(item.validityEndTime, false) }}
+                    </span>
+                  </span>
+                </div>
+              </div>
+              <div class="btns-wrap">
+                <div class="btns">
+                  <el-button
+                    class="btn btn--normal"
+                    :disabled="
+                      item.validityStartTime > sysTime ||
+                        item.validityEndTime < sysTime
+                    "
+                    type="primary"
+                    @click="goCourseDetail(item)"
+                    >进入学习
+                  </el-button>
+                </div>
+              </div>
+            </div>
+            <div
+              class="course-item__footer"
+              style="color: red;"
+              v-if="item.validityEndTime && item.validityEndTime < sysTime"
+            >
+              温馨提示:商品有效期已截至,如有疑问请联系:{{
+                $store.state.userInfo.eduPhone
+              }}
+            </div>
+          </div>
+        </el-main>
+        <div class="pagination" v-if="total > 0">
+          <el-pagination
+            @current-change="currentChange"
+            background
+            layout="prev, pager, next"
+            :total="total"
+            :pager-count="5"
+            :current-page.sync="param.pageNum"
+            :page-size="param.pageSize"
+          >
+          </el-pagination>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      loading: false,
+      total: 0,
+      courseList: [],
+      param: {
+        pageNum: 1,
+        pageSize: 5
+      },
+      sysTime: null
+    };
+  },
+  mounted() {
+    this.sysTime = this.$tools.timest();
+    this.courseGoodsList();
+  },
+  methods: {
+    currentChange(e) {
+      this.param.pageNum = e;
+      document.body.scrollTop = 0;
+      document.documentElement.scrollTop = 0;
+      this.courseGoodsList();
+    },
+    goCourseDetail(item) {
+      this.$router.push({
+        path: `/my-handout-detail/${item.goodsId}`,
+        query: {
+          orderGoodsId: item.orderGoodsId
+        }
+      });
+    },
+    courseGoodsList() {
+      this.loading = true;
+      this.$request
+        .courseGoodsHandoutsList(this.param)
+        .then(res => {
+          this.courseList = res.rows;
+          this.total = res.total;
+        })
+        .finally(() => {
+          this.loading = false;
+        });
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.my-course {
+  &__body {
+    .list {
+      padding: 0;
+      overflow: unset;
+      .course-item {
+        margin-top: 24px;
+        background: #fafbfc;
+        border-radius: 8px;
+        overflow: hidden;
+        padding: 30px;
+        border: 1px solid transparent;
+        transition: all 0.2s;
+        &:hover {
+          border: 1px solid #409eff;
+          // box-shadow: 0px 1px 6px 1px rgba(0,0,0,.3);
+        }
+        &__body {
+          display: flex;
+          .img {
+            float: left;
+            width: 250px;
+            height: 140px;
+
+            img {
+              width: 100%;
+              height: 100%;
+            }
+          }
+
+          .text {
+            flex: 1;
+            float: left;
+            margin-left: 12px;
+            .title {
+              margin-bottom: 4px;
+              font-size: 16px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #333333;
+              .note {
+                display: inline-block;
+                vertical-align: middle;
+                border: 1px solid #333333;
+                border-radius: 4px;
+                font-size: 12px;
+                font-family: Microsoft YaHei;
+                font-weight: 400;
+                color: #333333;
+                padding: 2px 5px;
+                margin-left: 12px;
+              }
+            }
+
+            .state {
+              margin-bottom: 4px;
+              font-size: 14px;
+              font-family: Microsoft YaHei;
+              font-weight: 400;
+              color: #666666;
+
+              .red {
+                color: #ff3b30;
+              }
+
+              .note {
+                vertical-align: middle;
+                display: inline-block;
+                padding: 0px 10px;
+                background: #ffeceb;
+                border: 1px solid #eb5757;
+                border-radius: 12px;
+                font-size: 14px;
+                font-family: Microsoft YaHei;
+                font-weight: 400;
+                color: #eb5757;
+                text-align: center;
+                margin-right: 10px;
+                &--blue {
+                  border-color: #498afe;
+                  color: #498afe;
+                  background: #ecf5ff;
+                }
+                &--yellow {
+                  border-color: #f67205;
+                  color: #f67205;
+                  background: #fff8e8;
+                }
+
+                &--green {
+                  border-color: #56dc68;
+                  color: #56dc68;
+                  background: #e6feea;
+                }
+              }
+            }
+
+            .time {
+              font-size: 14px;
+              font-family: Microsoft YaHei;
+              font-weight: 400;
+              color: #666666;
+
+              &--red {
+                color: #ff3b30;
+              }
+            }
+            .progress {
+              margin-bottom: 4px;
+              font-size: 14px;
+              font-family: Microsoft YaHei;
+              font-weight: 400;
+              color: #666;
+
+              &-line {
+                width: 220px;
+                display: inline-block;
+              }
+
+              /deep/ .el-progress-bar {
+                padding-right: 70px;
+                margin-right: -70px;
+              }
+              /deep/ .el-progress-bar__outer {
+                height: 12px !important;
+              }
+              /deep/ .el-progress__text {
+                font-size: 14px !important;
+              }
+            }
+          }
+
+          .btns-wrap {
+            align-self: center;
+            display: table;
+            float: right;
+            height: 90px;
+            width: 130px;
+
+            .btns {
+              display: table-cell;
+              vertical-align: middle;
+              text-align: center;
+              .el-button {
+                margin-bottom: 20px !important;
+              }
+              .btn {
+                cursor: pointer;
+                margin: 2px 0;
+                width: 122px;
+                height: 32px;
+                padding: 0;
+                border-radius: 16px;
+                display: inline-block;
+                text-align: center;
+                line-height: 32px;
+                color: #fff;
+
+                &--normal {
+                  &.disabled {
+                    // background: rgb(101, 164, 253);
+                    // border-color: rgb(101, 164, 253);
+                  }
+                }
+
+                &--warm {
+                  background: #ff3b30;
+
+                  &:hover {
+                    background: #f56c6c;
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        &__footer {
+          padding: 20px 18px;
+          font-size: 14px;
+          color: #333;
+
+          .text {
+            margin-right: 20px;
+
+            &--red {
+              color: #ff3b30;
+            }
+          }
+        }
+      }
+    }
+
+    .pagination {
+      padding: 30px 0;
+      text-align: center;
+    }
+  }
+
+  .exercises-modal {
+    &__content {
+      > div {
+        font-size: 16px;
+        line-height: 30px;
+        text-align: center;
+
+        img {
+          display: inline;
+        }
+      }
+    }
+  }
+
+  .appoint-modal {
+    &__content {
+      .el-radio {
+        display: block;
+        margin: 10px 30px 10px 0;
+      }
+    }
+  }
+}
+</style>

+ 55 - 8
src/router/index.js

@@ -10,7 +10,7 @@ let bankAdmin = ['/person-center/bank-record', '/person-center/my-bank/index', '
 let canToBank = null;
 let courseAdmin = ['/my-course-detail/', '/course-exam/']
 let canToCourse = null;
-const signLoginPage = ['/my-course-detail', '/my-bank', '/my-live']
+const signLoginPage = ['/my-course-detail', '/my-bank', '/my-live', '/living-room']
 const router = new Router({
   mode: 'history',
   scrollBehavior: () => ({ y: 0 }),
@@ -102,6 +102,18 @@ const router = new Router({
         }
       }
     },
+    {
+      path: '/handout-list',
+      name: '讲义资料',
+      component: resolve => require(['@/pages/handout-list/index'], resolve),
+      meta: {
+        title: + '-一二级建造师、工程师、建筑师视频课程、免费直播课',
+        content: {
+          keywords: + '-一级建造师视频课件,二级建造师视频课件,建筑师工程师学习视频课程',
+          description: + '-提供一二级建造师视频学习、免费直播公开课  ,免费试听,建造师内部习题资料、工程师教学辅导视频、建筑考试课件视频等资料。'
+        }
+      }
+    },
     {
       path: '/points-list',
       name: '积分商城列表',
@@ -175,6 +187,18 @@ const router = new Router({
         }
       }
     },
+    {
+      path: '/handout-detail/:goodsId',
+      name: '讲义资料详情',
+      component: resolve => require(['@/pages/goods-detail/handout-detail'], resolve),
+      meta: {
+        title: + '-题库-一建二建试题下载_考试科目题库_考题答案_历年试题_在线真题_水平测试_历年真题_在线题库',
+        content: {
+          keywords: + '-模拟试题练习,试题答案,一级建造师试题查找,二级建造师试题练习,题目类型,考试书籍,考试图书,考试教材',
+          description: + '-提供一二级建造师学习资料、教材教辅,一二级建造师考试专业培训辅导课程,免费试听,建造师内部习题资料、工程师教学辅导视频、建筑考试课件视频等资料'
+        }
+      }
+    },
     {
       path: '/my-course-detail/:goodsId',
       name: '课程详情',
@@ -187,6 +211,18 @@ const router = new Router({
         }
       }
     },
+    {
+      path: '/my-handout-detail/:goodsId',
+      name: '课程详情',
+      component: resolve => require(['@/pages/handout-detail/index'], resolve),
+      meta: {
+        title: + '-一二级建造师、工程师、建筑师视频课程、免费直播课',
+        content: {
+          keywords: + '-一级建造师视频课件,二级建造师视频课件,建筑师工程师学习视频课程',
+          description: + '-提供一二级建造师视频学习、免费直播公开课  ,免费试听,建造师内部习题资料、工程师教学辅导视频、建筑考试课件视频等资料。'
+        }
+      }
+    },
 
     {
       path: '/my-live-detail/:goodsId',
@@ -554,7 +590,6 @@ const router = new Router({
           component: resolve => require(['@/pages/person-center/my-wrong/index'], resolve),
           name: '错题集'
         },
-
         {
           path: 'record-list/:goodsId',
           component: resolve => require(['@/pages/person-center/bank-record/record-list/index'], resolve),
@@ -565,6 +600,11 @@ const router = new Router({
           component: resolve => require(['@/pages/person-center/mock-record/record-list/index'], resolve),
           name: '更多模考记录'
         },
+        {
+          path: 'my-handout',
+          component: resolve => require(['@/pages/person-center/my-handout/index'], resolve),
+          name: '我的讲义资料'
+        },
         {
           path: 'my-order',
           component: resolve => require(['@/pages/person-center/my-order/index'], resolve),
@@ -575,7 +615,7 @@ const router = new Router({
           component: resolve => require(['@/pages/person-center/my-mock/index'], resolve),
           name: '我的模考'
         },
-        {
+        { 
           path: 'my-message',
           component: resolve => require(['@/pages/person-center/my-message/index'], resolve),
           name: '我的消息'
@@ -708,12 +748,19 @@ router.beforeEach(async (to, from, next) => {
 
   } else {
     // 处理携带skipPort隐式登录
-    let { skipPort } = to.query
-    if (skipPort && signLoginPage.some(path => to.path.includes(path))) {
+    let { skipPort, user_account } = to.query
+    if ((skipPort || user_account) && signLoginPage.some(path => to.path.includes(path))) {
       try {
-        let { data } = await request.skipLogin({ sign: skipPort })
-        localStorage.setItem("user_account", data.user_account);
-        localStorage.setItem("token", data.token);
+        if (skipPort) {
+          let { data } = await request.skipLogin({ sign: skipPort })
+          localStorage.setItem("user_account", data.user_account);
+          localStorage.setItem("token", data.token);
+        }
+        if (user_account) {
+          let { data } = await request.account_login({ userAccount: user_account })
+          localStorage.setItem("user_account", user_account);
+          localStorage.setItem("token", data.token);
+        }
       } catch (error) {
         next('/login')
       }