瀏覽代碼

初始化项目

赵启卫 2 年之前
父節點
當前提交
5dad7ec4bc
共有 100 個文件被更改,包括 11237 次插入0 次删除
  1. 67 0
      public/pc/api/activity.js
  2. 46 0
      public/pc/api/article.js
  3. 205 0
      public/pc/api/auth.js
  4. 71 0
      public/pc/api/home.js
  5. 94 0
      public/pc/api/live.js
  6. 70 0
      public/pc/api/login.js
  7. 71 0
      public/pc/api/material.js
  8. 139 0
      public/pc/api/merchant.js
  9. 52 0
      public/pc/api/my.js
  10. 42 0
      public/pc/api/public.js
  11. 251 0
      public/pc/api/special.js
  12. 223 0
      public/pc/api/topic.js
  13. 64 0
      public/pc/components/account-change/index.css
  14. 26 0
      public/pc/components/account-change/index.html
  15. 127 0
      public/pc/components/account-change/index.js
  16. 34 0
      public/pc/components/base-agree/index.css
  17. 7 0
      public/pc/components/base-agree/index.html
  18. 25 0
      public/pc/components/base-agree/index.js
  19. 200 0
      public/pc/components/base-footer/index.css
  20. 49 0
      public/pc/components/base-footer/index.html
  21. 41 0
      public/pc/components/base-footer/index.js
  22. 二進制
      public/pc/components/base-header/images/1.png
  23. 二進制
      public/pc/components/base-header/images/2.png
  24. 二進制
      public/pc/components/base-header/images/3.png
  25. 424 0
      public/pc/components/base-header/index.css
  26. 91 0
      public/pc/components/base-header/index.html
  27. 204 0
      public/pc/components/base-header/index.js
  28. 41 0
      public/pc/components/base-lecturer/index.css
  29. 10 0
      public/pc/components/base-lecturer/index.html
  30. 11 0
      public/pc/components/base-lecturer/index.js
  31. 322 0
      public/pc/components/base-login/index.css
  32. 61 0
      public/pc/components/base-login/index.html
  33. 252 0
      public/pc/components/base-login/index.js
  34. 30 0
      public/pc/components/base_agree/index.css
  35. 7 0
      public/pc/components/base_agree/index.html
  36. 20 0
      public/pc/components/base_agree/index.js
  37. 200 0
      public/pc/components/base_footer/index.css
  38. 49 0
      public/pc/components/base_footer/index.html
  39. 42 0
      public/pc/components/base_footer/index.js
  40. 402 0
      public/pc/components/base_header/index.css
  41. 75 0
      public/pc/components/base_header/index.html
  42. 154 0
      public/pc/components/base_header/index.js
  43. 322 0
      public/pc/components/base_login/index.css
  44. 61 0
      public/pc/components/base_login/index.html
  45. 248 0
      public/pc/components/base_login/index.js
  46. 172 0
      public/pc/components/home/recommend0/index.css
  47. 31 0
      public/pc/components/home/recommend0/index.html
  48. 16 0
      public/pc/components/home/recommend0/index.js
  49. 161 0
      public/pc/components/home/recommend1/index.css
  50. 36 0
      public/pc/components/home/recommend1/index.html
  51. 20 0
      public/pc/components/home/recommend1/index.js
  52. 172 0
      public/pc/components/home/recommend2/index.css
  53. 25 0
      public/pc/components/home/recommend2/index.html
  54. 20 0
      public/pc/components/home/recommend2/index.js
  55. 121 0
      public/pc/components/home/recommend3/index.css
  56. 19 0
      public/pc/components/home/recommend3/index.html
  57. 20 0
      public/pc/components/home/recommend3/index.js
  58. 0 0
      public/pc/components/home/recommend4/index.css
  59. 32 0
      public/pc/components/home/recommend4/index.html
  60. 28 0
      public/pc/components/home/recommend4/index.js
  61. 70 0
      public/pc/components/home/recommend5/index.html
  62. 59 0
      public/pc/components/home/recommend5/index.js
  63. 115 0
      public/pc/components/home/recommend7/index.css
  64. 17 0
      public/pc/components/home/recommend7/index.html
  65. 17 0
      public/pc/components/home/recommend7/index.js
  66. 127 0
      public/pc/components/home/recommend8/index.css
  67. 20 0
      public/pc/components/home/recommend8/index.html
  68. 16 0
      public/pc/components/home/recommend8/index.js
  69. 131 0
      public/pc/components/my/account/index.css
  70. 46 0
      public/pc/components/my/account/index.html
  71. 103 0
      public/pc/components/my/account/index.js
  72. 160 0
      public/pc/components/my/activity/index.css
  73. 79 0
      public/pc/components/my/activity/index.html
  74. 91 0
      public/pc/components/my/activity/index.js
  75. 119 0
      public/pc/components/my/balance/index.css
  76. 60 0
      public/pc/components/my/balance/index.html
  77. 101 0
      public/pc/components/my/balance/index.js
  78. 559 0
      public/pc/components/my/coin/index.css
  79. 126 0
      public/pc/components/my/coin/index.html
  80. 258 0
      public/pc/components/my/coin/index.js
  81. 141 0
      public/pc/components/my/course/index.css
  82. 29 0
      public/pc/components/my/course/index.html
  83. 48 0
      public/pc/components/my/course/index.js
  84. 559 0
      public/pc/components/my/currency/index.css
  85. 126 0
      public/pc/components/my/currency/index.html
  86. 258 0
      public/pc/components/my/currency/index.js
  87. 333 0
      public/pc/components/my/favor/index.css
  88. 63 0
      public/pc/components/my/favor/index.html
  89. 119 0
      public/pc/components/my/favor/index.js
  90. 333 0
      public/pc/components/my/favorite/index.css
  91. 63 0
      public/pc/components/my/favorite/index.html
  92. 113 0
      public/pc/components/my/favorite/index.js
  93. 126 0
      public/pc/components/my/lecturer/index.css
  94. 19 0
      public/pc/components/my/lecturer/index.html
  95. 71 0
      public/pc/components/my/lecturer/index.js
  96. 95 0
      public/pc/components/my/material/index.css
  97. 24 0
      public/pc/components/my/material/index.html
  98. 46 0
      public/pc/components/my/material/index.js
  99. 500 0
      public/pc/components/my/member/index.css
  100. 94 0
      public/pc/components/my/member/index.html

+ 67 - 0
public/pc/api/activity.js

xqd
@@ -0,0 +1,67 @@
+define([
+    'scripts/request'
+], function(request) {
+    return {
+        /**
+         * 获取活动列表
+         * @param {*} params 
+         * @returns 
+         */
+        activityList: function (params) {
+            return request({
+                url: '/activity/activityList',
+                params: params
+            });
+        },
+        /**
+         * 活动报名
+         * @param {*} params 
+         * @returns 
+         */
+        activity_details: function (params) {
+            return request({
+                url: '/activity/activity_details',
+                params: params
+            });
+        },
+        getActivityEventData: function (params) {
+            return request({
+                url: '/activity/getActivityEventData',
+                params: params
+            });
+        },
+        /**
+         * 获取活动人数
+         * @param {*} params 
+         * @returns 
+         */
+        getActivityEventPrice: function (params) {
+            return request({
+                url: '/activity/getActivityEventPrice',
+                params: params
+            });
+        },
+        /**
+         * 用户报名活动列表
+         * @param {*} params 
+         * @returns 
+         */
+        activitySignInList: function (params) {
+            return request({
+                url: '/activity/activitySignInList',
+                params: params
+            });
+        },
+        /**
+         * 相关活动
+         * @param {*} params 
+         * @returns 
+         */
+        relatedActivities: function (params) {
+            return request({
+                url: '/activity/relatedActivities',
+                params: params
+            });
+        }
+    };
+});

+ 46 - 0
public/pc/api/article.js

xqd
@@ -0,0 +1,46 @@
+define([
+    'scripts/request'
+], function(request) {
+    return {
+        /**
+         * 新闻分类
+         * @returns 
+         */
+        get_article_cate: function () {
+            return request({
+                url: '/article/get_article_cate'
+            });
+        },
+        /**
+         * 新闻列表
+         * @param {*} params 
+         * @returns 
+         */
+        get_article_list: function (params) {
+            return request({
+                url: '/article/get_article_list',
+                params: params
+            });
+        },
+        /**
+         * 新闻广告
+         * @returns 
+         */
+        news_data: function () {
+            return request({
+                url: '/article/news_data'
+            });
+        },
+        /**
+         * 资讯详情
+         * @param {*} params 
+         * @returns 
+         */
+        article_details: function (params) {
+            return request({
+                url: '/article/article_details',
+                params: params
+            });
+        }
+    };
+});

+ 205 - 0
public/pc/api/auth.js

xqd
@@ -0,0 +1,205 @@
+define([
+    'scripts/request'
+], function (request) {
+    return {
+        /**
+         * 用户信息
+         * @returns 
+         */
+        user_info: function () {
+            return request({
+                url: '/auth_api/user_info'
+            });
+        },
+        /**
+         * 上传图片到阿里云
+         * @param {*} data 
+         * @returns 
+         */
+        upload: function (data) {
+            return request({
+                url: '/auth_api/upload',
+                method: 'post',
+                data: data
+            });
+        },
+        // 验证码
+        code: function (params) {
+            return request({
+                url: '/auth_api/code',
+                params: params
+            });
+        },
+        /**
+         * 新闻
+         * @returns 
+         */
+        get_article_unifiend_list: function (params) {
+            return request({
+                url: '/auth_api/get_article_unifiend_list',
+                params: params
+            });
+        },
+        /**
+         * 会员中心权益、说明
+         * @param {*} data 
+         * @returns 
+         */
+        merber_data: function () {
+            return request({
+                url: '/auth_api/merber_data'
+            });
+        },
+        /**
+         * 会员套餐
+         * @returns 
+         */
+        member_ship_lists: function () {
+            return request({
+                url: '/auth_api/member_ship_lists'
+            });
+        },
+        /**
+         * 支付
+         * @param {*} data 
+         * @returns 
+         */
+        create_order: function (data) {
+            return request({
+                url: '/auth_api/create_order',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 会员卡激活
+         * @param {*} data 
+         * @returns 
+         */
+        confirm_activation: function (data) {
+            return request({
+                url: '/auth_api/confirm_activation',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 我的金币信息
+         * @returns 
+         */
+        get_gold_coins: function () {
+            return request({
+                url: '/auth_api/get_gold_coins'
+            });
+        },
+        /**
+         * 金币明细
+         * @param {*} params 
+         * @returns 
+         */
+        user_gold_num_list: function (params) {
+            return request({
+                url: '/auth_api/user_gold_num_list',
+                params: params
+            });
+        },
+        /**
+         * 余额信息
+         * @returns 
+         */
+        get_user_balance: function () {
+            return request({
+                url: '/auth_api/get_user_balance'
+            });
+        },
+        /**
+         * 余额明细
+         * @param {*} params 
+         * @returns 
+         */
+        get_user_balance_list: function (params) {
+            return request({
+                url: '/auth_api/get_user_balance_list',
+                params: params
+            });
+        },
+        /**
+         * 我购买的课程
+         * @param {*} params 
+         * @returns 
+         */
+        my_special_list: function (params) {
+            return request({
+                url: '/auth_api/my_special_list',
+                params: params
+            });
+        },
+        /**
+         * 我的资料
+         * @param {*} params 
+         * @returns 
+         */
+        my_material_list: function (params) {
+            return request({
+                url: '/auth_api/my_material_list',
+                params: params
+            });
+        },
+        /**
+         * 我收藏的课程、资料
+         * @param {*} params 
+         * @returns 
+         */
+        get_grade_list: function (params) {
+            return request({
+                url: '/auth_api/get_grade_list',
+                params: params
+            });
+        },
+        /**
+         * 讲师详情
+         * @param {*} params 
+         * @returns 
+         */
+        lecturer_details: function (params) {
+            return request({
+                url: '/auth_api/lecturer_details',
+                params: params
+            });
+        },
+        /**
+         * 讲师的专题
+         * @param {object} data 
+         * @returns 
+         */
+        lecturer_special_list: function (data) {
+            return request({
+                url: '/auth_api/lecturer_special_list',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 扫码支付回调
+         * @param {*} params 
+         * @returns 
+         */
+        testing_order_state: function (params) {
+            return request({
+                url: '/auth_api/testing_order_state',
+                params: params
+            });
+        },
+        /**
+         * 详情页讲师信息
+         * @param {*} params 
+         * @returns 
+         */
+        getLecturer: function (params) {
+            return request({
+                url: '/auth_api/getLecturer',
+                params: params
+            });
+        }
+    };
+});

+ 71 - 0
public/pc/api/home.js

xqd
@@ -0,0 +1,71 @@
+define([
+    'scripts/request'
+], function (request) {
+    return {
+        /**
+         * 是否登录
+         * @returns 
+         */
+        user_login: function () {
+            return request({
+                url: '/index/login_user'
+            });
+        },
+        /**
+         * 首页固定数据
+         * @returns
+         */
+        index_data: function () {
+            return request({
+                url: '/index/index_data'
+            });
+        },
+        /**
+         * 首页推荐数据
+         * @returns
+         */
+        get_content_recommend: function () {
+            return request({
+                url: '/index/get_content_recommend'
+            });
+        },
+        courseRanking: function () {
+            return request({
+                url: '/auth_api/get_course_ranking'
+            });
+        },
+        newCourseFirst: function () {
+            return request({
+                url: '/auth_api/get_new_course_first'
+            });
+        },
+        articleList: function (params) {
+            return request({
+                url: '/auth_api/get_article_unifiend_list',
+                params: params
+            });
+        },
+        get_good_class_recommend: function () {
+            return request({
+                url: '/auth_api/get_good_class_recommend'
+            });
+        },
+        /**
+         * 付款页数据
+         * @param {*} params
+         * @returns
+         */
+        pay_data: function (params) {
+            return request({
+                url: '/index/pay_data',
+                params: params
+            });
+        },
+        get_unifiend_list: function (params) {
+            return request({
+                url: '/index/get_unifiend_list',
+                params: params
+            });
+        }
+    };
+});

+ 94 - 0
public/pc/api/live.js

xqd
@@ -0,0 +1,94 @@
+define([
+    'scripts/request'
+], function (request) {
+    return {
+        /**
+         * 直播间信息
+         * @param {object} params 
+         * @returns 
+         */
+        live_studio_index: function (params) {
+            return request({
+                url: '/live/live_studio_index',
+                params: params
+            });
+        },
+        /**
+         * 助教评论
+         * @param {object} params 
+         * @returns 
+         */
+        get_comment_list: function (params) {
+            return request({
+                url: '/live/get_comment_list',
+                params: params
+            });
+        },
+        /**
+         * 讲师、主教、普通人评论
+         * @param {object} params 
+         * @returns 
+         */
+        get_open_comment_list: function (params) {
+            return request({
+                url: '/live/get_open_comment_list',
+                params: params
+            });
+        },
+        /**
+         * 直播间录制的内容
+         * @param {object} params 
+         * @returns 
+         */
+        get_live_record_list: function (params) {
+            return request({
+                url: '/live/get_live_record_list',
+                params: params
+            });
+        },
+        /**
+         * 礼物
+         * @returns 
+         */
+        live_gift_list: function () {
+            return request({
+                url: '/live/live_gift_list'
+            });
+        },
+        /**
+         * 打赏
+         * @param {object} data 
+         * @returns 
+         */
+        live_reward: function (data) {
+            return request({
+                url: '/live/live_reward',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 带货商品
+         * @param {object} params 
+         * @returns 
+         */
+        live_goods_list: function (params) {
+            return request({
+                url: '/live/live_goods_list',
+                params: params
+            });
+        },
+        /**
+         * 礼物排行榜
+         * @param {object} data 
+         * @returns 
+         */
+        get_live_reward: function (data) {
+            return request({
+                url: '/live/get_live_reward',
+                method: 'post',
+                data: data
+            });
+        }
+    };
+});

+ 70 - 0
public/pc/api/login.js

xqd
@@ -0,0 +1,70 @@
+define([
+    'scripts/request'
+], function(request) {
+    return {
+        /**
+         * 短信登录、注册
+         * @param {*} data 
+         * @returns 
+         */
+        phoneCheck: function (data) {
+            return request({
+                url: '/login/phone_check',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 账号密码登录
+         * @param {*} data 
+         * @returns 
+         */
+        heck: function (data) {
+            return request({
+                url: '/login/check',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 账号密码注册、找回密码
+         * @param {*} data 
+         * @returns 
+         */
+        register: function (data) {
+            return request({
+                url: '/login/register',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 退出登录
+         * @returns 
+         */
+        logout: function () {
+            return request({
+                url: '/login/logout'
+            });
+        },
+        // 验证码
+        code: function (params) {
+            return request({
+                url: '/auth_api/code',
+                params: params
+            });
+        },
+        loginQrcode: function () {
+            return request({
+                url: '/login/login_pc_qrcode'
+            });
+        },
+        setScanLogin: function (data) {
+            return request({
+                url: '/login/setScanLogin',
+                method: 'post',
+                data: data
+            });
+        }
+    };
+});

+ 71 - 0
public/pc/api/material.js

xqd
@@ -0,0 +1,71 @@
+define([
+    'scripts/request'
+], function(request) {
+    return {
+        /**
+         * 资料分类
+         * @returns 
+         */
+        get_material_cate: function () {
+            return request({
+                url: '/material/get_material_cate'
+            });
+        },
+        /**
+         * 资料列表
+         * @param {*} data 
+         * @returns 
+         */
+        get_material_list: function (data) {
+            return request({
+                url: '/material/get_material_list',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 资料详情
+         * @param {*} params 
+         * @returns 
+         */
+        get_data_details: function (params) {
+            return request({
+                url: '/material/get_data_details',
+                params: params
+            });
+        },
+        /**
+         * 资料收藏
+         * @param {*} params 
+         * @returns 
+         */
+        collect: function (params) {
+            return request({
+                url: '/material/collect',
+                params: params
+            });
+        },
+        /**
+         * 增加下载记录
+         * @param {*} params 
+         * @returns 
+         */
+        user_download: function (params) {
+            return request({
+                url: '/material/user_download',
+                params: params
+            });
+        },
+        /**
+         * 获取下载链接
+         * @param {*} params 
+         * @returns 
+         */
+        get_data_download_link: function (params) {
+            return request({
+                url: '/material/get_data_download_link',
+                params: params
+            });
+        }
+    };
+});

+ 139 - 0
public/pc/api/merchant.js

xqd
@@ -0,0 +1,139 @@
+define([
+    'require',
+    'scripts/request',
+], function (require, request) {
+    'use strict';
+    return {
+        /**
+         * 讲师名下课程
+         * @param {*} data 
+         * @returns 
+         */
+        lecturer_special_list: function (data) {
+            return request({
+                url: '/merchant/lecturer_special_list',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 讲师名下资料
+         * @param {*} data 
+         * @returns 
+         */
+        lecturer_download_list: function (data) {
+            return request({
+                url: '/merchant/lecturer_download_list',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 讲师名下活动
+         * @param {*} data 
+         * @returns 
+         */
+        lecturer_event_list: function (data) {
+            return request({
+                url: '/merchant/lecturer_event_list',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 讲师申请
+         * @param {*} data 
+         * @returns 
+         */
+        apply: function (data) {
+            return request({
+                url: '/merchant/apply',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 检查是否提交申请
+         * @returns 
+         */
+        is_apply: function () {
+            return request({
+                url: '/merchant/is_apply'
+            });
+        },
+        /**
+         * 获得申请数据
+         * @returns 
+         */
+        apply_data: function () {
+            return request({
+                url: '/merchant/apply_data'
+            });
+        },
+        /**
+         * 讲师列表
+         * @param {*} params 
+         * @returns 
+         */
+        get_lecturer_list: function (params) {
+            return request({
+                url: '/merchant/get_lecturer_list',
+                params: params
+            });
+        },
+        /**
+         * 讲师入驻协议
+         * @returns 
+         */
+        lecturer_agree: function () {
+            return request({
+                url: '/merchant/lecturer_agree'
+            });
+        },
+        /**
+         * 是否关注
+         * @param {*} params 
+         * @returns 
+         */
+        is_follow: function (params) {
+            return request({
+                url: '/merchant/is_follow',
+                params: params
+            });
+        },
+        /**
+         * 关注、取消关注
+         * @param {*} params 
+         * @returns 
+         */
+        user_follow: function (params) {
+            return request({
+                url: '/merchant/user_follow',
+                params: params
+            });
+        },
+        /**
+         * 我的关注
+         * @param {*} params 
+         * @returns 
+         */
+        get_user_follow_list: function (params) {
+            return request({
+                url: '/merchant/get_user_follow_list',
+                params: params
+            });
+        },
+        /**
+         * 讲师的练习和考试
+         * @param {*} data 
+         * @returns 
+         */
+        lecturer_test_list: function (data) {
+            return request({
+                url: '/merchant/lecturer_test_list',
+                method: 'post',
+                data: data
+            });
+        },
+    };
+});

+ 52 - 0
public/pc/api/my.js

xqd
@@ -0,0 +1,52 @@
+define([
+    'scripts/request'
+], function (request) {
+    return {
+        /**
+         * 上传
+         * @param {*} data 
+         * @returns 
+         */
+        upload: function (data) {
+            return request({
+                url: '/auth_api/upload',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 修改头像、昵称
+         * @param {*} data 
+         * @returns 
+         */
+        saveUserInfo: function (data) {
+            return request({
+                url: '/my/save_user_info',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 修改手机号-验证旧手机号
+         * @param {*} params 
+         * @returns 
+         */
+        validate_code: function (params) {
+            return request({
+                url: '/my/validate_code',
+                params: params
+            });
+        },
+        /**
+         * 修改手机号-保存新手机号
+         * @param {*} params 
+         * @returns 
+         */
+        save_phone: function (params) {
+            return request({
+                url: '/my/save_phone',
+                params: params
+            });
+        }
+    };
+});

+ 42 - 0
public/pc/api/public.js

xqd
@@ -0,0 +1,42 @@
+define([
+    'scripts/request'
+], function(request) {
+    return {
+        /**
+         * 页面公共数据
+         * @returns 
+         */
+        public_data: function () {
+            return request({
+                url: '/public_api/public_data'
+            });
+        },
+        /**
+         * 用户协议
+         * @returns 
+         */
+        agree: function () {
+            return request({
+                url: '/public_api/agree'
+            });
+        },
+        /**
+         * 热搜词
+         * @returns 
+         */
+        get_host_search: function () {
+            return request({
+                url: '/public_api/get_host_search'
+            });
+        },
+        /**
+         * 顶部导航
+         * @returns 
+         */
+        get_home_navigation: function () {
+            return request({
+                url: '/public_api/get_home_navigation'
+            });
+        }
+    };
+});

+ 251 - 0
public/pc/api/special.js

xqd
@@ -0,0 +1,251 @@
+define([
+    'scripts/request'
+], function (request) {
+    return {
+        /**
+         * 专题详情
+         * @param {object} params 
+         * @returns 
+         */
+        get_special_details: function (params) {
+            return request({
+                url: '/special/get_special_details',
+                params: params
+            });
+        },
+        /**
+         * 轻专题详情
+         * @param {*} params 
+         * @returns 
+         */
+        get_special_single_details: function (params) {
+            return request({
+                url: '/special/get_special_single_details',
+                params: params
+            });
+        },
+        /**
+         * 专题的课程数量
+         * @param {object} params 
+         * @returns 
+         */
+        numberCourses: function (params) {
+            return request({
+                url: '/special/numberCourses',
+                params: params
+            });
+        },
+        /**
+         * 专题关联的资料
+         * @param {object} params 
+         * @returns 
+         */
+        special_data_download: function (params) {
+            return request({
+                url: '/special/special_data_download',
+                params: params
+            });
+        },
+        /**
+         * 专题页推荐课程
+         * @param {object} params 
+         * @returns 
+         */
+        recommended_courses: function (params) {
+            return request({
+                url: '/special/recommended_courses',
+                params: params
+            });
+        },
+        /**
+         * 专题的素材
+         * @param {object} params 
+         * @returns 
+         */
+        get_course_list: function (params) {
+            return request({
+                url: '/special/get_course_list',
+                params: params
+            });
+        },
+        /**
+         * 专题页套餐
+         * @param {object} params 
+         * @returns 
+         */
+        get_cloumn_task: function (params) {
+            return request({
+                url: '/special/get_cloumn_task',
+                params: params
+            });
+        },
+        /**
+         * 评价概况
+         * @param {object} params 
+         * @returns 
+         */
+        special_reply_data: function (params) {
+            return request({
+                url: '/special/special_reply_data',
+                params: params
+            });
+        },
+        /**
+         * 评价列表
+         * @param {object} params 
+         * @returns 
+         */
+        special_reply_list: function (params) {
+            return request({
+                url: '/special/special_reply_list',
+                params: params
+            });
+        },
+        /**
+         * 评价专题
+         * @param {string} special_id 
+         * @param {object} data 
+         * @returns 
+         */
+        user_comment_special: function (special_id, data) {
+            return request({
+                url: '/special/user_comment_special?special_id=' + special_id,
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 专题分类
+         * @returns 
+         */
+        get_grade_cate: function () {
+            return request({
+                url: '/special/get_grade_cate'
+            });
+        },
+        /**
+         * 分类
+         * @param {object} params 
+         * @returns 
+         */
+         get_all_special_cate: function (params) {
+            return request({
+                url: '/special/get_all_special_cate',
+                params: params
+            });
+        },
+        /**
+         * 专题分类列表
+         * @param {object} params 
+         * @returns 
+         */
+        get_special_list: function (params) {
+            return request({
+                url: '/special/get_special_list',
+                params: params
+            });
+        },
+        /**
+         * 素材详情
+         * @param {object} data 
+         * @returns 
+         */
+        getTaskInfo: function (data) {
+            return request({
+                url: '/special/getTaskInfo',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 视频上传凭证
+         * @param {object} params 
+         * @returns 
+         */
+        get_video_playback_credentials: function (params) {
+            return request({
+                url: '/special/get_video_playback_credentials',
+                params: params
+            });
+        },
+        /**
+         * 所有直播课
+         * @param {object} params 
+         * @returns 
+         */
+        get_live_special_list: function (params) {
+            return request({
+                url: '/special/get_live_special_list',
+                params: params
+            });
+        },
+        /**
+         * 专题收藏
+         * @param {*} params 
+         * @returns 
+         */
+        collect: function (params) {
+            return request({
+                url: '/special/collect',
+                params: params
+            });
+        },
+        /**
+         * 记录观看素材时间
+         * @param {*} data 
+         * @returns 
+         */
+        viewing: function (data) {
+            return request({
+                url: '/special/viewing',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 记录专题浏览人数
+         * @param {*} params 
+         * @returns 
+         */
+        addLearningRecords: function (params) {
+            return request({
+                url: '/special/addLearningRecords',
+                params: params
+            });
+        },
+        /**
+         * 提交兑换码
+         * @param {*} data 
+         * @returns 
+         */
+        exchange_submit: function (data) {
+            return request({
+                url: '/special/exchange_submit',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 是否可以播放
+         * @param {*} params 
+         * @returns 
+         */
+        get_task_link: function (params) {
+            return request({
+                url: '/special/get_task_link',
+                params: params
+            });
+        },
+        /**
+         * 播放数量增加
+         * @param {*} params 
+         * @returns 
+         */
+        play_num: function (params) {
+            return request({
+                url: '/special/play_num',
+                params: params
+            });
+        }
+    };
+});

+ 223 - 0
public/pc/api/topic.js

xqd
@@ -0,0 +1,223 @@
+define([
+    'scripts/request'
+], function (request) {
+    return {
+        /**
+         * 试卷分类
+         * @param {*} params 
+         * @returns 
+         */
+        testPaperCate: function (params) {
+            return request({
+                url: '/topic/testPaperCate',
+                params: params
+            });
+        },
+        /**
+         * 试卷列表
+         * @param {*} params 
+         * @returns 
+         */
+        practiceList: function (type, data) {
+            return request({
+                url: '/topic/practiceList?type=' + type,
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 试卷信息
+         * @param {*} params 
+         * @returns 
+         */
+        testPaperDetails: function (params) {
+            return request({
+                url: '/topic/testPaperDetails',
+                params: params
+            });
+        },
+        /**
+         * 试卷状态
+         * @param {*} params 
+         * @returns 
+         */
+        situationRecord: function (params) {
+            return request({
+                url: '/topic/situationRecord',
+                params: params
+            });
+        },
+        /**
+         * 开始答题
+         * @param {*} params 
+         * @returns 
+         */
+        userAnswer: function (params) {
+            return request({
+                url: '/topic/userAnswer',
+                params: params
+            });
+        },
+        /**
+         * 再次答题
+         * @param {*} params 
+         * @returns 
+         */
+        takeTheTestAgain: function (params) {
+            return request({
+                url: '/topic/takeTheTestAgain',
+                params: params
+            });
+        },
+        /**
+         * 继续答题
+         * @param {*} params 
+         * @returns 
+         */
+        continueAnswer: function (params) {
+            return request({
+                url: '/topic/continueAnswer',
+                params: params
+            });
+        },
+        /**
+         * 试卷内容
+         * @param {*} params 
+         * @returns 
+         */
+        testPaperQuestions: function (params) {
+            return request({
+                url: '/topic/testPaperQuestions',
+                params: params
+            });
+        },
+        /**
+         * 提交单题
+         * @param {*} data 
+         * @returns 
+         */
+        submitQuestions: function (data) {
+            return request({
+                url: '/topic/submitQuestions',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 答题卡
+         * @param {*} params 
+         * @returns 
+         */
+        answerSheet: function (params) {
+            return request({
+                url: '/topic/answerSheet',
+                params: params
+            });
+        },
+        /**
+         * 提交试卷
+         * @param {*} data 
+         * @returns 
+         */
+        submitTestPaper: function (data) {
+            return request({
+                url: '/topic/submitTestPaper',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 考试结果
+         * @param {*} params 
+         * @returns 
+         */
+        examinationResults: function (params) {
+            return request({
+                url: '/topic/examinationResults',
+                params: params
+            });
+        },
+        /**
+         * 我的试卷
+         * @param {*} data 
+         * @returns 
+         */
+        myTestPaper: function (data) {
+            return request({
+                url: '/topic/myTestPaper',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 我的错题
+         * @param {*} data 
+         * @returns 
+         */
+        userWrongBank: function (data) {
+            return request({
+                url: '/topic/userWrongBank',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 我的错题id
+         * @param {*} data 
+         * @returns 
+         */
+        userWrongBankIdArr: function (data) {
+            return request({
+                url: '/topic/userWrongBankIdArr',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 单个错题
+         * @param {*} params 
+         * @returns 
+         */
+        oneWrongBank: function (params) {
+            return request({
+                url: '/topic/oneWrongBank',
+                params: params
+            });
+        },
+        /**
+         * 掌握错题
+         * @param {*} data 
+         * @returns 
+         */
+        submitWrongBank: function (data) {
+            return request({
+                url: '/topic/submitWrongBank',
+                method: 'post',
+                data: data
+            });
+        },
+        /**
+         * 删除错题
+         * @param {*} params 
+         * @returns 
+         */
+        delWrongBank: function (params) {
+            return request({
+                url: '/topic/delWrongBank',
+                params: params
+            });
+        },
+        /**
+         * 专题的练习和考试
+         * @param {*} data 
+         * @returns 
+         */
+        specialTestPaper: function (data) {
+            return request({
+                url: '/topic/specialTestPaper',
+                method: 'post',
+                data: data
+            });
+        },
+    };
+});

+ 64 - 0
public/pc/components/account-change/index.css

xqd
@@ -0,0 +1,64 @@
+.phone-pwd-dialog .el-dialog__header {
+    padding-top: 47px;
+}
+
+.phone-pwd-dialog .el-dialog__title {
+    font-size: 20px;
+    color: #282828;
+}
+
+.phone-pwd-dialog .el-dialog__body {
+    padding: 17px 56px 59px;
+}
+
+.phone-pwd-dialog .el-form-item {
+    margin-bottom: 20px;
+}
+
+.phone-pwd-dialog .el-form-item:last-child {
+    margin-top: 40px;
+}
+
+.phone-pwd-dialog .el-input__inner {
+    height: 50px;
+    border-radius: 25px;
+    font-size: 14px;
+    line-height: 50px;
+}
+
+.phone-pwd-dialog .el-form-item:nth-child(2) .el-input__inner {
+    border-top-right-radius: 0;
+    border-bottom-right-radius: 0;
+}
+
+.phone-pwd-dialog .el-input-group__append {
+    border-top-right-radius: 25px;
+    border-bottom-right-radius: 25px;
+    background-color: #fff;
+}
+
+.phone-pwd-dialog .el-input-group__append .el-button {
+    width: 112px;
+    padding: 17px 0;
+    border-top-right-radius: 24px;
+    border-bottom-right-radius: 24px;
+    color: #2c8eff;
+}
+
+.phone-pwd-dialog .el-button.is-disabled, .phone-pwd-dialog .el-button.is-disabled:focus, .phone-pwd-dialog .el-button.is-disabled:hover {
+    color: #ccc;
+}
+
+.phone-pwd-dialog .el-form-item:last-child .el-button {
+    width: 100%;
+    padding-top: 17px;
+    padding-bottom: 17px;
+    border-color: #409dff;
+    border-radius: 25px;
+    background: -webkit-gradient(linear, left top, right top, from(#409dff), to(#1e85fb));
+    background: -webkit-linear-gradient(left, #409dff 0%, #1e85fb 100%);
+    background: -moz-linear-gradient(left, #409dff 0%, #1e85fb 100%);
+    background: -o-linear-gradient(left, #409dff 0%, #1e85fb 100%);
+    background: linear-gradient(90deg, #409dff 0%, #1e85fb 100%);
+    color: #fff;
+}

+ 26 - 0
public/pc/components/account-change/index.html

xqd
@@ -0,0 +1,26 @@
+<el-dialog :visible="sharedState.accountVisible" :title="sharedState.isAccount ? '修改手机号' : '修改密码'" width="470px" custom-class="phone-pwd-dialog" center @close="accountClose">
+    <el-form>
+        <template v-if="sharedState.isAccount">
+            <el-form-item v-if="state">
+                <el-input :value="currentPhone" disabled></el-input>
+            </el-form-item>
+            <el-form-item v-else>
+                <el-input v-model.trim="phone" placeholder="请输入新手机号" clearable></el-input>
+            </el-form-item>
+        </template>
+        <el-form-item v-else>
+            <el-input :value="currentPhone" disabled></el-input>
+        </el-form-item>
+        <el-form-item>
+            <el-input v-model.trim="code" placeholder="请输入验证码" maxlength="6" minlength="6" clearable>
+                <el-button slot="append" :disabled="count >= 0" @click="getCode">{{ count < 0 ? '获取验证码' : '重新获取(' + count + 's)' }}</el-button>
+            </el-input>
+        </el-form-item>
+        <el-form-item v-if="!sharedState.isAccount">
+            <el-input v-model.trim="pwd" placeholder="请输入8-16位字母加数字组合新密码" maxlength="16" minlength="8" show-password></el-input>
+        </el-form-item>
+        <el-form-item>
+            <el-button @click="submit">确认</el-button>
+        </el-form-item>
+    </el-form>
+</el-dialog>

+ 127 - 0
public/pc/components/account-change/index.js

xqd
@@ -0,0 +1,127 @@
+define([
+    'store/index',
+    'api/login',
+    'api/my',
+    'plugins/blueimp-md5/js/md5',
+    'text!./index.html',
+    'css!./index.css'
+], function(store, loginApi, myApi, md5, html) {
+    return {
+        inject: ['logout'],
+        props: {
+            currentPhone: {
+                type: String,
+                default: ''
+            }
+        },
+        data: function () {
+            return {
+                state: true,
+                phone: '',
+                code: '',
+                pwd: '',
+                count: -1,
+                TIME_COUNT: 60,
+                sharedState: store.state
+            };
+        },
+        methods: {
+            // 获取验证码
+            getCode: function () {
+                var vm = this;
+                this.count = this.TIME_COUNT;
+                this.timer = setInterval(function () {
+                    vm.count--;
+                    if (vm.count < 0) {
+                        clearInterval(vm.timer);
+                        vm.timer = null;
+                    }
+                }, 1000);
+                loginApi.code({
+                    phone: this.currentPhone
+                }).then(function (res) {
+                    vm.$message.success(res.msg);
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                    clearInterval(vm.timer);
+                    vm.timer = null;
+                    vm.count = -1;
+                });
+            },
+            submit: function () {
+                var vm = this;
+                if (!this.state) {
+                    if (!this.phone) {
+                        return this.$message.warning('请输入手机号');
+                    }
+                    if (!/^1[3456789]\d{9}$/.test(this.phone)) {
+                        return this.$message.warning('手机号错误');
+                    }   
+                }
+                if (!this.code) {
+                    return this.$message.warning('请输入验证码');
+                }
+                if (!/^\d{6}$/.test(this.code)) {
+                    return this.$message.warning('验证码错误');
+                }
+                if (this.timer) {
+                    clearInterval(this.timer);
+                    this.timer = null;
+                }
+                if (this.phonePassword) {
+                    if (this.state) {
+                        // 验证旧手机号
+                        myApi.validate_code({
+                            phone: this.currentPhone,
+                            code: this.code
+                        }).then(function () {
+                            vm.state = false;
+                            vm.phone = '';
+                            vm.code = '';
+                        }).catch(function (err) {
+                            vm.$message.error(err.msg);
+                            vm.count = -1;
+                        });
+                        return;
+                    }
+                    // 保存新手机号
+                    myApi.save_phone({
+                        phone: this.phone,
+                        code: this.code
+                    }).then(function (res) {
+                        vm.$message.success(res.msg);
+                        vm.accountClose();
+                        vm.logout();
+                    }).catch(function (err) {
+                        vm.$message.error(err.msg);
+                        vm.count = -1;
+                    });
+                }
+                if (!this.pwd) {
+                    return this.$message.warning('请输入密码');
+                }
+                if (!/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$/.test(this.pwd)) {
+                    return this.$message.warning('请输入8-16位字母加数字组合新密码');
+                }
+                // 修改密码
+                loginApi.register({
+                    account: this.currentPhone,
+                    code: this.code,
+                    pwd: md5(this.pwd),
+                    type: 2
+                }).then(function (res) {
+                    vm.$message.success(res.msg);
+                    vm.accountClose();
+                    vm.logout();
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                    vm.count = -1;
+                });
+            },
+            accountClose: function () {
+                store.setAccountAction(false);
+            }
+        },
+        template: html
+    };
+});

+ 34 - 0
public/pc/components/base-agree/index.css

xqd
@@ -0,0 +1,34 @@
+.agree-dialog .el-dialog__header {
+    padding-bottom: 5px;
+}
+
+.agree-dialog .el-dialog__title {
+    font-weight: bold;
+    font-size: 20px;
+    color: #333;
+}
+
+.agree-dialog.el-dialog--center .el-dialog__body {
+    max-height: 400px;
+    padding-right: 30px;
+    padding-bottom: 10px;
+    padding-left: 30px;
+    overflow: auto;
+}
+
+.agree-dialog .el-dialog__footer {
+    padding-bottom: 30px;
+}
+
+.agree-dialog .el-button {
+    padding: 14px 73px;
+    border-color: #2c8eff;
+    border-radius: 23px;
+    background-color: #2c8eff;
+    font-size: 16px;
+    color: #fff;
+}
+
+.agree-dialog.el-dialog--center .el-dialog__body * {
+    white-space: pre-wrap;
+}

+ 7 - 0
public/pc/components/base-agree/index.html

xqd
@@ -0,0 +1,7 @@
+<el-dialog :title="(agreeContent && agreeContent.title) || ''" :visible="agreeVisible" width="900px" center custom-class="agree-dialog" @close="agreeClose">
+    <span v-if="agreeContent && agreeContent.content" v-html="agreeContent.content"></span>
+    <el-empty v-else description="暂无内容"></el-empty>
+    <span slot="footer" class="dialog-footer">
+        <el-button @click="agreeClose">确定</el-button>
+    </span>
+</el-dialog>

+ 25 - 0
public/pc/components/base-agree/index.js

xqd
@@ -0,0 +1,25 @@
+define([
+    'store/index',
+    'text!./index.html',
+    'css!./index.css'
+], function(store, html) {
+    return {
+        props: {
+            agreeContent: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            }
+        },
+        data: function () {
+            return store.state;
+        },
+        methods: {
+            agreeClose: function () {
+                store.setAgreeAction(false);
+            }
+        },
+        template: html
+    };
+});

+ 200 - 0
public/pc/components/base-footer/index.css

xqd
@@ -0,0 +1,200 @@
+.base-footer {
+    background-color: #f2f2f2;
+}
+
+.base-footer .el-row {
+    width: 1200px;
+    margin: 0 auto;
+}
+
+.base-footer .el-row:first-child {
+    padding-top: 32px;
+    padding-bottom: 32px;
+    font-size: 16px;
+    text-align: center;
+    color: #666;
+}
+
+.base-footer .el-col-6 > div {
+    display: -webkit-inline-box;
+    display: -webkit-inline-flex;
+    display: -moz-inline-box;
+    display: -ms-inline-flexbox;
+    display: inline-flex;
+}
+
+.base-footer .el-image {
+    width: 38px;
+    height: 38px;
+    margin: 0 10px 0 0;
+    vertical-align: middle;
+}
+
+.base-footer .el-row:last-child {
+    padding-top: 30px;
+    padding-bottom: 48px;
+    border-top: 1px solid #e2e2e2;
+    font-size: 14px;
+    line-height: 22px;
+    text-align: center;
+    color: #999;
+}
+
+.base-footer .footer span {
+    display: inline-block;
+}
+
+.base-footer .address {
+    margin-left: 40px;
+}
+
+.base-footer .footer .el-image + span {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    min-width: 0;
+    padding: 12px 0 0;
+    margin: 0;
+    text-align: left;
+}
+
+.base-footer .el-link {
+    font-weight: normal;
+    color: #999;
+}
+
+.base-footer .sidebar {
+    position: fixed;
+    right: 40px;
+    bottom: 50%;
+    z-index: 99;
+    transform: translateY(50%);
+}
+
+.base-footer .sidebar .button-group {
+    -webkit-box-shadow: 0 3px 20px rgba(91, 126, 165, 0.15);
+            box-shadow: 0 3px 20px rgba(91, 126, 165, 0.15);
+}
+
+.base-footer .el-button {
+    position: relative;
+    display: block;
+    width: 64px;
+    height: 90px;
+    padding: 0;
+    border: 0;
+    border-radius: 0;
+    line-height: 18px;
+    color: #666666;
+}
+
+.base-footer .el-button:hover {
+    color: #2c8eff;
+}
+
+.base-footer > .el-button::after {
+    content: "";
+    position: absolute;
+    right: 12px;
+    bottom: 0;
+    left: 12px;
+    z-index: 2;
+    height: 1px;
+    background-color: #f0f0f0;
+}
+
+.base-footer > .el-button:last-child::after {
+    display: none;
+}
+
+.base-footer .service-button span {
+    display: block;
+    padding-top: 34px;
+    background: url("../../images/service1.png") top center/28px 28px no-repeat;
+}
+
+.base-footer .service-button:hover span {
+    background-image: url("../../images/service2.png");
+}
+
+.phone-popover {
+    padding: 0;
+    border-color: #2C8EFF;
+}
+
+.phone-popover .content {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+       -moz-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    height: 74px;
+    padding: 0 21px 0 53px;
+    background: url("../../images/phone2.png") 29px center/24px 24px no-repeat;
+    font-size: 14px;
+    line-height: 19px;
+    text-align: center;
+    color: #2C8EFF;
+}
+
+.phone-popover .content div:last-child {
+    margin-top: 3px;
+}
+
+.phone-popover-reference span {
+    display: block;
+    padding-top: 34px;
+    background: url("../../images/phone1.png") top center/28px 28px no-repeat;
+}
+
+.phone-popover-reference:hover span {
+    background-image: url("../../images/phone2.png");
+}
+
+.el-popover.phone-popover .popper__arrow {
+    border-left-color: #2C8EFF;
+}
+
+.base-footer .el-backtop {
+    width: 64px;
+    height: 30px;
+    border-radius: 0;
+    font-size: 18px;
+    color: #999;
+}
+
+.subscribe-popover {
+    min-width: 0;
+    padding: 0;
+    border: 0;
+}
+
+.subscribe-popover img {
+    display: block;
+    width: 110px;
+    height: 110px;
+    margin: 15px auto;
+}
+
+.subscribe-popover img + div {
+    border-radius: 0 0 4px 4px;
+    background-color: #2C8EFF;
+    font-size: 12px;
+    line-height: 26px;
+    text-align: center;
+    color: #FFFFFF;
+}

+ 49 - 0
public/pc/components/base-footer/index.html

xqd
@@ -0,0 +1,49 @@
+<div class="base-footer">
+    <div v-if="publicData" class="footer">
+        <el-row v-if="publicData.pc_end_bottom_display && publicData.pc_end_bottom_display.length">
+            <el-col v-for="item in publicData.pc_end_bottom_display" :key="item.id" :span="6">
+                <div>
+                    <el-image :src="item.pic" fit="cover"></el-image><span>{{ item.title }}</span>
+                </div>
+            </el-col>
+        </el-row>
+        <el-row>
+            <el-col v-if="publicData.site_phone || publicData.company_address" :span="24">
+                <span v-if="publicData.site_phone">联系电话:{{ publicData.site_phone }}</span>
+                <span v-if="publicData.company_address" class="address">地址:{{ publicData.company_address }}</span>
+            </el-col>
+            <el-col v-if="publicData.full_name_the_company || publicData.keep_on_record" :span="24">
+                <span v-if="publicData.full_name_the_company">Copyright © {{ publicData.full_name_the_company }}</span>
+                <el-link v-if="publicData.keep_on_record" :underline="false" href="https://beian.miit.gov.cn/#/Integrated/index" target="_blank">{{ publicData.keep_on_record }}</el-link>
+            </el-col>
+        </el-row>
+    </div>
+    <div ref="sidebar" class="sidebar">
+        <div class="button-group">
+                <el-button v-if="publicData && publicData.service_url" class="service-button" @click="goPage">
+                咨询<br>客服
+            </el-button>
+            <el-popover v-if="publicData && publicData.site_service_phone" trigger="hover" width="200" placement="left" popper-class="phone-popover" effect="light">
+                <div class="content">
+                    <div>服务热线</div>
+                    <div>{{ publicData.site_service_phone }}</div>
+                </div>
+                <el-button slot="reference" class="phone-popover-reference">
+                    服务<br>热线
+                </el-button>
+            </el-popover>
+            <el-popover v-if="code_url" trigger="hover" width="140" placement="left" popper-class="subscribe-popover">
+                <div class="content">
+                    <img :src="code_url" alt="公众号">
+                    <div>扫码关注公众号</div>
+                </div>
+                <el-button slot="reference">
+                    关注<br>公众号
+                </el-button>
+            </el-popover>
+        </div>
+        <el-backtop :style="{top: 'calc(50% + '+(sidebarHeight/2)+'px)', bottom: 'auto', right: 'auto'}">
+            <i class="el-icon-arrow-up"></i>
+        </el-backtop>
+    </div>
+</div>

+ 41 - 0
public/pc/components/base-footer/index.js

xqd
@@ -0,0 +1,41 @@
+define([
+    'text!./index.html',
+    'css!./index.css'
+], function (html) {
+    return {
+        props: {
+            publicData: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            }
+        },
+        data: function () {
+            return {
+                year: new Date().getFullYear(),
+                code_url: '',
+                sidebarHeight: 0
+            };
+        },
+        mounted: function () {
+            this.$nextTick(function () {
+                if (code_url) {
+                    this.code_url = code_url;
+                }
+            });               
+        },
+        updated: function () {
+            this.$nextTick(function () {
+                this.sidebarHeight = this.$refs.sidebar.clientHeight;
+                this.$emit('action', this.$refs.sidebar.clientHeight);
+            });
+        },
+        methods: {
+            goPage: function () {
+                window.useCustomerServer.getCustomeServer();
+            }
+        },
+        template: html
+    };
+});

二進制
public/pc/components/base-header/images/1.png


二進制
public/pc/components/base-header/images/2.png


二進制
public/pc/components/base-header/images/3.png


+ 424 - 0
public/pc/components/base-header/index.css

xqd
@@ -0,0 +1,424 @@
+.base-header {
+    border-bottom: 1px solid #F9F9F9;
+    background-color: #fff;
+}
+
+.base-header > div:not(:first-child) {
+    width: 1200px;
+    margin: 0 auto;
+}
+
+.base-header .button-bar {
+    background-color: #282828;
+}
+
+.base-header .bar-inner {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+    -moz-box-pack: justify;
+    -ms-flex-pack: justify;
+    justify-content: space-between;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+    -moz-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    width: 1200px;
+    height: 40px;
+    margin: 0 auto;
+}
+
+.base-header .button-bar .el-button--text {
+    padding: 0 15px;
+    border: 0;
+    border-left: 1px solid rgba(255, 255, 255, 0.1);
+    border-radius: 0;
+    font-size: 12px;
+    color: #b4b4b4;
+}
+
+.base-header .button-bar .el-button--text:hover {
+    color: #FFFFFF;
+}
+
+.base-header .button-bar .group-right {
+    display: -webkit-inline-box;
+    display: -webkit-inline-flex;
+    display: -moz-inline-box;
+    display: -ms-inline-flexbox;
+    display: inline-flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+    -moz-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+}
+
+.base-header .button-bar .group-right a {
+    float: left;
+    display: -webkit-inline-box;
+    display: -webkit-inline-flex;
+    display: -moz-inline-box;
+    display: -ms-inline-flexbox;
+    display: inline-flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+    -moz-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    padding-right: 15px;
+    padding-left: 15px;
+    font-size: 12px;
+    color: #b4b4b4;
+}
+
+.base-header .button-bar .group-right > span {
+    font-size: 0;
+}
+
+.base-header .button-bar .group-left > .el-button--text:first-child, .base-header .button-bar .group-right > .el-button--text:first-child {
+    border: 0;
+}
+
+.base-header .button-bar .el-avatar {
+    margin-right: 8px;
+}
+
+.base-header .logo-search {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+    -moz-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    padding: 17px 0;
+}
+
+.base-header .logo-search .el-image {
+    width: 126px;
+    height: 65px;
+    margin-left: 52px;
+}
+
+.base-header .logo-search .search {
+    margin-left: 266px;
+}
+
+.base-header .el-input-group {
+    width: 540px;
+}
+
+.base-header .el-input__inner {
+    border-color: #2c8eff;
+}
+
+.base-header .el-input-group__append, .base-header .el-input-group__prepend {
+    border-color: #2c8eff;
+    background-color: #FFFFFF;
+}
+
+.base-header .el-select .el-input {
+    width: 80px;
+}
+
+.base-header .el-input-group__append .el-button {
+    width: 90px;
+    height: 40px;
+    border-color: #2c8eff;
+    border-radius: 0 4px 4px 0;
+    background: #2c8eff;
+    font-size: 14px;
+    color: #fff;
+}
+
+.base-header > div:nth-child(2) .el-button-group {
+    display: block;
+    width: 540px;
+    height: 16px;
+    margin-top: 10px;
+    overflow: hidden;
+}
+
+.base-header > div:nth-child(2) .el-button--text {
+    padding-top: 0;
+    padding-bottom: 0;
+    border: 0;
+    margin-right: 18px;
+    font-size: 14px;
+    line-height: 16px;
+    color: #999;
+}
+
+.base-header > div:nth-child(2) .el-button--text:hover {
+    color: #2c8eff;
+}
+
+.base-header .category {
+    position: relative;
+    display: inline-block;
+}
+
+.base-header .category > .el-button {
+    width: 230px;
+    height: 56px;
+    border: 0;
+    border-radius: 8px 8px 0 0;
+    background: -webkit-linear-gradient(181deg, #409DFF 0%, #1E85FB 100%);
+    background: -moz-linear-gradient(181deg, #409DFF 0%, #1E85FB 100%);
+    background: -o-linear-gradient(181deg, #409DFF 0%, #1E85FB 100%);
+    background: linear-gradient(269deg, #409DFF 0%, #1E85FB 100%);
+    font-size: 18px;
+    color: #fff;
+}
+
+.base-header .category > .el-button span {
+    padding: 0 0 0 28px;
+    background: url("../../images/cate_icon.png") left center/15px 12px no-repeat;
+}
+
+.base-header .category .wrapper {
+    position: absolute;
+    top: 100%;
+    left: 0;
+    z-index: 100;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    height: 0;
+    -webkit-transition: 0.3s;
+    -o-transition: 0.3s;
+    -moz-transition: 0.3s;
+    transition: 0.3s;
+}
+
+.base-header .category .wrapper.on {
+    height: 450px;
+}
+
+.base-header .category .menu {
+    width: 230px;
+    background-color: rgba(0, 0, 0, 0.6);
+    overflow: auto;
+    scrollbar-width: none;
+    -ms-overflow-style: none;
+    -webkit-transition: 0.3s;
+    -o-transition: 0.3s;
+    -moz-transition: 0.3s;
+    transition: 0.3s;
+}
+
+.base-header .category .menu::-webkit-scrollbar {
+    display: none; /* Chrome Safari */
+  }
+
+.base-header .category .menu .el-button {
+    width: 100%;
+    height: 50px;
+    padding-right: 32px;
+    padding-left: 32px;
+    border-radius: 0;
+    margin-left: 0;
+    color: #fff;
+}
+
+.base-header .category .menu .el-button.on {
+    background-color: #2c8eff;
+}
+
+.base-header .category .menu .el-button span {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+    -moz-box-pack: justify;
+    -ms-flex-pack: justify;
+    justify-content: space-between;
+    font-size: 16px;
+}
+
+.base-header .category .content > div {
+    width: 710px;
+    height: 100%;
+    padding-right: 30px;
+    padding-left: 30px;
+    background-color: #fff;
+    -webkit-box-shadow: 0 0 10px rgba(106, 128, 154, 0.15);
+    box-shadow: 0 0 10px rgba(106, 128, 154, 0.15);
+    overflow-y: auto;
+    scrollbar-width: none;
+}
+.base-header .category .content > div::-webkit-scrollbar {
+    display: none;
+}
+
+.base-header .category .title {
+    padding-top: 30px;
+    padding-bottom: 20px;
+    font-weight: bold;
+    font-size: 16px;
+    color: #282828;
+}
+
+.base-header .category .wrap .el-link {
+    margin-right: 40px;
+    margin-bottom: 12px;
+    font-size: 14px;
+    color: #333;
+}
+
+.base-header .category .wrap .el-link:hover {
+    color: #2c8eff;
+}
+
+.base-header .category .wrap.special > div:nth-child(2) {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-flex-wrap: wrap;
+    -ms-flex-wrap: wrap;
+    flex-wrap: wrap;
+    margin-right: -30px;
+}
+
+.base-header .category .wrap.special a {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    width: 310px;
+    margin-right: 30px;
+    margin-bottom: 30px;
+}
+
+.base-header .category .el-image {
+    width: 140px;
+    height: 80px;
+    border-radius: 4px;
+}
+
+.base-header .category .el-image + div {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+    -moz-box-flex: 1;
+    -ms-flex: 1;
+    flex: 1;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+    -moz-box-orient: vertical;
+    -moz-box-direction: normal;
+    -ms-flex-direction: column;
+    flex-direction: column;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+    -moz-box-pack: justify;
+    -ms-flex-pack: justify;
+    justify-content: space-between;
+    min-width: 0;
+    margin-left: 12px;
+    font-size: 12px;
+    color: #999;
+}
+
+.base-header .category .el-image + div > div:first-child > div:first-child {
+    overflow: hidden;
+    white-space: nowrap;
+    -o-text-overflow: ellipsis;
+    text-overflow: ellipsis;
+    font-size: 14px;
+    color: #282828;
+}
+
+.base-header .category .el-image + div > div:first-child > div:nth-child(2) {
+    margin-top: 6px;
+    color: #ff6b00;
+}
+
+.base-header .category .el-image + div > div:first-child > div:nth-child(2) span {
+    font-size: 16px;
+}
+
+.base-header .nav-wrapper > .el-link {
+    padding-right: 25px;
+    padding-left: 25px;
+    font-size: 18px;
+    color: #333;
+}
+
+.base-header .nav-wrapper > .el-link:hover {
+    color: #2c8eff;
+}
+
+.base-header .nav-wrapper > .el-link:nth-child(2) {
+    padding-left: 40px;
+}
+
+.base-header .nav-wrapper > .el-link.on {
+    font-weight: bold;
+    color: #2c8eff;
+}
+
+.base-header .el-input-group__append, .el-input-group__prepend {
+    background-color: #fff;
+}
+
+.base-header .qrcode-popover {
+    min-width: auto;
+    padding: 5px;
+}
+
+.base-header .qrcode-popover .el-image {
+    width: 70px;
+    height: 70px;
+}
+
+.base-header .qrcode-popover .el-image + div {
+    margin: 2px 0 0;
+    font-size: 9px;
+    line-height: 12px;
+    text-align: center;
+    color: #666666;
+}
+
+.base-header .apply-dialog .el-dialog__body {
+    padding: 42px 0 39px;
+    text-align: center;
+}
+
+.base-header .apply-dialog .title {
+    margin-top: 40px;
+    text-align: center;
+    font-size: 22px;
+    line-height: 29px;
+    color: #2C8EFF;
+}
+
+.base-header .apply-dialog .message {
+    margin-top: 10px;
+    text-align: center;
+    font-size: 16px;
+    line-height: 21px;
+    color: #939393;
+}

+ 91 - 0
public/pc/components/base-header/index.html

xqd
@@ -0,0 +1,91 @@
+<div class="base-header">
+    <div class="button-bar">
+        <div class="bar-inner">
+            <el-button-group class="group-left">
+                <el-button type="text" icon="el-icon-star-off" @click="addFavorite">收藏本站</el-button>
+                <el-button v-if="pageName !== 'home'" type="text" icon="el-icon-house" @click="goPage('home')">返回首页</el-button>
+            </el-button-group>
+            <el-button-group class="group-right">
+                <a v-if="userInfo" :href="$router.user">
+                    <el-avatar :size="22" :src="userInfo.avatar"></el-avatar>
+                    {{ userInfo.nickname }}
+                </a>
+                <el-button v-else type="text" @click="loginOpen">登录/注册</el-button>
+                <el-button @click="goPage(['user', {activeName: 'member'}])" type="text">会员中心</el-button>
+                <el-button @click="goPage(['user', {activeName: 'special'}])" type="text">我的课程</el-button>
+                <el-button v-if="(!userInfo || !userInfo.business) && pageName !== 'teacher_apply'" @click="goPage('teacher_apply')" type="text">讲师申请
+                </el-button>
+                <el-button v-if="userInfo && userInfo.business" @click="goPage('teacher_apply')" type="text">讲师后台</el-button>
+            </el-button-group>
+        </div>
+    </div>
+    <div class="logo-search">
+        <el-image v-if="publicData && publicData.home_logo" :src="publicData.home_logo" fit="contain" @click.native="goPage('home')"></el-image>
+        <div class="search">
+            <el-input v-model.trim="searchValue" placeholder="请输入搜索内容">
+                <el-select v-model="selected" slot="prepend">
+                    <el-option v-for="option in options" :key="option.value" :label="option.label" :value="option.value"></el-option>
+                </el-select>
+                <el-button slot="append" @click="onSearch('')">搜索</el-button>
+            </el-input>
+            <el-button-group v-if="publicData">
+                <el-button v-for="(item, index) in publicData.host_search" :key="index" type="text" @click="onSearch(item)">{{ item }}</el-button>
+            </el-button-group>
+        </div>
+    </div>
+    <div v-if="publicData && publicData.grade_cate" class="nav-wrapper" :hidden="pageName === 'user' || pageName === 'question_index' || pageName === 'problem_index'">
+        <div class="category" @mouseenter="categoryMouseenter" @mouseleave="categoryMouseleave">
+            <el-button>课程分类</el-button>
+            <div :class="{ on: categoryVisible }" class="wrapper">
+                <div class="menu" @mouseenter="menuMouseenter" @mouseleave="menuMouseleave">
+                    <el-button v-for="(item, index) in publicData.grade_cate" :key="item.id" :class="{ on: menuOn === index }" type="text" @mouseenter.native="menuOn = index">
+                        {{ item.name }}<i class="el-icon-arrow-right el-icon--right"></i></el-button>
+                </div>
+                <div class="content" @mouseenter="contentMouseenter" @mouseleave="contentMouseleave">
+                    <div v-for="(item, index) in publicData.grade_cate" v-show="menuOn === index" :key="item.id">
+                        <div v-if="item.children.length" class="wrap">
+                            <div class="title">{{ item.name }}</div>
+                            <div>
+                                <el-link v-for="children in item.children" :key="children.id"
+                                         :href="$router.special_cate + '?cate_id=' + children.grade_id + '&subject_id=' + children.id" :underline="false">{{
+                                    children.name }}
+                                </el-link>
+                            </div>
+                        </div>
+                        <div v-if="item.list.length" class="wrap special">
+                            <div class="title">推荐课程</div>
+                            <div>
+                                <a v-for="(special, index) in item.list" v-if="index < 3" :key="special.id"
+                                   :href="(special.is_light ? $router.single_detail : $router.special_detail) + '?id=' + special.id">
+                                    <el-image :src="special.image" fit="cover"></el-image>
+                                    <div>
+                                        <div>
+                                            <div>{{ special.title }}</div>
+                                            <div>¥<span>{{ special.money }}</span></div>
+                                        </div>
+                                        <div>{{ special.browse_count }}人已学习</div>
+                                    </div>
+                                </a>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <el-link v-for="item in publicData.navList" :key="item.id"
+                 :class="{ on: item.link == currentURL || (currentURL.indexOf('question_category') != -1 && item.link.indexOf(URLSearch) != -1) }" :href="item.link"
+                 :underline="false">
+            {{ item.title }}</el-link>
+    </div>
+    <!-- 讲师申请状态弹窗 -->
+    <el-dialog :visible="applyVisible" :close-on-click-modal="false" :close-on-press-escape="false" :show-close="false" width="370px" custom-class="apply-dialog" center>
+        <el-image :src="applyStatus ? (applyStatus === 1 ? applyStatusIcon[0] : applyStatusIcon[2]) : applyStatusIcon[1]" style="width: 190px;">
+        </el-image>
+        <div class="title">{{ applyStatus ? (applyStatus === 1 ? '审核成功' : '审核失败') : '等待审核' }}</div>
+        <div v-if="applyStatus !== 1" class="message">{{ failMessage || '您的申请工作人员正在审核,稍后再试' }}</div>
+        <span slot="footer">
+            <el-button @click="applyVisible = false">关闭</el-button>
+            <el-button type="primary" @click="goApply">{{ applyStatus === -1 ? '继续' : '查看' }}</el-button>
+        </span>
+    </el-dialog>
+</div>

+ 204 - 0
public/pc/components/base-header/index.js

xqd
@@ -0,0 +1,204 @@
+define([
+    'require',
+    'store/index',
+    'api/merchant',
+    'scripts/util',
+    'text!./index.html',
+    'css!./index.css'
+], function (require, store, merchantApi, util, html) {
+    return {
+        props: {
+            publicData: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            },
+            userInfo: {
+                type: Object,
+                default: function () {
+                    return {
+                        avatar: ''
+                    };
+                }
+            }
+        },
+        data: function () {
+            return {
+                selected: 1,
+                options: [
+                    {
+                        label: '专题',
+                        value: 1
+                    },
+                    {
+                        label: '资料',
+                        value: 2
+                    }
+                ],
+                searchValue: '',
+                activeIndex: '1',
+                active: 1,
+                currentURL: window.location.pathname,
+                URLSearch: window.location.search,
+                categoryVisible: false,
+                menuOn: -1,
+                pageName: false,
+                code_url: code_url,
+                sharedState: store.state,
+                applyStatus: null,
+                applyVisible: false,
+                failMessage: '',
+                applyStatusIcon: [
+                    require.toUrl('./images/1.png'),
+                    require.toUrl('./images/2.png'),
+                    require.toUrl('./images/2.png')
+                ]
+            };
+        },
+        created: function () {
+            for (var key in this.$router) {
+                if (Object.hasOwnProperty.call(this.$router, key)) {
+                    if (this.$router[key].indexOf(this.currentURL) !== -1) {
+                        this.pageName = key;
+                    }
+                }
+            }
+            if (['material_list', 'material_detail', 'special_cate'].indexOf(this.pageName) !== -1) {
+                this.setSearchValue();
+            }
+            if (['material_list', 'material_detail'].indexOf(this.pageName) !== -1) {
+                this.selected = 2;
+            }
+            if (code_url) {
+                this.code_url = code_url;
+            }
+        },
+        methods: {
+            goPage: function (page) {
+                var vm = this;
+                var params = '';
+                // 判断路由结构
+                if (Array.isArray(page)) {
+                    if (page[1].constructor.toString().indexOf('Object') !== -1) {
+                        params = Object.keys(page[1]).map(function (key) {
+                            return key + '=' + page[1][key];
+                        }).join('&');
+                    }
+                    page = page[0];
+                }
+                // 判断是否登录
+                if (page !== 'home' && (!this.userInfo || !this.userInfo.uid)) {
+                    return store.setLoginAction(true);
+                }
+                // 讲师申请状态
+                if (page === 'teacher_apply') {
+                    if (this.userInfo && this.userInfo.business) {
+                        window.open('/merchant/index.html');
+                        return false;
+                    }
+                    merchantApi.is_apply().then(function (res) {
+                        if (res.data == null) {
+                            window.location.assign(vm.$router[page] + (params ? '?' + params : ''));
+                        } else {
+                            if (res.data.status === null) {
+                                window.location.assign(vm.$router[page] + (params ? '?' + params : ''));
+                            } else {
+                                if (res.data.status === 2) {
+                                    window.location.assign(vm.$router[page] + (params ? '?' + params : ''));
+                                } else {
+                                    vm.applyStatus = res.data.status;
+                                    vm.applyVisible = true;
+                                    if (res.data.status === -1) {
+                                        vm.failMessage = res.data.fail_message;
+                                    }
+                                }
+                            }
+                        }
+                    });
+                    return false;
+                }
+                window.location.assign(this.$router[page] + (params ? '?' + params : ''));
+            },
+            onSearch: function (hot) {
+                if (!hot && !this.searchValue) {
+                    return;
+                }
+                if (hot) {
+                    this.searchValue = hot;
+                }
+                if (this.currentURL.includes('/web/special/special_cate')) {
+                    if (this.selected === 1) {
+                        this.$emit('submit-search', this.searchValue);
+                    } else {
+                        window.location.assign(this.$router.material_list + '?search=' + this.searchValue);
+                    }
+                } else if (this.currentURL.includes('/web/material/material_list')) {
+                    if (this.selected === 2) {
+                        this.$emit('submit-search', this.searchValue);
+                    } else {
+                        window.location.assign(this.$router.special_cate + '?search=' + this.searchValue);
+                    }
+                } else {
+                    window.location.assign((this.selected === 1 ? this.$router.special_cate : this.$router.material_list) + '?search=' + this.searchValue);
+                }
+            },
+            categoryMouseenter: function () {
+                this.categoryMouse = true;
+                this.categoryVisible = true;
+            },
+            categoryMouseleave: function () {
+                this.categoryMouse = false;
+                if (!(this.contentMouse || this.menuMouse)) {
+                    this.menuOn = -1;
+                    this.categoryVisible = false;
+                }
+            },
+            menuMouseenter: function () {
+                this.menuMouse = true;
+            },
+            menuMouseleave: function () {
+                this.menuMouse = false;
+                if (!(this.contentMouse || this.categoryMouse)) {
+                    this.menuOn = -1;
+                    this.categoryVisible = false;
+                }
+            },
+            contentMouseenter: function () {
+                this.contentMouse = true;
+            },
+            contentMouseleave: function () {
+                this.contentMouse = false;
+                if (!(this.menuMouse || this.categoryMouse)) {
+                    this.menuOn = -1;
+                    this.categoryVisible = false;
+                }
+            },
+            setSearchValue: function () {
+                var search = util.getParmas('search');
+                if (search) {
+                    this.searchValue = search;
+                }
+            },
+            // 收藏本站
+            addFavorite: function () {
+                try {
+                    window.external.addFavorite(window.location.origin + this.$router.home, this.publicData.site_name);
+                } catch (error) {
+                    try {
+                        window.sidebar.addPanel(this.publicData.site_name, window.location.origin + this.$router.home, '');
+                    } catch (error) {
+                        this.$message('抱歉,您所使用的浏览器无法完成此操作,请使用Ctrl+D进行添加!');
+                    }
+                }
+            },
+            loginOpen: function () {
+                store.setLoginAction(true);
+            },
+            goApply: function () {
+                window.location.assign(this.$router.teacher_apply);
+            }
+        },
+        template: html
+    };
+});

+ 41 - 0
public/pc/components/base-lecturer/index.css

xqd
@@ -0,0 +1,41 @@
+.base-lecturer {
+    display: block;
+    padding: 30px 30px 37px;
+    background-color: #FFFFFF;
+}
+
+.base-lecturer .lecturer-main {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+}
+
+.base-lecturer img {
+    width: 80px;
+    height: 80px;
+    border-radius: 50%;
+    vertical-align: middle;
+}
+
+.base-lecturer .name-tags {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    padding-left: 20px;
+}
+
+.base-lecturer .lecturer-name {
+    font-weight: bold;
+    font-size: 18px;
+    line-height: 24px;
+    color: #333333;
+}

+ 10 - 0
public/pc/components/base-lecturer/index.html

xqd
@@ -0,0 +1,10 @@
+<a class="base-lecturer" href="">
+    <div class="lecturer-main">
+        <div><img src="" alt=""></div>
+        <div class="name-tags">
+            <div class="lecturer-name"></div>
+            <div class="lecturer-tags"><span class="tag"></span></div>
+        </div>
+    </div>
+    <div class="lecturer-footer"></div>
+</a>

+ 11 - 0
public/pc/components/base-lecturer/index.js

xqd
@@ -0,0 +1,11 @@
+define([
+    'require',
+    'text!./index.html',
+    'css!./index.css'
+], function(require, html) {
+    return {
+        props: {},
+        methods: {},
+        template: html
+    };
+});

+ 322 - 0
public/pc/components/base-login/index.css

xqd
@@ -0,0 +1,322 @@
+.login-dialog .el-dialog__header {
+    padding: 0;
+}
+
+.login-dialog .el-dialog__body {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    height: 460px;
+    padding: 0;
+}
+
+.login-dialog .el-image {
+    width: 355px;
+    border-top-left-radius: 8px;
+    border-bottom-left-radius: 8px;
+    background-color: #2c8eff;
+}
+
+.login-dialog .el-form {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+       -moz-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    position: relative;
+}
+
+.login-dialog .el-form-item {
+    margin-bottom: 20px;
+}
+
+.login-dialog .el-radio-button__inner {
+    padding-right: 35px;
+    padding-left: 35px;
+    border: none;
+    font-size: 20px;
+    color: #282828;
+}
+
+.login-dialog .el-radio-button:first-child .el-radio-button__inner {
+    border-left: none;
+}
+
+.login-dialog .el-radio-button__orig-radio:checked+.el-radio-button__inner {
+    background: none;
+    -webkit-box-shadow: none;
+            box-shadow: none;
+    color: #2c8eff;
+}
+
+.login-dialog .el-form-item:first-child .el-form-item__content, .login-dialog .el-form-item:nth-child(2) .el-form-item__content {
+    font-size: 20px;
+    color: #282828;
+}
+
+.login-dialog .el-form-item:nth-child(4), .login-dialog .el-form-item:nth-child(5), .login-dialog .el-form-item:nth-child(6), .login-dialog .el-form-item:nth-child(7), .login-dialog .el-form-item:nth-child(8), .login-dialog .el-form-item:nth-child(9), .login-dialog .el-form-item:nth-child(10), .login-dialog .el-form-item:nth-child(11) {
+    width: 358px;
+}
+
+.login-dialog .el-input__inner {
+    height: 50px;
+    border-radius: 25px;
+    line-height: 50px;
+}
+
+.login-dialog .el-form-item:nth-child(5) .el-input__inner {
+    border-top-right-radius: 0;
+    border-bottom-right-radius: 0;
+}
+
+.login-dialog .el-form-item:nth-child(5) .el-input-group__append {
+    border-color: #dbdbdb;
+    border-top-right-radius: 25px;
+    border-bottom-right-radius: 25px;
+    background-color: transparent;
+}
+
+.login-dialog .el-form-item:nth-child(5) .el-button {
+    width: 112px;
+    padding: 17px 0;
+    border-top-right-radius: 24px;
+    border-bottom-right-radius: 24px;
+    color: #2c8eff;
+}
+
+.login-dialog .el-button.is-disabled, .login-dialog .el-button.is-disabled:focus, .login-dialog .el-button.is-disabled:hover {
+    color: #ccc;
+}
+
+.login-dialog .el-form-item:nth-child(6) .el-input__inner {
+    padding-right: 90px;
+}
+
+.login-dialog .el-form-item:nth-child(6) .el-input-group__append {
+    position: absolute;
+    top: 50%;
+    right: 0;
+    z-index: 2;
+    width: 90px;
+    border: 0;
+    background-color: transparent;
+    -webkit-transform: translateY(-50%);
+       -moz-transform: translateY(-50%);
+        -ms-transform: translateY(-50%);
+         -o-transform: translateY(-50%);
+            transform: translateY(-50%);
+}
+
+.login-dialog .el-form-item:nth-child(6) .el-button {
+    font-size: 12px;
+    color: #999;
+}
+
+.login-dialog .el-form-item:nth-child(9) .el-form-item__content, .login-dialog .el-form-item:nth-child(10) .el-form-item__content, .login-dialog .el-form-item:nth-child(12) .el-form-item__content, .login-dialog .el-form-item:nth-child(13) .el-form-item__content, .login-dialog .el-form-item:nth-child(14) .el-form-item__content {
+    line-height: normal;
+}
+
+.login-dialog .el-checkbox__inner {
+    border-radius: 50%;
+}
+
+.login-dialog .el-checkbox__label {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    font-size: 12px;
+    color: #666;
+}
+
+.login-dialog .el-form-item:nth-child(9) .el-checkbox {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+}
+
+.login-dialog .el-form-item:nth-child(9) .el-checkbox .el-button--text {
+    padding-top: 0;
+    padding-bottom: 0;
+    white-space: pre-line;
+    text-align: left;
+    font-size: 12px;
+    line-height: normal;
+    color: #ff6b00;
+}
+
+.login-dialog .el-form-item:nth-child(9) .el-form-item__content > .el-button--text {
+    padding-top: 0;
+    padding-bottom: 0;
+    font-size: 12px;
+    color: #999;
+}
+
+.login-dialog .el-form-item:nth-child(10) .el-button {
+    width: 100%;
+    padding-top: 18px;
+    padding-bottom: 18px;
+    border: none;
+    border-radius: 25px;
+    background: -webkit-gradient(linear, left top, right top, from(#409dff), to(#1e85fb));
+    background: -webkit-linear-gradient(left, #409dff 0%, #1e85fb 100%);
+    background: -moz-linear-gradient(left, #409dff 0%, #1e85fb 100%);
+    background: -o-linear-gradient(left, #409dff 0%, #1e85fb 100%);
+    background: linear-gradient(90deg, #409dff 0%, #1e85fb 100%);
+    color: #fff;
+}
+
+.login-dialog .el-form-item:nth-child(10) .el-button+.el-button {
+    margin-left: 0;
+}
+
+.login-dialog .el-form-item:nth-child(11) .el-form-item__content {
+    text-align: center;
+}
+
+.login-dialog .el-form-item:nth-child(11) .el-form-item__content, .login-dialog .el-form-item:nth-child(13) .el-form-item__content {
+    color: #ccc;
+}
+
+.login-dialog .el-form-item:nth-child(11) .el-button--text, .login-dialog .el-form-item:nth-child(12) .el-button--text, .login-dialog .el-form-item:nth-child(13) .el-button--text {
+    padding-top: 0;
+    padding-bottom: 0;
+    color: #2c8eff;
+}
+
+.login-dialog .el-form-item:nth-child(11), .login-dialog .el-form-item:nth-child(12), .login-dialog .el-form-item:nth-child(13) {
+    margin-bottom: 0;
+}
+
+.login-dialog .el-form-item:nth-child(14) {
+    margin-bottom: 44px;
+}
+
+.login-dialog .el-form-item:nth-child(14) .el-form-item__content {
+    font-size: 20px;
+    line-height: 26px;
+    color: #282828;
+}
+
+.login-dialog .el-form-item.qrcode .el-image {
+    width: 190px;
+    height: 190px;
+    border-radius: 0;
+    vertical-align: middle;
+}
+
+.login-dialog .el-form-item.qrcode .el-form-item__content > div:first-child {
+    position: relative;
+    width: 209px;
+    height: 209px;
+    line-height: 209px;
+    text-align: center;
+}
+
+.login-dialog .el-form-item.qrcode .el-form-item__content > div:last-child {
+    margin-top: 20px;
+    font-size: 14px;
+    line-height: 19px;
+    text-align: center;
+    color: #666666;
+}
+
+.login-dialog .el-form-item.qrcode .el-form-item__content > div:first-child > div:first-child {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 22px;
+    height: 22px;
+    border-width: 2px;
+    border-style: solid;
+    border-color: #CBCBCB transparent transparent #CBCBCB;
+}
+
+.login-dialog .el-form-item.qrcode .el-form-item__content > div:first-child > div:nth-child(2) {
+    position: absolute;
+    top: 0;
+    right: 0;
+    width: 22px;
+    height: 22px;
+    border-width: 2px;
+    border-style: solid;
+    border-color: #CBCBCB #CBCBCB transparent transparent;
+}
+
+.login-dialog .el-form-item.qrcode .el-form-item__content > div:first-child > div:nth-child(3) {
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    width: 22px;
+    height: 22px;
+    border-width: 2px;
+    border-style: solid;
+    border-color: transparent #CBCBCB #CBCBCB transparent;
+}
+
+.login-dialog .el-form-item.qrcode .el-form-item__content > div:first-child > div:nth-child(4) {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    width: 22px;
+    height: 22px;
+    border-width: 2px;
+    border-style: solid;
+    border-color: transparent transparent #CBCBCB #CBCBCB;
+}
+
+.login-dialog .el-dialog__headerbtn {
+    top: -50px;
+    right: -70px;
+    font-size: 40px;
+}
+
+.login-dialog .el-dialog__headerbtn .el-dialog__close {
+    color: #ddd;
+}
+
+.login-dialog .method-btn {
+    position: absolute;
+    top: 0;
+    right: 0;
+    width: 68px;
+    height: 68px;
+    background: url("../../images/login1.png") left top/100% 100% no-repeat;
+    cursor: pointer;
+}
+
+.login-dialog .method-btn.qrcode-btn {
+    background-image: url("../../images/login2.png");
+}

+ 61 - 0
public/pc/components/base-login/index.html

xqd
@@ -0,0 +1,61 @@
+<el-dialog :visible="sharedState.loginVisible" width="825px" custom-class="login-dialog" @close="loginClose">
+    <el-image v-if="publicData" :src="publicData.pc_login_diagram" fit="cover"></el-image>
+    <el-form>
+        <el-form-item v-show="state === 1 && type != 3">注册账号</el-form-item>
+        <el-form-item v-show="state === 2 && type != 3">找回密码</el-form-item>
+        <el-form-item v-show="state === 3 && type != 3">
+            <el-radio-group v-model="type">
+                <el-radio-button :label="1">账号登录</el-radio-button>
+                <el-radio-button :label="2">快速登录</el-radio-button>
+            </el-radio-group>
+        </el-form-item>
+        <el-form-item v-show="type != 3">
+            <el-input v-model.trim="phone" placeholder="请输入手机号" clearable></el-input>
+        </el-form-item>
+        <el-form-item v-show="(state !== 3 && type != 3) || type === 2">
+            <el-input v-model.trim="code" placeholder="请输入验证码" maxlength="6" minlength="6" clearable>
+                <el-button slot="append" :disabled="count >= 0" @click="getCode">{{ count < 0 ? '获取验证码' : '重新获取(' + count + 's)' }}</el-button>
+            </el-input>
+        </el-form-item>
+        <el-form-item v-show="state === 3 && type === 1">
+            <el-input v-model.trim="pwd" placeholder="请输入密码" maxlength="16" minlength="8" show-password>
+                <el-button slot="append" @click="state = 2">忘记密码</el-button>
+            </el-input>
+        </el-form-item>
+        <el-form-item v-show="state === 1 && type != 3">
+            <el-input v-model.trim="pwd" placeholder="请输入8-16位字母加数字组合密码" maxlength="16" minlength="8" show-password></el-input>
+        </el-form-item>
+        <el-form-item v-show="state === 2 && type != 3">
+            <el-input v-model.trim="pwd" placeholder="请输入8-16位字母加数字组合新密码" maxlength="16" minlength="8" show-password></el-input>
+        </el-form-item>
+        <el-form-item v-show="state !== 2 && type != 3">
+            <el-checkbox v-model="agree">我已阅读并同意<el-button type="text" @click="agreeOpen">《{{ agreeContent && agreeContent.title }}》</el-button></el-checkbox>
+        </el-form-item>
+        <el-form-item v-show="type != 3">
+            <el-button v-show="state === 1" @click="register">注册</el-button>
+            <el-button v-show="state === 2" @click="register">确认</el-button>
+            <el-button v-show="state === 3" @click="login">登录</el-button>
+        </el-form-item>
+        <el-form-item v-show="state === 1 && type != 3">
+            已有账号?<el-button type="text" @click="state = 3">立即登录</el-button>
+        </el-form-item>
+        <el-form-item v-show="state === 2 && type != 3">
+            <el-button type="text" @click="state = 3">立即登录</el-button>
+        </el-form-item>
+        <el-form-item v-show="state === 3 && type != 3">
+            没有账号?<el-button type="text" @click="state = 1">立即注册</el-button>
+        </el-form-item>
+        <el-form-item v-show="type == 3">扫码登录</el-form-item>
+        <el-form-item v-show="type == 3" class="qrcode">
+            <div>
+                <div></div>
+                <div></div>
+                <div></div>
+                <div></div>
+                <el-image :src="qrcodeSrc"></el-image>
+            </div>
+            <div>请使用微信扫一扫登录</div>
+        </el-form-item>
+        <div v-show="state == 3" :class="{ 'qrcode-btn': type == 3 }" class="method-btn" @click="type = type == 3 ? 1 : 3"></div>
+    </el-form>
+</el-dialog>

+ 252 - 0
public/pc/components/base-login/index.js

xqd
@@ -0,0 +1,252 @@
+define([
+    'store/index',
+    'api/auth',
+    'api/login',
+    'plugins/blueimp-md5/js/md5',
+    'text!./index.html',
+    'css!./index.css'
+], function (store, authApi, loginApi, md5, html) {
+    return {
+        inject: ['getUserInfo'],
+        props: {
+            publicData: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            },
+            agreeContent: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            }
+        },
+        data: function () {
+            return {
+                state: 3, // 1 注册,2 找回密码,3 登录
+                type: 1,  // 1 账号登录,2 快速登录,3 扫码登录
+                phone: '',
+                code: '',
+                pwd: '',
+                agree: false,
+                count: -1,
+                TIME_COUNT: 60,
+                scanCount: 0,
+                scanTimer: null,
+                qrcodeSrc: '',
+                sharedState: store.state
+            };
+        },
+        watch: {
+            state: function () {
+                this.phone = '';
+                this.code = '';
+                this.pwd = '';
+                this.agree = false;
+                if (this.timer) {
+                    clearInterval(this.timer);
+                    this.timer = null;
+                    this.count = -1;
+                }
+            },
+            type: function (val) {
+                var vm = this;
+                if (val == 3) {
+                    loginApi.loginQrcode().catch(function (res) {
+                        vm.qrcodeSrc = res.url;
+                        vm.setScanLogin(res);
+                    });
+                } else {
+                    if (this.scanTimer) {
+                        clearInterval(this.scanTimer);
+                        this.scanTimer = null;
+                    }
+                }
+            },
+            loginVisible: function (val) {
+                if (val) {
+                    this.state = 3;
+                    this.type = 1;
+                } else {
+                    if (this.scanTimer) {
+                        clearInterval(this.scanTimer);
+                        this.scanTimer = null;
+                    }
+                }
+            }
+        },
+        created: function () {
+            var vm = this;
+            window.addEventListener('keydown', function (event) {
+                if (event.key == 'Enter' && vm.loginVisible) {
+                    vm.login();
+                }
+            });
+        },
+        methods: {
+            // 获取验证码
+            getCode: function () {
+                var vm = this;
+                if (!this.phone) {
+                    return this.$message.warning('请输入手机号');
+                }
+                if (!/^1[3456789]\d{9}$/.test(this.phone)) {
+                    return this.$message.warning('手机号错误');
+                }
+                this.count = this.TIME_COUNT;
+                this.timer = setInterval(function () {
+                    vm.count--;
+                    if (vm.count < 0) {
+                        clearInterval(vm.timer);
+                        vm.timer = null;
+                    }
+                }, 1000);
+                authApi.code({
+                    phone: this.phone
+                }).then(function (res) {
+                    vm.$message.success(res.msg);
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                    clearInterval(vm.timer);
+                    vm.timer = null;
+                    vm.count = -1;
+                });
+            },
+            // 登录
+            login: function () {
+                this.type === 1 ? this.pwdLogin() : this.smsLogin();
+            },
+            // 短信登录、注册
+            smsLogin: function () {
+                var vm = this;
+                if (!this.phone) {
+                    return this.$message.warning('请输入手机号');
+                }
+                if (!/^1[3456789]\d{9}$/.test(this.phone)) {
+                    return this.$message.warning('手机号错误');
+                }
+                if (!this.code) {
+                    return this.$message.warning('请输入验证码');
+                }
+                if (!/^\d{6}$/.test(this.code)) {
+                    return this.$message.warning('验证码错误');
+                }
+                if (!this.agree) {
+                    return this.$message.warning('请勾选用户协议');
+                }
+                if (this.timer) {
+                    clearInterval(this.timer);
+                    this.timer = null;
+                }
+                loginApi.phoneCheck({
+                    phone: this.phone,
+                    code: this.code
+                }).then(function (res) {
+                    vm.$message.success(res.msg);
+                    vm.loginClose();
+                    vm.getUserInfo();
+                    vm.phone = '';
+                    vm.code = '';
+                    vm.count = -1;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                    vm.count = -1;
+                });
+            },
+            // 账号密码登录
+            pwdLogin: function () {
+                var vm = this;
+                if (!this.phone) {
+                    return this.$message.warning('请输入手机号');
+                }
+                if (!/^1[3456789]\d{9}$/.test(this.phone)) {
+                    return this.$message.warning('手机号错误');
+                }
+                if (!this.pwd) {
+                    return this.$message.warning('请输入密码');
+                }
+                if (!this.agree) {
+                    return this.$message.warning('请勾选用户协议');
+                }
+                loginApi.heck({
+                    account: this.phone,
+                    pwd: md5(this.pwd)
+                }).then(function (res) {
+                    vm.$message.success(res.msg);
+                    vm.loginClose();
+                    vm.getUserInfo();
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            // 账号注册、找回密码
+            register: function () {
+                var vm = this;
+                if (!this.phone) {
+                    return this.$message.warning('请输入手机号');
+                }
+                if (!/^1[3456789]\d{9}$/.test(this.phone)) {
+                    return this.$message.warning('手机号错误');
+                }
+                if (!this.code) {
+                    return this.$message.warning('请输入验证码');
+                }
+                if (!/^\d{6}$/.test(this.code)) {
+                    return this.$message.warning('验证码错误');
+                }
+                if (!this.pwd) {
+                    return this.$message.warning('请输入密码');
+                }
+                if (!/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$/.test(this.pwd)) {
+                    return this.$message.warning('请输入8-16位字母加数字组合密码');
+                }
+                if (this.state === 1 && !this.agree) {
+                    return this.$message.warning('请勾选用户协议');
+                }
+                if (this.timer) {
+                    clearInterval(this.timer);
+                    this.timer = null;
+                }
+                loginApi.register({
+                    account: this.phone,
+                    pwd: md5(this.pwd),
+                    code: this.code,
+                    type: this.state
+                }).then(function (res) {
+                    vm.$message.success(res.msg);
+                    vm.phone = '';
+                    vm.pwd = '';
+                    vm.code = '';
+                    vm.state = 3;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                    vm.count = -1;
+                });
+            },
+            setScanLogin: function (data) {
+                var vm = this;
+                this.scanTimer = setInterval(function () {
+                    if (vm.scanCount < 40) {
+                        vm.scanCount++;
+                        loginApi.setScanLogin(data).then(function () {
+                            clearInterval(vm.scanTimer);
+                            vm.scanTimer = null;
+                            window.location.reload();
+                        });
+                    } else {
+                        clearInterval(vm.scanTimer);
+                        vm.scanTimer = null;
+                    }
+                }, 3000);
+            },
+            loginClose: function () {
+                store.setLoginAction(false);
+            },
+            agreeOpen: function () {
+                store.setAgreeAction(true);
+            }
+        },
+        template: html
+    };
+});

+ 30 - 0
public/pc/components/base_agree/index.css

xqd
@@ -0,0 +1,30 @@
+.agree-dialog .el-dialog__header {
+    padding-bottom: 5px;
+}
+
+.agree-dialog .el-dialog__title {
+    font-weight: bold;
+    font-size: 20px;
+    color: #333;
+}
+
+.agree-dialog.el-dialog--center .el-dialog__body {
+    max-height: 400px;
+    padding-right: 30px;
+    padding-bottom: 10px;
+    padding-left: 30px;
+    overflow: auto;
+}
+
+.agree-dialog .el-dialog__footer {
+    padding-bottom: 30px;
+}
+
+.agree-dialog .el-button {
+    padding: 14px 73px;
+    border-color: #2c8eff;
+    border-radius: 23px;
+    background-color: #2c8eff;
+    font-size: 16px;
+    color: #fff;
+}

+ 7 - 0
public/pc/components/base_agree/index.html

xqd
@@ -0,0 +1,7 @@
+<el-dialog :title="agreeContent.title" :visible="agreeVisible" width="900px" center custom-class="agree-dialog" @close="$emit('agree-close')">
+    <span v-if="agreeContent.content" v-html="agreeContent.content"></span>
+    <el-empty v-else description="暂无内容"></el-empty>
+    <span slot="footer" class="dialog-footer">
+        <el-button @click="$emit('agree-close')">确定</el-button>
+    </span>
+</el-dialog>

+ 20 - 0
public/pc/components/base_agree/index.js

xqd
@@ -0,0 +1,20 @@
+define([
+    'text!components/base_agree/index.html',
+    'css!components/base_agree/index.css'
+], function(html) {
+    return {
+        props: {
+            agreeVisible: {
+                type: Boolean,
+                default: false
+            },
+            agreeContent: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            }
+        },
+        template: html
+    };
+});

+ 200 - 0
public/pc/components/base_footer/index.css

xqd
@@ -0,0 +1,200 @@
+.base-footer {
+    background-color: #f2f2f2;
+}
+
+.base-footer .el-row {
+    width: 1200px;
+    margin: 0 auto;
+}
+
+.base-footer .el-row:first-child {
+    padding-top: 32px;
+    padding-bottom: 32px;
+    font-size: 16px;
+    text-align: center;
+    color: #666;
+}
+
+.base-footer .el-col-6 > div {
+    display: -webkit-inline-box;
+    display: -webkit-inline-flex;
+    display: -moz-inline-box;
+    display: -ms-inline-flexbox;
+    display: inline-flex;
+}
+
+.base-footer .el-image {
+    width: 38px;
+    height: 38px;
+    margin: 0 10px 0 0;
+    vertical-align: middle;
+}
+
+.base-footer .el-row:last-child {
+    padding-top: 30px;
+    padding-bottom: 48px;
+    border-top: 1px solid #e2e2e2;
+    font-size: 14px;
+    line-height: 22px;
+    text-align: center;
+    color: #999;
+}
+
+.base-footer .footer span {
+    display: inline-block;
+}
+
+.base-footer .address {
+    margin-left: 40px;
+}
+
+.base-footer .footer .el-image + span {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    min-width: 0;
+    padding: 12px 0 0;
+    margin: 0;
+    text-align: left;
+}
+
+.base-footer .el-link {
+    font-weight: normal;
+    color: #999;
+}
+
+.base-footer .sidebar {
+    position: fixed;
+    right: 40px;
+    bottom: 50%;
+    z-index: 99;
+    transform: translateY(50%);
+}
+
+.base-footer .sidebar .button-group {
+    -webkit-box-shadow: 0 3px 20px rgba(91, 126, 165, 0.15);
+            box-shadow: 0 3px 20px rgba(91, 126, 165, 0.15);
+}
+
+.base-footer .el-button {
+    position: relative;
+    display: block;
+    width: 64px;
+    height: 90px;
+    padding: 0;
+    border: 0;
+    border-radius: 0;
+    line-height: 18px;
+    color: #666666;
+}
+
+.base-footer .el-button:hover {
+    color: #2c8eff;
+}
+
+.base-footer > .el-button::after {
+    content: "";
+    position: absolute;
+    right: 12px;
+    bottom: 0;
+    left: 12px;
+    z-index: 2;
+    height: 1px;
+    background-color: #f0f0f0;
+}
+
+.base-footer > .el-button:last-child::after {
+    display: none;
+}
+
+.base-footer .service-button span {
+    display: block;
+    padding-top: 34px;
+    background: url("../../images/service1.png") top center/28px 28px no-repeat;
+}
+
+.base-footer .service-button:hover span {
+    background-image: url("../../images/service2.png");
+}
+
+.phone-popover {
+    padding: 0;
+    border-color: #2C8EFF;
+}
+
+.phone-popover .content {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+       -moz-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    height: 74px;
+    padding: 0 21px 0 53px;
+    background: url("../../images/phone2.png") 29px center/24px 24px no-repeat;
+    font-size: 14px;
+    line-height: 19px;
+    text-align: center;
+    color: #2C8EFF;
+}
+
+.phone-popover .content div:last-child {
+    margin-top: 3px;
+}
+
+.phone-popover-reference span {
+    display: block;
+    padding-top: 34px;
+    background: url("../../images/phone1.png") top center/28px 28px no-repeat;
+}
+
+.phone-popover-reference:hover span {
+    background-image: url("../../images/phone2.png");
+}
+
+.el-popover.phone-popover .popper__arrow {
+    border-left-color: #2C8EFF;
+}
+
+.base-footer .el-backtop {
+    width: 64px;
+    height: 30px;
+    border-radius: 0;
+    font-size: 18px;
+    color: #999;
+}
+
+.subscribe-popover {
+    min-width: 0;
+    padding: 0;
+    border: 0;
+}
+
+.subscribe-popover img {
+    display: block;
+    width: 110px;
+    height: 110px;
+    margin: 15px auto;
+}
+
+.subscribe-popover img + div {
+    border-radius: 0 0 4px 4px;
+    background-color: #2C8EFF;
+    font-size: 12px;
+    line-height: 26px;
+    text-align: center;
+    color: #FFFFFF;
+}

+ 49 - 0
public/pc/components/base_footer/index.html

xqd
@@ -0,0 +1,49 @@
+<div class="base-footer">
+    <div class="footer">
+        <el-row v-if="publicData.pc_end_bottom_display && publicData.pc_end_bottom_display.length">
+            <el-col v-for="item in publicData.pc_end_bottom_display" :key="item.id" :span="6">
+                <div>
+                    <el-image :src="item.pic" fit="cover"></el-image><span>{{ item.title }}</span>
+                </div>
+            </el-col>
+        </el-row>
+        <el-row>
+            <el-col v-if="publicData.site_phone || publicData.company_address" :span="24">
+                <span v-if="publicData.site_phone">联系电话:{{ publicData.site_phone }}</span>
+                <span v-if="publicData.company_address" class="address">地址:{{ publicData.company_address }}</span>
+            </el-col>
+            <el-col v-if="publicData.full_name_the_company || publicData.keep_on_record" :span="24">
+                <span v-if="publicData.full_name_the_company">Copyright © {{ publicData.full_name_the_company }}</span>
+                <el-link v-if="publicData.keep_on_record" :underline="false" href="https://beian.miit.gov.cn/#/Integrated/index" target="_blank">{{ publicData.keep_on_record }}</el-link>
+            </el-col>
+        </el-row>
+    </div>
+    <div ref="sidebar" class="sidebar">
+        <div class="button-group">
+                <el-button v-if="publicData.service_url" class="service-button" @click="goPage">
+                咨询<br>客服
+            </el-button>
+                <el-popover v-if="publicData.site_service_phone" trigger="hover" width="200" placement="left" popper-class="phone-popover" effect="light">
+                <div class="content">
+                    <div>服务热线</div>
+                    <div>{{ publicData.site_service_phone }}</div>
+                </div>
+                <el-button slot="reference" class="phone-popover-reference">
+                    服务<br>热线
+                </el-button>
+            </el-popover>
+            <el-popover v-if="code_url" trigger="hover" width="140" placement="left" popper-class="subscribe-popover">
+                <div class="content">
+                    <img :src="code_url" alt="公众号">
+                    <div>扫码关注公众号</div>
+                </div>
+                <el-button slot="reference">
+                    关注<br>公众号
+                </el-button>
+            </el-popover>
+        </div>
+        <el-backtop :style="{top: 'calc(50% + '+(sidebarHeight/2)+'px)', bottom: 'auto', right: 'auto'}">
+            <i class="el-icon-arrow-up"></i>
+        </el-backtop>
+    </div>
+</div>

+ 42 - 0
public/pc/components/base_footer/index.js

xqd
@@ -0,0 +1,42 @@
+define([
+    'text!components/base_footer/index.html',
+    'css!components/base_footer/index.css'
+], function (html) {
+    return {
+        props: {
+            publicData: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            }
+        },
+        data: function () {
+            return {
+                year: new Date().getFullYear(),
+                code_url: '',
+                sidebarHeight: 0
+            };
+        },
+        mounted: function () {
+            this.$nextTick(function () {
+                if (code_url) {
+                    this.code_url = code_url;
+                }
+                // this.$emit('action', this.$refs.sidebar.clientHeight);
+            });               
+        },
+        updated: function () {
+            this.$nextTick(function () {
+                this.sidebarHeight = this.$refs.sidebar.clientHeight;
+                this.$emit('action', this.$refs.sidebar.clientHeight);
+            });
+        },
+        methods: {
+            goPage: function () {
+                window.canCustomerServer.getCustomeServer();
+            }
+        },
+        template: html
+    };
+});

+ 402 - 0
public/pc/components/base_header/index.css

xqd
@@ -0,0 +1,402 @@
+.base-header {
+    border-bottom: 1px solid #F9F9F9;
+    background-color: #fff;
+}
+
+.base-header > div:not(:first-child) {
+    width: 1200px;
+    margin: 0 auto;
+}
+
+.base-header .button-bar {
+    background-color: #282828;
+}
+
+.base-header .bar-inner {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+    -moz-box-pack: justify;
+    -ms-flex-pack: justify;
+    justify-content: space-between;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+    -moz-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    width: 1200px;
+    height: 40px;
+    margin: 0 auto;
+}
+
+.base-header .button-bar .el-button--text {
+    padding: 0 15px;
+    border: 0;
+    border-left: 1px solid rgba(255, 255, 255, 0.1);
+    border-radius: 0;
+    font-size: 12px;
+    color: #b4b4b4;
+}
+
+.base-header .button-bar .el-button--text:hover {
+    color: #FFFFFF;
+}
+
+.base-header .button-bar .group-right {
+    display: -webkit-inline-box;
+    display: -webkit-inline-flex;
+    display: -moz-inline-box;
+    display: -ms-inline-flexbox;
+    display: inline-flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+    -moz-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+}
+
+.base-header .button-bar .group-right a {
+    float: left;
+    display: -webkit-inline-box;
+    display: -webkit-inline-flex;
+    display: -moz-inline-box;
+    display: -ms-inline-flexbox;
+    display: inline-flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+    -moz-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    padding-right: 15px;
+    padding-left: 15px;
+    font-size: 12px;
+    color: #b4b4b4;
+}
+
+.base-header .button-bar .group-right > span {
+    font-size: 0;
+}
+
+.base-header .button-bar .group-left > .el-button--text:first-child, .base-header .button-bar .group-right > .el-button--text:first-child {
+    border: 0;
+}
+
+.base-header .button-bar .el-avatar {
+    margin-right: 8px;
+}
+
+.base-header .logo-search {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+    -moz-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    padding: 17px 0;
+}
+
+.base-header .logo-search .el-image {
+    width: 126px;
+    height: 65px;
+    margin-left: 52px;
+}
+
+.base-header .logo-search .search {
+    margin-left: 266px;
+}
+
+.base-header .el-input-group {
+    width: 540px;
+}
+
+.base-header .el-input__inner {
+    border-color: #2c8eff;
+}
+
+.base-header .el-input-group__append, .base-header .el-input-group__prepend {
+    border-color: #2c8eff;
+    background-color: #FFFFFF;
+}
+
+.base-header .el-select .el-input {
+    width: 80px;
+}
+
+.base-header .el-input-group__append .el-button {
+    width: 90px;
+    height: 40px;
+    border-color: #2c8eff;
+    border-radius: 0 4px 4px 0;
+    background: #2c8eff;
+    font-size: 14px;
+    color: #fff;
+}
+
+.base-header > div:nth-child(2) .el-button-group {
+    display: block;
+    width: 540px;
+    height: 16px;
+    margin-top: 10px;
+    overflow: hidden;
+}
+
+.base-header > div:nth-child(2) .el-button--text {
+    padding-top: 0;
+    padding-bottom: 0;
+    border: 0;
+    margin-right: 18px;
+    font-size: 14px;
+    line-height: 16px;
+    color: #999;
+}
+
+.base-header > div:nth-child(2) .el-button--text:hover {
+    color: #2c8eff;
+}
+
+.base-header .category {
+    position: relative;
+    display: inline-block;
+}
+
+.base-header .category > .el-button {
+    width: 230px;
+    height: 56px;
+    border: 0;
+    border-radius: 8px 8px 0 0;
+    background: -webkit-linear-gradient(181deg, #409DFF 0%, #1E85FB 100%);
+    background: -moz-linear-gradient(181deg, #409DFF 0%, #1E85FB 100%);
+    background: -o-linear-gradient(181deg, #409DFF 0%, #1E85FB 100%);
+    background: linear-gradient(269deg, #409DFF 0%, #1E85FB 100%);
+    font-size: 18px;
+    color: #fff;
+}
+
+.base-header .category > .el-button span {
+    padding: 0 0 0 28px;
+    background: url("../../images/cate_icon.png") left center/15px 12px no-repeat;
+}
+
+.base-header .category .wrapper {
+    position: absolute;
+    top: 100%;
+    left: 0;
+    z-index: 100;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    height: 0;
+    -webkit-transition: 0.3s;
+    -o-transition: 0.3s;
+    -moz-transition: 0.3s;
+    transition: 0.3s;
+}
+
+.base-header .category .wrapper.on {
+    height: 450px;
+}
+
+.base-header .category .menu {
+    width: 230px;
+    background-color: rgba(0, 0, 0, 0.6);
+    overflow: auto;
+    scrollbar-width: none;
+    -ms-overflow-style: none;
+    -webkit-transition: 0.3s;
+    -o-transition: 0.3s;
+    -moz-transition: 0.3s;
+    transition: 0.3s;
+}
+
+.base-header .category .menu::-webkit-scrollbar {
+    display: none; /* Chrome Safari */
+  }
+
+.base-header .category .menu .el-button {
+    width: 100%;
+    height: 50px;
+    padding-right: 32px;
+    padding-left: 32px;
+    border-radius: 0;
+    margin-left: 0;
+    color: #fff;
+}
+
+.base-header .category .menu .el-button.on {
+    background-color: #2c8eff;
+}
+
+.base-header .category .menu .el-button span {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+    -moz-box-pack: justify;
+    -ms-flex-pack: justify;
+    justify-content: space-between;
+    font-size: 16px;
+}
+
+.base-header .category .content > div {
+    width: 710px;
+    height: 100%;
+    padding-right: 30px;
+    padding-left: 30px;
+    background-color: #fff;
+    -webkit-box-shadow: 0 0 10px rgba(106, 128, 154, 0.15);
+    box-shadow: 0 0 10px rgba(106, 128, 154, 0.15);
+    overflow-y: auto;
+    scrollbar-width: none;
+}
+.base-header .category .content > div::-webkit-scrollbar {
+    display: none;
+}
+
+.base-header .category .title {
+    padding-top: 30px;
+    padding-bottom: 20px;
+    font-weight: bold;
+    font-size: 16px;
+    color: #282828;
+}
+
+.base-header .category .wrap .el-link {
+    margin-right: 40px;
+    margin-bottom: 12px;
+    font-size: 14px;
+    color: #333;
+}
+
+.base-header .category .wrap .el-link:hover {
+    color: #2c8eff;
+}
+
+.base-header .category .wrap.special > div:nth-child(2) {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-flex-wrap: wrap;
+    -ms-flex-wrap: wrap;
+    flex-wrap: wrap;
+    margin-right: -30px;
+}
+
+.base-header .category .wrap.special a {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    width: 310px;
+    margin-right: 30px;
+    margin-bottom: 30px;
+}
+
+.base-header .category .el-image {
+    width: 140px;
+    height: 80px;
+    border-radius: 4px;
+}
+
+.base-header .category .el-image + div {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+    -moz-box-flex: 1;
+    -ms-flex: 1;
+    flex: 1;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+    -moz-box-orient: vertical;
+    -moz-box-direction: normal;
+    -ms-flex-direction: column;
+    flex-direction: column;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+    -moz-box-pack: justify;
+    -ms-flex-pack: justify;
+    justify-content: space-between;
+    min-width: 0;
+    margin-left: 12px;
+    font-size: 12px;
+    color: #999;
+}
+
+.base-header .category .el-image + div > div:first-child > div:first-child {
+    overflow: hidden;
+    white-space: nowrap;
+    -o-text-overflow: ellipsis;
+    text-overflow: ellipsis;
+    font-size: 14px;
+    color: #282828;
+}
+
+.base-header .category .el-image + div > div:first-child > div:nth-child(2) {
+    margin-top: 6px;
+    color: #ff6b00;
+}
+
+.base-header .category .el-image + div > div:first-child > div:nth-child(2) span {
+    font-size: 16px;
+}
+
+.base-header .nav-wrapper > .el-link {
+    padding-right: 25px;
+    padding-left: 25px;
+    font-size: 18px;
+    color: #333;
+}
+
+.base-header .nav-wrapper > .el-link:hover {
+    color: #2c8eff;
+}
+
+.base-header .nav-wrapper > .el-link:nth-child(2) {
+    padding-left: 40px;
+}
+
+.base-header .nav-wrapper > .el-link.on {
+    color: #2c8eff;
+}
+
+.base-header .el-input-group__append, .el-input-group__prepend {
+    background-color: #fff;
+}
+
+.base-header .qrcode-popover {
+    min-width: auto;
+    padding: 5px;
+}
+
+.base-header .qrcode-popover .el-image {
+    width: 70px;
+    height: 70px;
+}
+
+.base-header .qrcode-popover .el-image + div {
+    margin: 2px 0 0;
+    font-size: 9px;
+    line-height: 12px;
+    text-align: center;
+    color: #666666;
+}

+ 75 - 0
public/pc/components/base_header/index.html

xqd
@@ -0,0 +1,75 @@
+<div class="base-header">
+    <div class="button-bar">
+        <div class="bar-inner">
+            <el-button-group class="group-left">
+                <el-button type="text" icon="el-icon-star-off" @click="addFavorite">收藏本站</el-button>
+                <el-button v-if="!isHomePage" type="text" icon="el-icon-house" @click="goPage('home')">返回首页</el-button>
+            </el-button-group>
+            <el-button-group class="group-right">
+                <a v-if="userInfo.avatar" :href="router.user">
+                    <el-avatar :size="22" :src="userInfo.avatar"></el-avatar>
+                    {{ userInfo.nickname }}
+                </a>
+                <el-button v-else type="text" @click="$emit('login-open')">登录/注册</el-button>
+                <el-button @click="goPage('member')" type="text">会员中心</el-button>
+                <el-button @click="goPage('course')" type="text">我的课程</el-button>
+            </el-button-group>
+        </div>
+    </div>
+    <div class="logo-search">
+        <el-image v-if="publicData.home_logo" :src="publicData.home_logo" fit="cover" @click.native="goPage('home')"></el-image>
+        <div class="search">
+            <el-input v-model.trim="searchValue" placeholder="请输入搜索内容">
+                <el-select v-model="selected" slot="prepend">
+                    <el-option v-for="option in options" :key="option.value" :label="option.label"
+                               :value="option.value"></el-option>
+                </el-select>
+                <el-button slot="append" @click="onSearch('')">搜索</el-button>
+            </el-input>
+            <el-button-group>
+                <el-button v-for="(item, index) in publicData.host_search" :key="index" type="text" @click="onSearch(item)">{{ item }}
+                </el-button>
+            </el-button-group>
+        </div>
+    </div>
+    <div class="nav-wrapper" :hidden="isUserPage">
+        <div class="category" @mouseenter="categoryMouseenter" @mouseleave="categoryMouseleave">
+            <el-button>课程分类</el-button>
+            <div :class="{ on: categoryVisible }" class="wrapper">
+                <div class="menu" @mouseenter="menuMouseenter" @mouseleave="menuMouseleave">
+                    <el-button v-for="(item, index) in publicData.grade_cate" :key="item.id" :class="{ on: menuOn === index }"
+                               type="text" @mouseenter.native="menuOn = index">{{ item.name }}<i
+                            class="el-icon-arrow-right el-icon--right"></i></el-button>
+                </div>
+                <div class="content" @mouseenter="contentMouseenter" @mouseleave="contentMouseleave">
+                    <div v-for="(item, index) in publicData.grade_cate" v-show="menuOn === index" :key="item.id">
+                        <div v-if="item.children.length" class="wrap">
+                            <div class="title">{{ item.name }}</div>
+                            <div>
+                                <el-link v-for="children in item.children" :key="children.id" :href="router.special_cate + '?cate_id=' + children.grade_id + '&subject_id=' + children.id" :underline="false">{{
+                                    children.name }}
+                                </el-link>
+                            </div>
+                        </div>
+                        <div v-if="item.list.length" class="wrap special">
+                            <div class="title">推荐课程</div>
+                            <div>
+                                <a v-for="(special, index) in item.list" v-if="index < 3" :key="special.id" :href="(special.is_light ? router.single_details : router.special_details) + '?id=' + special.id">
+                                    <el-image :src="special.image" fit="cover"></el-image>
+                                    <div>
+                                        <div>
+                                            <div>{{ special.title }}</div>
+                                            <div>¥<span>{{ special.money }}</span></div>
+                                        </div>
+                                        <div>{{ special.browse_count }}人已学习</div>
+                                    </div>
+                                </a>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <el-link v-for="item in publicData.navList" :key="item.id" :class="{ on: item.link == currentURL }" :href="item.link" :underline="false">{{ item.title }}</el-link>
+    </div>
+</div>

+ 154 - 0
public/pc/components/base_header/index.js

xqd
@@ -0,0 +1,154 @@
+define([
+    'mixins/router',
+    'scripts/util',
+    'text!components/base_header/index.html',
+    'css!components/base_header/index.css'
+], function (routerMixin, util, html) {
+    return {
+        mixins: [routerMixin],
+        props: {
+            publicData: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            },
+            userInfo: {
+                type: Object,
+                default: function () {
+                    return {
+                        avatar: ''
+                    };
+                }
+            }
+        },
+        data: function () {
+            return {
+                selected: 1,
+                options: [
+                    {
+                        label: '专题',
+                        value: 1
+                    },
+                    {
+                        label: '资料',
+                        value: 2
+                    }
+                ],
+                searchValue: '',
+                activeIndex: '1',
+                active: 1,
+                currentURL: window.location.pathname,
+                categoryVisible: false,
+                menuOn: -1,
+                isUserPage: false,
+                isHomePage: false,
+                code_url: code_url
+            };
+        },
+        created: function () {
+            if (this.currentURL.includes('/web/index/index')) {
+                this.isHomePage = true;
+            } else if (this.currentURL.includes('/web/material/material_list') || this.currentURL.includes('/web/material/details')) {
+                this.selected = 2;
+                this.setSearchValue();
+            } else if (this.currentURL.includes('/web/special/special_cate')) {
+                this.setSearchValue();
+            } else if (this.currentURL.includes('/web/my/index')) {
+                this.isUserPage = true;
+            }
+            if (code_url) {
+                this.code_url = code_url;
+            }
+        },
+        methods: {
+            goPage: function (page) {
+                switch (page) {
+                    case 'home':
+                        window.location.assign(this.router.home);
+                        break;
+                    case 'member':
+                    case 'course':
+                        if (!this.userInfo.uid) {
+                            return this.$emit('login-open');
+                        }
+                        window.location.assign(this.router.user + '?activeName=' + page);
+                        break;
+                }
+            },
+            onSearch: function (hot) {
+                if (!hot && !this.searchValue) {
+                    return;
+                }
+                if (hot) {
+                    this.searchValue = hot;
+                }
+                if (this.currentURL.includes('/web/special/special_cate')) {
+                    if (this.selected === 1) {
+                        this.$emit('submit-search', this.searchValue);
+                    } else {
+                        window.location.assign(this.router.material_list + '?search=' + this.searchValue);
+                    }
+                } else if (this.currentURL.includes('/web/material/material_list')) {
+                    if (this.selected === 2) {
+                        this.$emit('submit-search', this.searchValue);
+                    } else {
+                        window.location.assign(this.router.special_cate + '?search=' + this.searchValue);
+                    }
+                } else {
+                    window.location.assign((this.selected === 1 ? this.router.special_cate : this.router.material_list) + '?search=' + this.searchValue);
+                }
+            },
+            categoryMouseenter: function () {
+                this.categoryMouse = true;
+                this.categoryVisible = true;
+            },
+            categoryMouseleave: function () {
+                this.categoryMouse = false;
+                if (!(this.contentMouse || this.menuMouse)) {
+                    this.menuOn = -1;
+                    this.categoryVisible = false;
+                }
+            },
+            menuMouseenter: function () {
+                this.menuMouse = true;
+            },
+            menuMouseleave: function () {
+                this.menuMouse = false;
+                if (!(this.contentMouse || this.categoryMouse)) {
+                    this.menuOn = -1;
+                    this.categoryVisible = false;
+                }
+            },
+            contentMouseenter: function () {
+                this.contentMouse = true;
+            },
+            contentMouseleave: function () {
+                this.contentMouse = false;
+                if (!(this.menuMouse || this.categoryMouse)) {
+                    this.menuOn = -1;
+                    this.categoryVisible = false;
+                }
+            },
+            setSearchValue: function () {
+                var search = util.getParmas('search');
+                if (search) {
+                    this.searchValue = search;
+                }
+            },
+            // 收藏本站
+            addFavorite: function () {
+                try {
+                    window.external.addFavorite(window.location.origin + this.router.home, this.publicData.site_name);
+                } catch (error) {
+                    try {
+                        window.sidebar.addPanel(this.publicData.site_name, window.location.origin + this.router.home, '');
+                    } catch (error) {
+                        this.$message('抱歉,您所使用的浏览器无法完成此操作,请使用Ctrl+D进行添加!');
+                    }
+                }
+            }
+        },
+        template: html
+    };
+});

+ 322 - 0
public/pc/components/base_login/index.css

xqd
@@ -0,0 +1,322 @@
+.login-dialog .el-dialog__header {
+    padding: 0;
+}
+
+.login-dialog .el-dialog__body {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    height: 460px;
+    padding: 0;
+}
+
+.login-dialog .el-image {
+    width: 355px;
+    border-top-left-radius: 8px;
+    border-bottom-left-radius: 8px;
+    background-color: #2c8eff;
+}
+
+.login-dialog .el-form {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+       -moz-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    position: relative;
+}
+
+.login-dialog .el-form-item {
+    margin-bottom: 20px;
+}
+
+.login-dialog .el-radio-button__inner {
+    padding-right: 35px;
+    padding-left: 35px;
+    border: none;
+    font-size: 20px;
+    color: #282828;
+}
+
+.login-dialog .el-radio-button:first-child .el-radio-button__inner {
+    border-left: none;
+}
+
+.login-dialog .el-radio-button__orig-radio:checked+.el-radio-button__inner {
+    background: none;
+    -webkit-box-shadow: none;
+            box-shadow: none;
+    color: #2c8eff;
+}
+
+.login-dialog .el-form-item:first-child .el-form-item__content, .login-dialog .el-form-item:nth-child(2) .el-form-item__content {
+    font-size: 20px;
+    color: #282828;
+}
+
+.login-dialog .el-form-item:nth-child(4), .login-dialog .el-form-item:nth-child(5), .login-dialog .el-form-item:nth-child(6), .login-dialog .el-form-item:nth-child(7), .login-dialog .el-form-item:nth-child(8), .login-dialog .el-form-item:nth-child(9), .login-dialog .el-form-item:nth-child(10), .login-dialog .el-form-item:nth-child(11) {
+    width: 358px;
+}
+
+.login-dialog .el-input__inner {
+    height: 50px;
+    border-radius: 25px;
+    line-height: 50px;
+}
+
+.login-dialog .el-form-item:nth-child(5) .el-input__inner {
+    border-top-right-radius: 0;
+    border-bottom-right-radius: 0;
+}
+
+.login-dialog .el-form-item:nth-child(5) .el-input-group__append {
+    border-color: #dbdbdb;
+    border-top-right-radius: 25px;
+    border-bottom-right-radius: 25px;
+    background-color: transparent;
+}
+
+.login-dialog .el-form-item:nth-child(5) .el-button {
+    width: 112px;
+    padding: 17px 0;
+    border-top-right-radius: 24px;
+    border-bottom-right-radius: 24px;
+    color: #2c8eff;
+}
+
+.login-dialog .el-button.is-disabled, .login-dialog .el-button.is-disabled:focus, .login-dialog .el-button.is-disabled:hover {
+    color: #ccc;
+}
+
+.login-dialog .el-form-item:nth-child(6) .el-input__inner {
+    padding-right: 90px;
+}
+
+.login-dialog .el-form-item:nth-child(6) .el-input-group__append {
+    position: absolute;
+    top: 50%;
+    right: 0;
+    z-index: 2;
+    width: 90px;
+    border: 0;
+    background-color: transparent;
+    -webkit-transform: translateY(-50%);
+       -moz-transform: translateY(-50%);
+        -ms-transform: translateY(-50%);
+         -o-transform: translateY(-50%);
+            transform: translateY(-50%);
+}
+
+.login-dialog .el-form-item:nth-child(6) .el-button {
+    font-size: 12px;
+    color: #999;
+}
+
+.login-dialog .el-form-item:nth-child(9) .el-form-item__content, .login-dialog .el-form-item:nth-child(10) .el-form-item__content, .login-dialog .el-form-item:nth-child(12) .el-form-item__content, .login-dialog .el-form-item:nth-child(13) .el-form-item__content, .login-dialog .el-form-item:nth-child(14) .el-form-item__content {
+    line-height: normal;
+}
+
+.login-dialog .el-checkbox__inner {
+    border-radius: 50%;
+}
+
+.login-dialog .el-checkbox__label {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    font-size: 12px;
+    color: #666;
+}
+
+.login-dialog .el-form-item:nth-child(9) .el-checkbox {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+}
+
+.login-dialog .el-form-item:nth-child(9) .el-checkbox .el-button--text {
+    padding-top: 0;
+    padding-bottom: 0;
+    white-space: pre-line;
+    text-align: left;
+    font-size: 12px;
+    line-height: normal;
+    color: #ff6b00;
+}
+
+.login-dialog .el-form-item:nth-child(9) .el-form-item__content > .el-button--text {
+    padding-top: 0;
+    padding-bottom: 0;
+    font-size: 12px;
+    color: #999;
+}
+
+.login-dialog .el-form-item:nth-child(10) .el-button {
+    width: 100%;
+    padding-top: 18px;
+    padding-bottom: 18px;
+    border: none;
+    border-radius: 25px;
+    background: -webkit-gradient(linear, left top, right top, from(#409dff), to(#1e85fb));
+    background: -webkit-linear-gradient(left, #409dff 0%, #1e85fb 100%);
+    background: -moz-linear-gradient(left, #409dff 0%, #1e85fb 100%);
+    background: -o-linear-gradient(left, #409dff 0%, #1e85fb 100%);
+    background: linear-gradient(90deg, #409dff 0%, #1e85fb 100%);
+    color: #fff;
+}
+
+.login-dialog .el-form-item:nth-child(10) .el-button+.el-button {
+    margin-left: 0;
+}
+
+.login-dialog .el-form-item:nth-child(11) .el-form-item__content {
+    text-align: center;
+}
+
+.login-dialog .el-form-item:nth-child(11) .el-form-item__content, .login-dialog .el-form-item:nth-child(13) .el-form-item__content {
+    color: #ccc;
+}
+
+.login-dialog .el-form-item:nth-child(11) .el-button--text, .login-dialog .el-form-item:nth-child(12) .el-button--text, .login-dialog .el-form-item:nth-child(13) .el-button--text {
+    padding-top: 0;
+    padding-bottom: 0;
+    color: #2c8eff;
+}
+
+.login-dialog .el-form-item:nth-child(11), .login-dialog .el-form-item:nth-child(12), .login-dialog .el-form-item:nth-child(13) {
+    margin-bottom: 0;
+}
+
+.login-dialog .el-form-item:nth-child(14) {
+    margin-bottom: 44px;
+}
+
+.login-dialog .el-form-item:nth-child(14) .el-form-item__content {
+    font-size: 20px;
+    line-height: 26px;
+    color: #282828;
+}
+
+.login-dialog .el-form-item.qrcode .el-image {
+    width: 190px;
+    height: 190px;
+    border-radius: 0;
+    vertical-align: middle;
+}
+
+.login-dialog .el-form-item.qrcode .el-form-item__content > div:first-child {
+    position: relative;
+    width: 209px;
+    height: 209px;
+    line-height: 209px;
+    text-align: center;
+}
+
+.login-dialog .el-form-item.qrcode .el-form-item__content > div:last-child {
+    margin-top: 20px;
+    font-size: 14px;
+    line-height: 19px;
+    text-align: center;
+    color: #666666;
+}
+
+.login-dialog .el-form-item.qrcode .el-form-item__content > div:first-child > div:first-child {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 22px;
+    height: 22px;
+    border-width: 2px;
+    border-style: solid;
+    border-color: #CBCBCB transparent transparent #CBCBCB;
+}
+
+.login-dialog .el-form-item.qrcode .el-form-item__content > div:first-child > div:nth-child(2) {
+    position: absolute;
+    top: 0;
+    right: 0;
+    width: 22px;
+    height: 22px;
+    border-width: 2px;
+    border-style: solid;
+    border-color: #CBCBCB #CBCBCB transparent transparent;
+}
+
+.login-dialog .el-form-item.qrcode .el-form-item__content > div:first-child > div:nth-child(3) {
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    width: 22px;
+    height: 22px;
+    border-width: 2px;
+    border-style: solid;
+    border-color: transparent #CBCBCB #CBCBCB transparent;
+}
+
+.login-dialog .el-form-item.qrcode .el-form-item__content > div:first-child > div:nth-child(4) {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    width: 22px;
+    height: 22px;
+    border-width: 2px;
+    border-style: solid;
+    border-color: transparent transparent #CBCBCB #CBCBCB;
+}
+
+.login-dialog .el-dialog__headerbtn {
+    top: -50px;
+    right: -70px;
+    font-size: 40px;
+}
+
+.login-dialog .el-dialog__headerbtn .el-dialog__close {
+    color: #ddd;
+}
+
+.login-dialog .method-btn {
+    position: absolute;
+    top: 0;
+    right: 0;
+    width: 68px;
+    height: 68px;
+    background: url("../../images/login1.png") left top/100% 100% no-repeat;
+    cursor: pointer;
+}
+
+.login-dialog .method-btn.qrcode-btn {
+    background-image: url("../../images/login2.png");
+}

+ 61 - 0
public/pc/components/base_login/index.html

xqd
@@ -0,0 +1,61 @@
+<el-dialog :visible="loginVisible" width="825px" custom-class="login-dialog" @close="$emit('login-close')">
+    <el-image :src="publicData.pc_login_diagram" fit="cover"></el-image>
+    <el-form>
+        <el-form-item v-show="state === 1 && type != 3">注册账号</el-form-item>
+        <el-form-item v-show="state === 2 && type != 3">找回密码</el-form-item>
+        <el-form-item v-show="state === 3 && type != 3">
+            <el-radio-group v-model="type">
+                <el-radio-button :label="1">账号登录</el-radio-button>
+                <el-radio-button :label="2">快速登录</el-radio-button>
+            </el-radio-group>
+        </el-form-item>
+        <el-form-item v-show="type != 3">
+            <el-input v-model.trim="phone" placeholder="请输入手机号" clearable></el-input>
+        </el-form-item>
+        <el-form-item v-show="(state !== 3 && type != 3) || type === 2">
+            <el-input v-model.trim="code" placeholder="请输入验证码" maxlength="6" minlength="6" clearable>
+                <el-button slot="append" :disabled="count >= 0" @click="getCode">{{ count < 0 ? '获取验证码' : '重新获取(' + count + 's)' }}</el-button>
+            </el-input>
+        </el-form-item>
+        <el-form-item v-show="state === 3 && type === 1">
+            <el-input v-model.trim="pwd" placeholder="请输入密码" maxlength="16" minlength="8" show-password>
+                <el-button slot="append" @click="state = 2">忘记密码</el-button>
+            </el-input>
+        </el-form-item>
+        <el-form-item v-show="state === 1 && type != 3">
+            <el-input v-model.trim="pwd" placeholder="请输入8-16位字母加数字组合密码" maxlength="16" minlength="8" show-password></el-input>
+        </el-form-item>
+        <el-form-item v-show="state === 2 && type != 3">
+            <el-input v-model.trim="pwd" placeholder="请输入8-16位字母加数字组合新密码" maxlength="16" minlength="8" show-password></el-input>
+        </el-form-item>
+        <el-form-item v-show="state !== 2 && type != 3">
+            <el-checkbox v-model="agree">我已阅读并同意<el-button type="text" @click="$emit('agree-open')">《{{ agreeContent.title }}》</el-button></el-checkbox>
+        </el-form-item>
+        <el-form-item v-show="type != 3">
+            <el-button v-show="state === 1" @click="register">注册</el-button>
+            <el-button v-show="state === 2" @click="register">确认</el-button>
+            <el-button v-show="state === 3" @click="login">登录</el-button>
+        </el-form-item>
+        <el-form-item v-show="state === 1 && type != 3">
+            已有账号?<el-button type="text" @click="state = 3">立即登录</el-button>
+        </el-form-item>
+        <el-form-item v-show="state === 2 && type != 3">
+            <el-button type="text" @click="state = 3">立即登录</el-button>
+        </el-form-item>
+        <el-form-item v-show="state === 3 && type != 3">
+            没有账号?<el-button type="text" @click="state = 1">立即注册</el-button>
+        </el-form-item>
+        <el-form-item v-show="type == 3">扫码登录</el-form-item>
+        <el-form-item v-show="type == 3" class="qrcode">
+            <div>
+                <div></div>
+                <div></div>
+                <div></div>
+                <div></div>
+                <el-image :src="qrcodeSrc"></el-image>
+            </div>
+            <div>请使用微信扫一扫登录</div>
+        </el-form-item>
+        <div v-show="state == 3" :class="{ 'qrcode-btn': type == 3 }" class="method-btn" @click="type = type == 3 ? 1 : 3"></div>
+    </el-form>
+</el-dialog>

+ 248 - 0
public/pc/components/base_login/index.js

xqd
@@ -0,0 +1,248 @@
+define([
+    'api/auth',
+    'api/login',
+    'plugins/blueimp-md5/js/md5',
+    'text!components/base_login/index.html',
+    'css!components/base_login/index.css'
+], function (authApi, loginApi, md5, html) {
+    return {
+        props: {
+            loginVisible: {
+                type: Boolean,
+                default: false
+            },
+            publicData: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            },
+            agreeContent: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            }
+        },
+        data: function () {
+            return {
+                state: 3, // 1 注册,2 找回密码,3 登录
+                type: 1,  // 1 账号登录,2 快速登录,3 扫码登录
+                phone: '',
+                code: '',
+                pwd: '',
+                agree: false,
+                count: -1,
+                TIME_COUNT: 60,
+                scanCount: 0,
+                scanTimer: null,
+                qrcodeSrc: ''
+            };
+        },
+        watch: {
+            state: function () {
+                this.phone = '';
+                this.code = '';
+                this.pwd = '';
+                this.agree = false;
+                if (this.timer) {
+                    clearInterval(this.timer);
+                    this.timer = null;
+                    this.count = -1;
+                }
+            },
+            type: function (val) {
+                var vm = this;
+                if (val == 3) {
+                    loginApi.loginQrcode().catch(function (res) {
+                        vm.qrcodeSrc = res.url;
+                        vm.setScanLogin(res);
+                    });
+                } else {
+                    if (this.scanTimer) {
+                        clearInterval(this.scanTimer);
+                        this.scanTimer = null;
+                    }
+                }
+            },
+            loginVisible: function (val) {
+                if (val) {
+                    this.state = 3;
+                    this.type = 1;
+                } else {
+                    if (this.scanTimer) {
+                        clearInterval(this.scanTimer);
+                        this.scanTimer = null;
+                    }
+                }
+            }
+        },
+        created: function () {
+            var vm = this;
+            window.addEventListener('keydown', function (event) {
+                if (event.key == 'Enter' && vm.loginVisible) {
+                    vm.login();
+                }
+            });
+        },
+        methods: {
+            // 获取验证码
+            getCode: function () {
+                var vm = this;
+                if (!this.phone) {
+                    return this.$message.warning('请输入手机号');
+                }
+                if (!/^1[3456789]\d{9}$/.test(this.phone)) {
+                    return this.$message.warning('手机号错误');
+                }
+                this.count = this.TIME_COUNT;
+                this.timer = setInterval(function () {
+                    vm.count--;
+                    if (vm.count < 0) {
+                        clearInterval(vm.timer);
+                        vm.timer = null;
+                    }
+                }, 1000);
+                authApi.code({
+                    phone: this.phone
+                }).then(function (res) {
+                    vm.$message.success(res.msg);
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                    clearInterval(vm.timer);
+                    vm.timer = null;
+                    vm.count = -1;
+                });
+            },
+            // 登录
+            login: function () {
+                this.type === 1 ? this.pwdLogin() : this.smsLogin();
+            },
+            // 短信登录、注册
+            smsLogin: function () {
+                var vm = this;
+                if (!this.phone) {
+                    return this.$message.warning('请输入手机号');
+                }
+                if (!/^1[3456789]\d{9}$/.test(this.phone)) {
+                    return this.$message.warning('手机号错误');
+                }
+                if (!this.code) {
+                    return this.$message.warning('请输入验证码');
+                }
+                if (!/^\d{6}$/.test(this.code)) {
+                    return this.$message.warning('验证码错误');
+                }
+                if (!this.agree) {
+                    return this.$message.warning('请勾选用户协议');
+                }
+                if (this.timer) {
+                    clearInterval(this.timer);
+                    this.timer = null;
+                }
+                loginApi.phoneCheck({
+                    phone: this.phone,
+                    code: this.code
+                }).then(function (res) {
+                    vm.$message.success(res.msg);
+                    vm.$emit('login-close', 1);
+                    vm.phone = '';
+                    vm.code = '';
+                    vm.count = -1;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                    vm.count = -1;
+                });
+            },
+            // 账号密码登录
+            pwdLogin: function () {
+                var vm = this;
+                if (!this.phone) {
+                    return this.$message.warning('请输入手机号');
+                }
+                if (!/^1[3456789]\d{9}$/.test(this.phone)) {
+                    return this.$message.warning('手机号错误');
+                }
+                if (!this.pwd) {
+                    return this.$message.warning('请输入密码');
+                }
+                // if (this.pwd !== '123456' || !/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$/.test(this.pwd)) {
+                //     return this.$message.warning('密码格式错误');
+                // }
+                if (!this.agree) {
+                    return this.$message.warning('请勾选用户协议');
+                }
+                loginApi.heck({
+                    account: this.phone,
+                    pwd: md5(this.pwd)
+                }).then(function (res) {
+                    vm.$message.success(res.msg);
+                    vm.$emit('login-close', 1);
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            // 账号注册、找回密码
+            register: function () {
+                var vm = this;
+                if (!this.phone) {
+                    return this.$message.warning('请输入手机号');
+                }
+                if (!/^1[3456789]\d{9}$/.test(this.phone)) {
+                    return this.$message.warning('手机号错误');
+                }
+                if (!this.code) {
+                    return this.$message.warning('请输入验证码');
+                }
+                if (!/^\d{6}$/.test(this.code)) {
+                    return this.$message.warning('验证码错误');
+                }
+                if (!this.pwd) {
+                    return this.$message.warning('请输入密码');
+                }
+                if (!/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$/.test(this.pwd)) {
+                    return this.$message.warning('请输入8-16位字母加数字组合密码');
+                }
+                if (this.state === 1 && !this.agree) {
+                    return this.$message.warning('请勾选用户协议');
+                }
+                if (this.timer) {
+                    clearInterval(this.timer);
+                    this.timer = null;
+                }
+                loginApi.register({
+                    account: this.phone,
+                    pwd: md5(this.pwd),
+                    code: this.code,
+                    type: this.state
+                }).then(function (res) {
+                    vm.$message.success(res.msg);
+                    vm.phone = '';
+                    vm.pwd = '';
+                    vm.code = '';
+                    vm.state = 3;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                    vm.count = -1;
+                });
+            },
+            setScanLogin: function (data) {
+                var vm = this;
+                this.scanTimer = setInterval(function () {
+                    if (vm.scanCount < 40) {
+                        vm.scanCount++;
+                        loginApi.setScanLogin(data).then(function () {
+                            clearInterval(vm.scanTimer);
+                            vm.scanTimer = null;
+                            window.location.reload();
+                        });
+                    } else {
+                        clearInterval(vm.scanTimer);
+                        vm.scanTimer = null;
+                    }
+                }, 3000);
+            }
+        },
+        template: html
+    };
+});

+ 172 - 0
public/pc/components/home/recommend0/index.css

xqd
@@ -0,0 +1,172 @@
+.recommend {
+    padding-top: 30px;
+    padding-bottom: 30px;
+}
+
+.recommend .head {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    -webkit-box-align: end;
+    -webkit-align-items: flex-end;
+       -moz-box-align: end;
+        -ms-flex-align: end;
+            align-items: flex-end;
+    font-weight: bold;
+    font-size: 24px;
+    color: #333;
+}
+
+.recommend .head div span {
+    margin-left: 10px;
+    font-weight: normal;
+    font-size: 16px;
+    color: #999;
+}
+
+.recommend .head .el-link.el-link--default {
+    font-size: 14px;
+    color: #666;
+}
+
+.recommend .el-row {
+    margin-top: 30px;
+}
+
+.recommend0 .el-row {
+    margin-bottom: -20px;
+}
+
+.recommend0 .el-col {
+    margin-bottom: 14px;
+}
+
+.recommend0 .el-row a {
+    display: block;
+    border-radius: 8px;
+    background-color: #fff;
+    overflow: hidden;
+    -webkit-transition: 0.3s;
+    -o-transition: 0.3s;
+    -moz-transition: 0.3s;
+    transition: 0.3s;
+}
+
+.recommend0 .el-row a:hover {
+    -webkit-box-shadow: 0 2px 16px rgba(79, 109, 143, 0.12);
+            box-shadow: 0 2px 16px rgba(79, 109, 143, 0.12);
+    -webkit-transform: translateY(-6px);
+       -moz-transform: translateY(-6px);
+        -ms-transform: translateY(-6px);
+         -o-transform: translateY(-6px);
+            transform: translateY(-6px);
+}
+
+.recommend0 .el-image {
+    display: block;
+    width: 100%;
+    height: 160px;
+}
+
+.recommend0 .el-image + div {
+    padding-right: 15px;
+    padding-left: 15px;
+}
+
+.recommend0 .title {
+    padding-top: 15px;
+    overflow: hidden;
+    white-space: nowrap;
+    -o-text-overflow: ellipsis;
+       text-overflow: ellipsis;
+    font-size: 16px;
+    color: #333;
+}
+
+.recommend0 .label-count {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    padding-top: 8px;
+    padding-bottom: 8px;
+    font-size: 14px;
+    color: #666;
+}
+
+.recommend0 .label-count > div:first-child {
+    font-size: 0;
+}
+
+.recommend0 .el-tag {
+    height: 22px;
+    padding-right: 9px;
+    padding-left: 9px;
+    border-color: rgba(44, 142, 255, 0.06);
+    border-radius: 2px;
+    background-color: rgba(44, 142, 255, 0.06);
+    line-height: 20px;
+    color: #2c8eff;
+}
+
+.recommend0 .el-tag ~ .el-tag {
+    margin-left: 6px;
+}
+
+.recommend0 .browse-money {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    height: 48px;
+    border-top: 1px dashed #eee;
+    font-size: 14px;
+    color: #999;
+}
+
+.recommend0 .money {
+    font-size: 14px;
+    color: #ff6b00;
+}
+
+.recommend0 .money.free {
+    font-size: 16px;
+}
+
+.recommend0 .money span {
+    font-size: 18px;
+}
+
+.recommend0 .el-col-6 {
+    padding-right: 7px !important;
+    padding-left: 7px !important;
+}

+ 31 - 0
public/pc/components/home/recommend0/index.html

xqd
@@ -0,0 +1,31 @@
+<div class="recommend recommend0">
+    <div class="head">
+        <div>{{ recommend.title }}<span>{{ recommend.explain }}</span></div>
+        <el-link :href="$router.more_list + '?type=' + recommend.type + '&recommend_id=' + recommend.id" :underline="false">更多<i class="el-icon-arrow-right el-icon--right"></i></el-link>
+    </div>
+    <el-row :gutter="20">
+        <el-col v-for="item in recommend.list" :key="item.id" :span="6">
+            <a :href="(item.is_light ? $router.single_detail : $router.special_detail) + '?id=' + item.id + '&from=more_list&type=' + recommend.type + '&recommend_id=' + recommend.id">
+                <el-image :src="item.image" fit="cover">
+                    <div slot="error" class="image-slot">
+                        <i class="el-icon-picture-outline"></i>
+                    </div>
+                </el-image>
+                <div>
+                    <div class="title">{{ item.title }}</div>
+                    <div class="label-count">
+                        <div>
+                            <el-tag v-for="label in item.label">{{ label }}</el-tag>
+                        </div>
+                        <div v-if="!item.is_light">共{{ item.count }}节</div>
+                    </div>
+                    <div class="browse-money">
+                        <div>{{ item.browse_count }}人已学</div>
+                        <div v-if="item.pay_type" class="money">¥<span>{{ item.money }}</span></div>
+                        <div v-else class="money free">免费</div>
+                    </div>
+                </div>
+            </a>
+        </el-col>
+    </el-row>
+</div>

+ 16 - 0
public/pc/components/home/recommend0/index.js

xqd
@@ -0,0 +1,16 @@
+define([
+    'text!./index.html',
+    'css!./index.css'
+], function(html) {
+    return {
+        props: {
+            recommend: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            }
+        },
+        template: html
+    };
+});

+ 161 - 0
public/pc/components/home/recommend1/index.css

xqd
@@ -0,0 +1,161 @@
+.recommend {
+    padding-top: 30px;
+    padding-bottom: 30px;
+}
+
+.recommend .head {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    -webkit-box-align: end;
+    -webkit-align-items: flex-end;
+       -moz-box-align: end;
+        -ms-flex-align: end;
+            align-items: flex-end;
+    font-weight: bold;
+    font-size: 24px;
+    color: #333;
+}
+
+.recommend .head div span {
+    margin-left: 10px;
+    font-weight: normal;
+    font-size: 16px;
+    color: #999;
+}
+
+.recommend .head .el-link.el-link--default {
+    font-size: 14px;
+    color: #666;
+}
+
+.recommend .el-row {
+    margin-top: 30px;
+}
+
+.recommend1 .el-row a {
+    display: block;
+    border-radius: 8px;
+    background-color: #fff;
+    overflow: hidden;
+}
+
+.recommend1 .el-row a > div:first-child {
+    position: relative;
+}
+
+.recommend1 .el-row a > div:first-child > div:first-child {
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: 2;
+    padding-right: 16px;
+    padding-left: 41px;
+    border-bottom-right-radius: 8px;
+    background: rgba(0, 0, 0, 0.6) url("../../../images/live3.png") 15px center/16px 16px no-repeat;
+    font-size: 16px;
+    line-height: 34px;
+    color: #fff;
+}
+
+.recommend1 .el-row a > div:first-child > div.live1 {
+    background-image: url("../../../images/live1.png");
+}
+
+.recommend1 .el-row a > div:first-child > div.live2 {
+    background-image: url("../../../images/live2.png");
+}
+
+.recommend1 .el-image {
+    display: block;
+    width: 100%;
+    height: 216px;
+}
+
+.recommend1 .el-row a > div:last-child {
+    padding-right: 15px;
+    padding-left: 15px;
+}
+
+.recommend1 .title {
+    padding-top: 16px;
+    overflow: hidden;
+    white-space: nowrap;
+    -o-text-overflow: ellipsis;
+       text-overflow: ellipsis;
+    font-size: 18px;
+    color: #333;
+}
+
+.recommend1 .lecturer {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    padding-top: 8px;
+    padding-bottom: 8px;
+    font-size: 16px;
+    color: #2b2b2b;
+    height: 75px;
+}
+
+.recommend1 .el-avatar {
+    margin-right: 15px;
+}
+
+.recommend1 .browse-money {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    height: 46px;
+    border-top: 1px dashed #e9e9e9;
+    font-size: 14px;
+    color: #999;
+}
+
+.recommend1 .el-icon-view {
+    margin-right: 5px;
+}
+
+.recommend1 .money {
+    font-size: 16px;
+    color: #ff6b00;
+}
+
+.recommend1 .money.free {
+    font-size: 18px;
+}
+
+.recommend1 .money span {
+    font-size: 24px;
+}
+
+.recommend1 .el-col-8 {
+    padding-right: 7px !important;
+    padding-left: 7px !important;
+}

+ 36 - 0
public/pc/components/home/recommend1/index.html

xqd
@@ -0,0 +1,36 @@
+<div class="recommend recommend1">
+    <div class="head">
+        <div>{{ recommend.title }}<span>{{ recommend.explain }}</span></div>
+        <el-link :href="$router.special_live" :underline="false">更多<i class="el-icon-arrow-right el-icon--right"></i></el-link>
+    </div>
+    <el-row :gutter="24">
+        <el-col v-for="item in recommend.list" :key="item.id" :span="8">
+            <a :href="$router.special_detail + '?id=' + item.id">
+                <div>
+                    <div v-if="item.status === 1" class="live1">直播中</div>
+                    <div v-else-if="item.status === 2" class="live1">回放</div>
+                    <div v-else-if="item.status === 4" class="live2">已结束</div>
+                    <div v-else>直播时间 {{ item.start_play_time }}</div>
+                    <el-image :src="item.image" fit="cover">
+                        <div slot="error" class="image-slot">
+                            <i class="el-icon-picture-outline"></i>
+                        </div>
+                    </el-image>
+                </div>
+                <div>
+                    <div class="title">{{ item.title }}</div>
+                    <div v-if="item.lecturer_id" class="lecturer">
+                        <el-avatar :src="item.lecturer.lecturer_head" :size="34" icon="el-icon-user-solid"></el-avatar>
+                        {{ item.lecturer.lecturer_name }}
+                    </div>
+                    <div v-else style="height: 75px;"></div>
+                    <div class="browse-money">
+                        <div><i class="el-icon-view"></i>{{ item.browse_count }}</div>
+                        <div v-if="item.pay_type" class="money">¥<span>{{ item.money }}</span></div>
+                        <div v-else class="money free">免费</div>
+                    </div>
+                </div>
+            </a>
+        </el-col>
+    </el-row>
+</div>

+ 20 - 0
public/pc/components/home/recommend1/index.js

xqd
@@ -0,0 +1,20 @@
+define([
+    'text!./index.html',
+    'css!./index.css'
+], function (html) {
+    return {
+        props: {
+            recommend: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            }
+        },
+        data: function () {
+            return {};
+        },
+        methods: {},
+        template: html
+    };
+});

+ 172 - 0
public/pc/components/home/recommend2/index.css

xqd
@@ -0,0 +1,172 @@
+.recommend {
+    padding-top: 30px;
+    padding-bottom: 30px;
+    margin-top: 10px;
+}
+
+.recommend .head {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+    -moz-box-pack: justify;
+    -ms-flex-pack: justify;
+    justify-content: space-between;
+    -webkit-box-align: end;
+    -webkit-align-items: flex-end;
+    -moz-box-align: end;
+    -ms-flex-align: end;
+    align-items: flex-end;
+    font-weight: bold;
+    font-size: 24px;
+    color: #333;
+}
+
+.recommend .head div span {
+    margin-left: 10px;
+    font-weight: normal;
+    font-size: 16px;
+    color: #999;
+}
+
+.recommend .head .el-link.el-link--default {
+    font-size: 14px;
+    color: #666;
+}
+
+.recommend .el-row {
+    margin-top: 30px;
+}
+
+.recommend2 .el-row a {
+    position: relative;
+    display: block;
+    border-radius: 8px;
+    overflow: hidden;
+}
+
+.recommend2 .el-image {
+    display: block;
+    width: 100%;
+    height: 224px;
+}
+
+.recommend2 .el-row a > div:nth-child(2) {
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    left: 0;
+    z-index: 2;
+    padding-left: 25px;
+    background: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.3)), to(#000));
+    background: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.3) 0%, #000 100%);
+    background: -moz-linear-gradient(top, rgba(0, 0, 0, 0.3) 0%, #000 100%);
+    background: -o-linear-gradient(top, rgba(0, 0, 0, 0.3) 0%, #000 100%);
+    background: linear-gradient(180deg, rgba(0, 0, 0, 0.3) 0%, #000 100%);
+    font-weight: bold;
+    font-size: 18px;
+    line-height: 62px;
+    color: #fff;
+}
+
+.recommend2 .el-row a:hover > div:nth-child(2) {
+    opacity: 0;
+}
+
+.recommend2 .el-row a > div:nth-child(2) span {
+    position: relative;
+    padding-left: 15px;
+    margin-left: 12px;
+    font-weight: normal;
+    font-size: 14px;
+}
+
+.recommend2 .el-row a > div:nth-child(2) span::before {
+    content: "/";
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    z-index: 2;
+    font-size: 12px;
+    line-height: normal;
+}
+
+.recommend2 .el-row a > div:last-child {
+    position: absolute;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    left: 0;
+    z-index: 2;
+    padding-top: 40px;
+    padding-right: 20px;
+    padding-left: 20px;
+    background-color: rgba(0, 0, 0, 0.8);
+    font-size: 14px;
+    color: #fff;
+    opacity: 0;
+    -webkit-transition: 0.3s;
+    -o-transition: 0.3s;
+    -moz-transition: 0.3s;
+    transition: 0.3s;
+}
+
+.recommend2 .el-row a:hover > div:last-child {
+    opacity: 1;
+}
+
+.recommend2 .el-row a > div:last-child > div:first-child {
+    font-weight: bold;
+    font-size: 18px;
+}
+
+.recommend2 .el-row a > div:last-child > div:nth-child(2) {
+    position: relative;
+    padding-top: 10px;
+    padding-bottom: 29px;
+    font-size: 0;
+}
+
+.recommend2 .el-row a > div:last-child > div:nth-child(2)::after {
+    content: "/";
+    position: absolute;
+    bottom: 0;
+    left: 10px;
+    z-index: 2;
+    font-size: 12px;
+}
+
+.recommend2 .el-tag {
+    height: 29px;
+    padding-right: 9px;
+    padding-left: 9px;
+    border-color: #6a6a6a;
+    border-radius: 2px;
+    background-color: #6a6a6a;
+    font-size: 14px;
+    line-height: 27px;
+    color: #fff;
+}
+
+.recommend2 .el-tag ~ .el-tag {
+    margin-left: 6px;
+}
+
+.recommend2 .el-row a > div:last-child > div:last-child {
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 3;
+    margin-top: 7px;
+    overflow: hidden;
+    line-height: 36px;
+}
+
+.recommend2 .el-col-6 {
+    width: 20%;
+    padding-right: 7px !important;
+    padding-left: 7px !important;
+    margin-bottom: 14px;
+}

+ 25 - 0
public/pc/components/home/recommend2/index.html

xqd
@@ -0,0 +1,25 @@
+<div class="recommend recommend2">
+    <div class="head">
+        <div>{{ recommend.title }}<span>{{ recommend.explain }}</span></div>
+        <el-link :href="$router.teacher_list" :underline="false">更多<i class="el-icon-arrow-right el-icon--right"></i></el-link>
+    </div>
+    <el-row :gutter="20">
+        <el-col v-for="item in recommend.list" :key="item.id" :span="6">
+            <a :href="$router.teacher_detail +'?id=' + item.id">
+                <el-image :src="item.lecturer_head" fit="cover">
+                    <div slot="error" class="image-slot">
+                        <i class="el-icon-picture-outline"></i>
+                    </div>
+                </el-image>
+                <div>{{ item.lecturer_name }}<span>{{ item.label[0] }}</span></div>
+                <div>
+                    <div>{{ item.lecturer_name }}</div>
+                    <div>
+                        <el-tag v-for="label in item.label" :key="label">{{ label }}</el-tag>
+                    </div>
+                    <div>{{ item.explain }}</div>
+                </div>
+            </a>
+        </el-col>
+    </el-row>
+</div>

+ 20 - 0
public/pc/components/home/recommend2/index.js

xqd
@@ -0,0 +1,20 @@
+define([
+    'text!./index.html',
+    'css!./index.css'
+], function (html) {
+    return {
+        props: {
+            recommend: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            }
+        },
+        data: function () {
+            return {};
+        },
+        methods: {},
+        template: html
+    };
+});

+ 121 - 0
public/pc/components/home/recommend3/index.css

xqd
@@ -0,0 +1,121 @@
+.recommend {
+    padding-top: 30px;
+    padding-bottom: 30px;
+}
+
+.recommend .head {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+    -moz-box-pack: justify;
+    -ms-flex-pack: justify;
+    justify-content: space-between;
+    -webkit-box-align: end;
+    -webkit-align-items: flex-end;
+    -moz-box-align: end;
+    -ms-flex-align: end;
+    align-items: flex-end;
+    font-weight: bold;
+    font-size: 24px;
+    color: #333;
+}
+
+.recommend .head div span {
+    margin-left: 10px;
+    font-weight: normal;
+    font-size: 16px;
+    color: #999;
+}
+
+.recommend .head .el-link.el-link--default {
+    font-size: 14px;
+    color: #666;
+}
+
+.recommend .el-row {
+    margin-top: 30px;
+}
+
+.recommend3 .el-row {
+    margin-bottom: -20px;
+}
+
+.recommend3 .el-col {
+    padding-right: 7px !important;
+    padding-left: 7px !important;
+    margin-bottom: 14px;
+}
+
+.recommend3 .el-row a {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    border-radius: 8px;
+    background: #FFFFFF;
+    overflow: hidden;
+    font-size: 14px;
+    color: #999;
+}
+
+.recommend3 .el-row a:hover {
+    -webkit-box-shadow: 0 2px 15px rgba(79, 109, 143, 0.15);
+    box-shadow: 0 2px 15px rgba(79, 109, 143, 0.15);
+}
+
+.recommend3 .el-image {
+    width: 330px;
+    height: 186px;
+}
+
+.recommend3 .el-row a > div:last-child {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+    -moz-box-flex: 1;
+    -ms-flex: 1;
+    flex: 1;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+    -moz-box-orient: vertical;
+    -moz-box-direction: normal;
+    -ms-flex-direction: column;
+    flex-direction: column;
+    min-width: 0;
+    padding: 15px 30px 20px 20px;
+}
+
+.recommend3 .el-row a > div:last-child > div:first-child {
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 2;
+    overflow: hidden;
+    font-size: 16px;
+    line-height: 26px;
+    color: #333;
+}
+
+.recommend3 .el-row a > div:last-child > div:nth-child(2) {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+    -moz-box-flex: 1;
+    -ms-flex: 1;
+    flex: 1;
+    margin-top: 18px;
+    font-size: 14px;
+    color: #ff6b00;
+}
+
+.recommend3 .el-row a > div:last-child > div:nth-child(2) span {
+    font-size: 22px;
+}

+ 19 - 0
public/pc/components/home/recommend3/index.html

xqd
@@ -0,0 +1,19 @@
+<div class="recommend recommend3">
+    <div class="head">
+        <div>{{ recommend.title }}<span>{{ recommend.explain }}</span></div>
+        <el-link :href="$router.material_list" :underline="false">更多<i class="el-icon-arrow-right el-icon--right"></i>
+        </el-link>
+    </div>
+    <el-row :gutter="20">
+        <el-col v-for="item in recommend.list" :key="item.id" :span="12">
+            <a :href="$router.material_detail + '?id=' + item.id">
+                <el-image :src="item.image" fit="cover"></el-image>
+                <div>
+                    <div>{{ item.title }}</div>
+                    <div>¥<span>{{ item.money }}</span></div>
+                    <div>{{ item.count }}人已下载</div>
+                </div>
+            </a>
+        </el-col>
+    </el-row>
+</div>

+ 20 - 0
public/pc/components/home/recommend3/index.js

xqd
@@ -0,0 +1,20 @@
+define([
+    'text!./index.html',
+    'css!./index.css'
+], function (html) {
+    return {
+        props: {
+            recommend: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            }
+        },
+        data: function () {
+            return {};
+        },
+        methods: {},
+        template: html
+    };
+});

+ 0 - 0
public/pc/components/home/recommend4/index.css


+ 32 - 0
public/pc/components/home/recommend4/index.html

xqd
@@ -0,0 +1,32 @@
+<div class="news-push">
+    <div class="title">
+        <div>新闻资讯<span>探索更多未知可能</span></div>
+        <el-link :href="$router.news_list" :underline="false">更多<i class="el-icon-arrow-right el-icon--right"></i></el-link>
+    </div>
+    <div class="content">
+        <div style="padding-left: 0;">
+            <a v-for="item in recommend.list" :key="item.id" :href="$router.news_detail + '?id=' + item.id">
+                <el-image :src="item.image_input" fit="cover">
+                    <div slot="error" class="image-slot">
+                        <i class="el-icon-picture-outline"></i>
+                    </div>
+                </el-image>
+                <div>
+                    <div>
+                        <div>{{ item.title }}</div>
+                        <div>{{ item.synopsis }}</div>
+                    </div>
+                    <div><span><i class="el-icon-view"></i>{{ item.visit }}</span><span><i class="el-icon-time"></i>{{ item.add_time }}</span></div>
+                </div>
+            </a>
+        </div>
+        <div>
+            <div>最新资讯</div>
+            <div>
+                <a v-for="(item, index) in articleList" :key="item.id" :href="$router.news_detail + '?id=' + item.id">
+                    <span>{{ index + 1 }}</span>{{ item.title }}
+                </a>
+            </div>
+        </div>
+    </div>
+</div>

+ 28 - 0
public/pc/components/home/recommend4/index.js

xqd
@@ -0,0 +1,28 @@
+define([
+    'text!./index.html',
+    'css!./index.css'
+], function(html) {
+    return {
+        props: {
+            recommend: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            },
+            articleList: {
+                type: Array,
+                default: function () {
+                    return [];
+                }
+            }
+        },
+        data: function () {
+            return {};
+        },
+        methods: {
+
+        },
+        template: html
+    };
+});

+ 70 - 0
public/pc/components/home/recommend5/index.html

xqd
@@ -0,0 +1,70 @@
+<el-row :gutter="24" class="system-push">
+    <!-- 课程排行 -->
+    <el-col :span="8">
+        <div class="rank">
+            <div class="title">
+                <div>课程<span>排行</span><span>热门课程,好评推荐</span></div>
+                <el-link :href="$router.special_cate" :underline="false" icon="el-icon-arrow-right"></el-link>
+            </div>
+            <div class="content">
+                <a v-for="item in rankList" :key="item.id" :href="(item.is_light ? $router.single_detail : $router.special_detail) + '?id=' + item.id">
+                    <el-image :src="item.image" fit="cover">
+                        <div slot="error" class="image-slot">
+                            <i class="el-icon-picture-outline"></i>
+                        </div>
+                    </el-image>
+                    <div>
+                        <div>{{ item.title }}</div>
+                        <div>{{ item.browse_count }}人已学</div>
+                    </div>
+                </a>
+            </div>
+        </div>
+    </el-col>
+    <!-- 好课推荐 -->
+    <el-col v-if="goodList.length" :span="8">
+        <div class="hot">
+            <div class="title">
+                <div>好课<span>推荐</span><span>热门课程,好评推荐</span></div>
+                <el-link :href="$router.special_cate" :underline="false" icon="el-icon-arrow-right"></el-link>
+            </div>
+            <div class="swiper-container">
+                <div class="swiper-wrapper">
+                    <div v-for="item in goodList" :key="item.id" class="swiper-slide">
+                        <a :href="(item.is_light ? $router.single_detail : $router.special_detail) + '?id=' + item.id">
+                            <img :src="item.image" :alt="item.title">
+                            <div>
+                                <div>{{ item.title }}</div>
+                                <div v-if="item.pay_type">¥<span>{{ item.money }}</span></div>
+                                <div v-else class="free">免费</div>
+                            </div>
+                        </a>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </el-col>
+    <!-- 新课首推 -->
+    <el-col :span="8">
+        <div class="new">
+            <div class="title">
+                <div>新课<span>首推</span><span>优质好课等你来选</span></div>
+                <el-link :href="$router.special_cate" :underline="false" icon="el-icon-arrow-right"></el-link>
+            </div>
+            <div class="content">
+                <a v-for="item in newList" :key="item.id" :href="(item.is_light ? $router.single_detail : $router.special_detail) + '?id=' + item.id">
+                    <el-image :src="item.image" fit="cover">
+                        <div slot="error" class="image-slot">
+                            <i class="el-icon-picture-outline"></i>
+                        </div>
+                    </el-image>
+                    <div>
+                        <div>{{ item.title }}</div>
+                        <div v-if="item.pay_type">¥<span>{{ item.money }}</span></div>
+                        <div v-else>免费</div>
+                    </div>
+                </a>
+            </div>
+        </div>
+    </el-col>
+</el-row>

+ 59 - 0
public/pc/components/home/recommend5/index.js

xqd
@@ -0,0 +1,59 @@
+define([
+    'text!./index.html',
+    'swiper'
+], function(html, Swiper) {
+    return {
+        props: {
+            recommend: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            },
+            rankList: {
+                type: Array,
+                default: function () {
+                    return [];
+                }
+            },
+            goodList: {
+                type: Array,
+                default: function () {
+                    return [];
+                }
+            },
+            newList: {
+                type: Array,
+                default: function () {
+                    return [];
+                }
+            }
+        },
+        watch: {
+            goodList: function () {
+                var vm = this;
+                this.$nextTick(function () {
+                    this.swiper = new Swiper('.swiper-container', {
+                        slidesPerView: 'auto',
+                        spaceBetween: 10,
+                        centeredSlides: true,
+                        initialSlide: 1,
+                        autoplay: true,
+                        loop: true,
+                        // loopedSlides: 4,
+                        observer: true,
+                        observeParents: true,
+                        observeSlideChildren: true
+                    });
+                });
+            }
+        },
+        mounted: function () {
+            
+        },
+        methods: {
+
+        },
+        template: html
+    };
+});

+ 115 - 0
public/pc/components/home/recommend7/index.css

xqd
@@ -0,0 +1,115 @@
+.recommend6 .recommend-head {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: end;
+    -webkit-align-items: flex-end;
+    -moz-box-align: end;
+    -ms-flex-align: end;
+    align-items: flex-end;
+    margin-top: 70px;
+}
+
+.recommend6 .recommend-head .title {
+    font-weight: bold;
+    font-size: 24px;
+    line-height: 31px;
+    color: #282828;
+}
+
+.recommend6 .recommend-head .subtitle {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+    -moz-box-flex: 1;
+    -ms-flex: 1;
+    flex: 1;
+    margin-left: 10px;
+    font-size: 16px;
+    line-height: 21px;
+    color: #999999;
+}
+
+.recommend6 .recommend-body {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-flex-wrap: wrap;
+    -ms-flex-wrap: wrap;
+    flex-wrap: wrap;
+    -webkit-align-content: flex-start;
+    -ms-flex-line-pack: start;
+    align-content: flex-start;
+    margin: 30px -24px -24px 0;
+}
+
+.recommend6 .recommend-body .item {
+    width: 384px;
+    padding: 20px 20px 17px;
+    border-radius: 8px;
+    margin: 0 24px 24px 0;
+    background-color: #FFFFFF;
+}
+
+.recommend6 .recommend-body .item:hover {
+    -webkit-box-shadow: 0 3px 20px rgba(0, 0, 0, 0.07);
+    box-shadow: 0 3px 20px rgba(0, 0, 0, 0.07);
+}
+
+.recommend6 .recommend-body .title {
+    overflow: hidden;
+    white-space: nowrap;
+    -o-text-overflow: ellipsis;
+    text-overflow: ellipsis;
+    font-size: 18px;
+    line-height: 24px;
+    color: #282828;
+}
+
+.recommend6 .recommend-body .group {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+    -moz-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    margin-top: 39px;
+}
+
+.recommend6 .recommend-body .total {
+    font-size: 16px;
+    color: #FF6B00;
+}
+
+.recommend6 .recommend-body .people {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+    -moz-box-flex: 1;
+    -ms-flex: 1;
+    flex: 1;
+    margin-left: 20px;
+    font-size: 14px;
+    color: #999999;
+}
+
+.recommend6 .recommend-body .button {
+    height: 30px;
+    padding: 0 17px;
+    border-radius: 15px;
+    background-color: #F2F8FF;
+    font-size: 14px;
+    line-height: 30px;
+    color: #2C8EFF;
+}
+
+.recommend6 .recommend-body .iconfont {
+    margin-right: 5px;
+    font-size: 14px;
+}

+ 17 - 0
public/pc/components/home/recommend7/index.html

xqd
@@ -0,0 +1,17 @@
+<div class="recommend6">
+    <div class="recommend-head">
+        <div class="title">{{ recommend.title }}</div>
+        <div class="subtitle">{{ recommend.explain }}</div>
+        <el-link :href="$router.question_category" :underline="false">更多<i class="el-icon-arrow-right el-icon--right"></i></el-link>
+    </div>
+    <div class="recommend-body">
+        <a v-for="item in recommend.list" :key="item.id" :href="$router.problem_index + '?id=' + item.id" class="item">
+            <div class="title">{{ item.title }}</div>
+            <div class="group">
+                <div class="total">共{{ item.item_number }}题</div>
+                <div class="people">{{ item.fake_sales + item.answer }}人已答题</div>
+                <div class="button"><i class="iconfont icon-19-lianxi"></i>练习</div>
+            </div>
+        </a>
+    </div>
+</div>

+ 17 - 0
public/pc/components/home/recommend7/index.js

xqd
@@ -0,0 +1,17 @@
+define([
+    'require',
+    'text!./index.html',
+    'css!./index.css'
+], function (require, html) {
+    return {
+        props: {
+            recommend: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            }
+        },
+        template: html
+    };
+});

+ 127 - 0
public/pc/components/home/recommend8/index.css

xqd
@@ -0,0 +1,127 @@
+.recommend7 .recommend-head {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: end;
+    -webkit-align-items: flex-end;
+    -moz-box-align: end;
+    -ms-flex-align: end;
+    align-items: flex-end;
+    margin-top: 70px;
+}
+
+.recommend7 .recommend-head .title {
+    font-weight: bold;
+    font-size: 24px;
+    line-height: 31px;
+    color: #282828;
+}
+
+.recommend7 .recommend-head .subtitle {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+    -moz-box-flex: 1;
+    -ms-flex: 1;
+    flex: 1;
+    margin-left: 10px;
+    font-size: 16px;
+    line-height: 21px;
+    color: #999999;
+}
+
+.recommend7 .recommend-body {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-flex-wrap: wrap;
+    -ms-flex-wrap: wrap;
+    flex-wrap: wrap;
+    -webkit-align-content: flex-start;
+    -ms-flex-line-pack: start;
+    align-content: flex-start;
+    margin: 30px -20px -20px 0;
+}
+
+.recommend7 .recommend-body .item {
+    width: 285px;
+    border-radius: 8px;
+    margin: 0 20px 20px 0;
+    background-color: #FFFFFF;
+}
+
+.recommend7 .recommend-body .item:hover {
+    -webkit-box-shadow: 0 2px 15px rgba(79, 109, 143, 0.15);
+    box-shadow: 0 2px 15px rgba(79, 109, 143, 0.15);
+}
+
+.recommend7 .recommend-body .image {
+    display: block;
+    width: 285px;
+    height: 160px;
+    border-radius: 8px 8px 0 0;
+}
+
+.recommend7 .recommend-body .title {
+    padding: 15px 20px 0;
+    overflow: hidden;
+    white-space: nowrap;
+    -o-text-overflow: ellipsis;
+    text-overflow: ellipsis;
+    font-size: 18px;
+    line-height: 24px;
+    color: #282828;
+}
+
+.recommend7 .recommend-body .group {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+    -moz-box-pack: justify;
+    -ms-flex-pack: justify;
+    justify-content: space-between;
+    -webkit-box-align: end;
+    -webkit-align-items: flex-end;
+    -moz-box-align: end;
+    -ms-flex-align: end;
+    align-items: flex-end;
+    padding: 14px 20px 28px;
+}
+
+.recommend7 .recommend-body .money {
+    font-size: 16px;
+    color: #FF6B00;
+}
+
+.recommend7 .recommend-body .number {
+    font-size: 24px;
+    line-height: 31px;
+}
+
+.recommend7 .recommend-body .people {
+    margin-top: 8px;
+    font-size: 14px;
+    color: #999999;
+}
+
+.recommend7 .recommend-body .button {
+    height: 34px;
+    padding: 0 19px;
+    border-radius: 17px;
+    background-color: #F2F8FF;
+    font-size: 16px;
+    line-height: 34px;
+    color: #2C8EFF;
+}
+
+.recommend7 .recommend-body .iconfont {
+    margin-right: 6px;
+    font-size: 15px;
+}

+ 20 - 0
public/pc/components/home/recommend8/index.html

xqd
@@ -0,0 +1,20 @@
+<div class="recommend7">
+    <div class="recommend-head">
+        <div class="title">{{ recommend.title }}</div>
+        <div class="subtitle">{{ recommend.explain }}</div>
+        <el-link :href="$router.question_category + '?type=2'" :underline="false">更多<i class="el-icon-arrow-right el-icon--right"></i></el-link>
+    </div>
+    <div class="recommend-body">
+        <a v-for="item in recommend.list" :key="item.id" :href="$router.question_index + '?id=' + item.id" class="item">
+            <img :src="item.image" class="image">
+            <div class="title">{{ item.title }}</div>
+            <div class="group">
+                <div>
+                    <div class="money">¥<span class="number">{{ item.money }}</span></div>
+                    <div class="people">{{ item.fake_sales + item.answer }}人已下载</div>
+                </div>
+                <div class="button"><i class="iconfont icon-19-lianxi"></i>答题</div>
+            </div>
+        </a>
+    </div>
+</div>

+ 16 - 0
public/pc/components/home/recommend8/index.js

xqd
@@ -0,0 +1,16 @@
+define([
+    'text!./index.html',
+    'css!./index.css'
+], function (html) {
+    return {
+        props: {
+            recommend: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            }
+        },
+        template: html
+    };
+});

+ 131 - 0
public/pc/components/my/account/index.css

xqd
@@ -0,0 +1,131 @@
+.my-account {
+    padding-left: 54px;
+    background-color: #fff;
+}
+
+.my-account .title {
+    padding-top: 20px;
+    padding-bottom: 16px;
+    padding-left: 8px;
+    font-size: 18px;
+    color: #282828;
+}
+
+.my-account .content {
+    border-top: 1px solid #ececec;
+}
+
+.my-account .wrapper-title {
+    padding-top: 34px;
+    padding-left: 10px;
+    padding-bottom: 12px;
+    font-size: 18px;
+    color: #282828;
+}
+
+.my-account .wrapper-content {
+    padding-right: 46px;
+}
+
+.my-account .item {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    padding: 26px 8px 26px 16px;
+    border-bottom: 1px dashed #ddd;
+    font-size: 14px;
+    color: #282828;
+}
+
+.my-account .item:not(:first-child) {
+    height: 70px;
+}
+
+.my-account .item > div:first-child {
+    width: 105px;
+    color: #777;
+}
+
+.my-account .item > div:nth-child(2) {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    padding-right: 15px;
+    padding-left: 15px;
+}
+
+.my-account .item > div.el-input {
+    padding-right: 0;
+    padding-left: 0;
+}
+
+.my-account .el-input__inner {
+    -webkit-transition: 0.3s;
+    -o-transition: 0.3s;
+    -moz-transition: 0.3s;
+    transition: 0.3s;
+    font-size: 14px;
+    color: #282828;
+}
+
+.my-account .el-input__inner:-moz-read-only {
+    border-color: transparent;
+}
+
+.my-account .el-input__inner:read-only {
+    border-color: transparent;
+}
+
+.my-account .item .el-button {
+    margin-left: 50px;
+    color: #2c8eff;
+}
+
+.my-account .item:first-child .el-button {
+    -webkit-align-self: flex-end;
+        -ms-flex-item-align: end;
+            align-self: flex-end;
+}
+
+.my-account .el-upload-dragger {
+    width: 80px;
+    height: 80px;
+    border-radius: 50%;
+    font-size: 0;
+    line-height: 80px;
+}
+
+.my-account .el-upload-dragger img {
+    width: 100%;
+    height: 100%;
+}
+
+.my-account .el-upload-dragger .avatar-uploader-icon {
+    vertical-align: middle;
+    font-size: 28px;
+    color: #d9d9d9;
+}
+
+.my-account .bottom {
+    padding-top: 38px;
+    padding-right: 44px;
+    padding-bottom: 43px;
+    text-align: right;
+}
+
+.my-account .bottom .el-button {
+    padding: 11px 48px;
+    border-color: #2c8eff;
+    background-color: #2c8eff;
+    font-size: 16px;
+    color: #fff;
+}

+ 46 - 0
public/pc/components/my/account/index.html

xqd
@@ -0,0 +1,46 @@
+<div class="my-account">
+    <div class="title">账户管理</div>
+    <div class="content">
+        <div class="wrapper">
+            <div class="wrapper-title">我的信息</div>
+            <div class="wrapper-content">
+                <div class="item">
+                    <div class="item-title">我的头像:</div>
+                    <el-upload ref="upload" :show-file-list="false" :before-upload="handleBeforeUpload" :on-success="handleSuccess" action="/web/auth_api/upload" accept="image/jpg, image/jpeg, image/png" drag @click.native="handleLogin">
+                        <img v-if="userInfo" :src="avatar">
+                        <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+                    </el-upload>
+                    <el-button type="text" @click="updateAvatar">修改</el-button>
+                </div>
+                <div class="item">
+                    <div class="item-title">我的昵称:</div>
+                    <el-input v-model="nickname" :readonly="nicknameReadonly"></el-input>
+                    <!-- <el-button type="text" @click="nicknameReadonly = !nicknameReadonly">修改</el-button> -->
+                    <el-button type="text" @click="handleUpdate">修改</el-button>
+                </div>
+                <div v-if="userInfo.phone" class="item">
+                    <div class="item-title">手机号:</div>
+                    <div>{{ userInfo.phone | phoneEncrypt }}</div>
+                    <el-button type="text" @click="accountOpen(true)">修改</el-button>
+                </div>
+                <div class="item">
+                    <div class="item-title">我的ID:</div>
+                    <div>{{ userInfo.uid }}</div>
+                </div>
+            </div>
+        </div>
+        <div v-if="userInfo.phone" class="wrapper">
+            <div class="wrapper-title">密码设置</div>
+            <div class="wrapper-content">
+                <div class="item">
+                    <div>我的密码</div>
+                    <div>**********</div>
+                    <el-button type="text" @click="accountOpen(false)">修改</el-button>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="bottom">
+        <el-button round @click="save">保存</el-button>
+    </div>
+</div>

+ 103 - 0
public/pc/components/my/account/index.js

xqd
@@ -0,0 +1,103 @@
+define([
+    'store/index',
+    'api/my',
+    'text!./index.html',
+    'css!./index.css'
+], function(store, myApi, html) {
+    return {
+        filters: {
+            phoneEncrypt: function (phone) {
+                if (!phone) {
+                    return '';
+                }
+                return phone.replace(/(\d{3})\d*(\d{4})/, '$1****$2');
+            }
+        },
+        inject: ['getUserInfo', 'logout', 'getUserLogin'],
+        props: {
+            isLogin: {
+                type: Boolean,
+                default: false
+            },
+            userInfo: {
+                type: Object,
+                default: function () {
+                    return {};
+                }
+            }
+        },
+        data: function () {
+            return {
+                nicknameReadonly: true,
+                avatar: '',
+                nickname: ''
+            };
+        },
+        watch: {
+            'userInfo.avatar': function () {
+                this.avatar = this.userInfo.avatar;
+            },
+            'userInfo.nickname': function () {
+                this.nickname = this.userInfo.nickname;
+            }
+        },
+        methods: {
+            handleBeforeUpload: function (file) {
+                if (file.type == 'image/jpeg') {
+                    return true;
+                }
+                if (file.type == 'image/jpg') {
+                    return true;
+                }
+                if (file.type == 'image/png') {
+                    return true;
+                }
+                this.$message.error('上传头像图片只能是 JPEG、JPG、PNG 格式!');
+                return false;
+            },
+            handleSuccess: function (res) {
+                var vm = this;
+                if (typeof res == 'string') {
+                    return vm.$message.error(res);
+                }
+                if (res.code == 400) {
+                    vm.$message.error(res.msg)
+                    return;
+                }
+                vm.avatar = res.data.url;
+                vm.$message.success(res.msg);
+            },
+            // 点击保存
+            save: function () {
+                var vm = this;
+                myApi.saveUserInfo({
+                    avatar: this.avatar || this.userInfo.avatar,
+                    nickname: this.nickname
+                }).then(function (res) {
+                    vm.$message.success(res.msg);
+                    vm.nicknameReadonly = true;
+                    vm.getUserInfo();
+                }).catch(function (err) {
+                    window.location.replace(vm.$router.home);
+                });
+            },
+            // 点击头像的修改
+            updateAvatar: function () {
+                this.$refs.upload.$refs['upload-inner'].$refs.input.click();
+            },
+            accountOpen: function (value) {
+                this.getUserLogin();
+                store.setIsAccountAction(value);
+                store.setAccountAction(true);
+            },
+            handleLogin: function () {
+                this.getUserLogin();
+            },
+            handleUpdate: function () {
+                this.getUserLogin();
+                this.nicknameReadonly = !this.nicknameReadonly;
+            }
+        },
+        template: html
+    };
+});

+ 160 - 0
public/pc/components/my/activity/index.css

xqd
@@ -0,0 +1,160 @@
+.my-activity .el-tabs .el-tabs__header {
+    padding-right: 0;
+    padding-left: 54px;
+}
+
+.my-activity .el-tabs__header .el-tabs__nav-wrap::after {
+    display: block;
+    height: 1px;
+    background-color: #ECECEC;
+}
+
+.my-activity .el-tabs__nav .el-tabs__item {
+    height: 60px;
+    padding-right: 25px;
+    padding-left: 25px;
+    line-height: 60px;
+    color: #999999;
+}
+
+.my-activity .el-tabs.el-tabs--top .el-tabs__item.is-top:nth-child(2) {
+    padding-left: 0;
+}
+
+.my-activity .el-tabs__content {
+    padding-left: 54px;
+}
+
+.my-activity .el-tab-pane {
+    padding-right: 46px;
+}
+
+.my-activity .item {
+    display: block;
+    padding: 30px 0;
+    border-top: 1px dashed #D0D0D0;
+}
+
+.my-activity .item:first-child {
+    border-top: 0;
+}
+
+.my-activity .item-head {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    font-size: 14px;
+    line-height: 19px;
+    color: #666666;
+}
+
+.my-activity .item-code {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+}
+
+.my-activity .item-code span {
+    color: #FF6B00;
+}
+
+.my-activity .item-status {
+    color: #999999;
+}
+
+.my-activity .item-status.no {
+    color: #2C8EFF;
+}
+
+.my-activity .item-body {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    margin-top: 20px;
+}
+
+.my-activity .el-image {
+    width: 202px;
+    height: 114px;
+    border-radius: 8px;
+}
+
+.my-activity .item-text {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    padding-left: 20px;
+}
+
+.my-activity .item-title {
+    font-size: 18px;
+    line-height: 24px;
+    color: #282828;
+}
+
+.my-activity .item-attr {
+    margin-top: 20px;
+    font-size: 14px;
+    line-height: 19px;
+    color: #666666;
+}
+
+.my-activity .item-attr div {
+    margin-top: 6px;
+}
+
+.my-activity .item-attr div:first-child {
+    margin-top: 0;
+}
+
+.my-activity .item-attr .iconfont {
+    margin-right: 6px;
+    font-size: 13px;
+    color: #2C8EFF;
+}
+
+.my-activity .item-info {
+    font-size: 14px;
+    line-height: 19px;
+    text-align: right;
+    color: #999999;
+}
+
+.my-activity .item-money {
+    margin-bottom: 10px;
+    font-size: 12px;
+    line-height: 26px;
+    color: #FF6B00;
+}
+
+.my-activity .item-money.free {
+    font-size: 18px;
+    line-height: 24px;
+}
+
+.my-activity .item-money span {
+    font-size: 20px;
+}
+
+.my-activity .el-empty {
+    padding: 50px 0;
+}
+
+.my-activity .item-people {
+    font-size: 14px;
+    line-height: 19px;
+    color: #FF6B00;
+}

+ 79 - 0
public/pc/components/my/activity/index.html

xqd
@@ -0,0 +1,79 @@
+<div class="my-activity">
+    <el-tabs  v-model="active" @tab-click="handleClick">
+        <el-tab-pane label="全部" name="0">
+            <a v-for="item in list0" class="item" href="javascript:">
+                <div class="item-head">
+                    <div class="item-code">核销码:<span>{{ item.code }}</span></div>
+                    <div :class="{ no: !item.status }" class="item-status no">{{ item.status ? '已核销' : '待核销' }}</div>
+                </div>
+                <div class="item-body">
+                    <el-image :src="item.image"></el-image>
+                    <div class="item-text">
+                        <div class="item-title">{{ item.title }}</div>
+                        <div class="item-attr">
+                            <div><i class="iconfont iconhuodongshijian"></i>活动时间:{{ item.start_time | timeFormat }}~{{ item.end_time | timeFormat }}</div>
+                            <div><i class="iconfont iconhuodongdizhi"></i>活动地址:{{ item.province }}{{ item.city }}{{ item.district }}{{ item.detail }}</div>
+                        </div>
+                    </div>
+                    <div class="item-info">
+                        <div v-if="item.price == '0.00'" class="item-money free">免费</div>
+                        <div v-else class="item-money">¥<span>{{ item.pay_price }}</span></div>
+                        <div class="item-people">{{ item.upUnmber }}人参加</div>
+                    </div>
+                </div>
+            </a>
+            <el-pagination :page-size="limit" :total="total0" :current-page="page0" layout="prev, pager, next" prev-text="上一页" next-text="下一页" hide-on-single-page @current-change="activitySignInList0"></el-pagination>
+            <el-empty v-if="!list0.length" :image-size="200"></el-empty>
+        </el-tab-pane>
+        <el-tab-pane label="待核销" name="1">
+            <a v-for="item in list1" class="item" href="javascript:">
+                <div class="item-head">
+                    <div class="item-code">核销码:<span>{{ item.code }}</span></div>
+                    <div class="item-status no">待核销</div>
+                </div>
+                <div class="item-body">
+                    <el-image :src="item.image"></el-image>
+                    <div class="item-text">
+                        <div class="item-title">{{ item.title }}</div>
+                        <div class="item-attr">
+                            <div><i class="iconfont iconhuodongshijian"></i>活动时间:{{ item.start_time | timeFormat }}~{{ item.end_time | timeFormat }}</div>
+                            <div><i class="iconfont iconhuodongdizhi"></i>活动地址:{{ item.province }}{{ item.city }}{{ item.district }}{{ item.detail }}</div>
+                        </div>
+                    </div>
+                    <div class="item-info">
+                        <div class="item-money">¥<span>{{ item.pay_price }}</span></div>
+                        <div v-if="item.price == '0.00'" class="item-money free">免费</div>
+                        <div class="item-people">{{ item.upUnmber }}人参加</div>
+                    </div>
+                </div>
+            </a>
+            <el-pagination :page-size="limit" :total="total1" :current-page="page1" layout="prev, pager, next" prev-text="上一页" next-text="下一页" hide-on-single-page @current-change="activitySignInList1"></el-pagination>
+            <el-empty v-if="!list1.length" :image-size="200"></el-empty>
+        </el-tab-pane>
+        <el-tab-pane label="已核销" name="2">
+            <a v-for="item in list2" class="item" href="javascript:">
+                <div class="item-head">
+                    <div class="item-code">核销码:<span>{{ item.code }}</span></div>
+                    <div class="item-status">已核销</div>
+                </div>
+                <div class="item-body">
+                    <el-image :src="item.image"></el-image>
+                    <div class="item-text">
+                        <div class="item-title">{{ item.title }}</div>
+                        <div class="item-attr">
+                            <div><i class="iconfont iconhuodongshijian"></i>活动时间:{{ item.start_time | timeFormat }}~{{ item.end_time | timeFormat }}</div>
+                            <div><i class="iconfont iconhuodongdizhi"></i>活动地址:{{ item.province }}{{ item.city }}{{ item.district }}{{ item.detail }}</div>
+                        </div>
+                    </div>
+                    <div class="item-info">
+                        <div v-if="item.price == '0.00'" class="item-money free">免费</div>
+                        <div v-else class="item-money">¥<span>{{ item.pay_price }}</span></div>
+                        <div class="item-people">{{ item.upUnmber }}人参加</div>
+                    </div>
+                </div>
+            </a>
+            <el-pagination :page-size="limit" :total="total2" :current-page="page2" layout="prev, pager, next" prev-text="上一页" next-text="下一页" hide-on-single-page @current-change="activitySignInList2"></el-pagination>
+            <el-empty v-if="!list2.length" :image-size="200"></el-empty>
+        </el-tab-pane>
+    </el-tabs>
+</div>

+ 91 - 0
public/pc/components/my/activity/index.js

xqd
@@ -0,0 +1,91 @@
+define([
+    'api/activity',
+    'moment',
+    'text!./index.html',
+    'css!./index.css',
+    'css!../../../../wap/first/zsff/iconfont/iconfont.css',
+], function(activityApi, moment, html) {
+    return {
+        props: {
+            activeName: {
+                type: String,
+                default: 'activity'
+            },
+            isLogin: {
+                type: Boolean,
+                default: false
+            }
+        },
+        filters: {
+            timeFormat: function (value) {
+                return moment(value * 1000).format('YYYY-MM-DD HH:mm');
+            }
+        },
+        data: function () {
+            return {
+                active: '0',
+                limit: 10,
+                page0: 1,
+                page1: 1,
+                page2: 1,
+                total0: 10,
+                total1: 10,
+                total2: 10,
+                list0: [],
+                list1: [],
+                list2: []
+            };
+        },
+        watch: {
+            isLogin: function (val) {
+                if (val) {
+                    this.activitySignInList0();
+                    this.activitySignInList1();
+                    this.activitySignInList2();
+                }
+            }
+        },
+        methods: {
+            activitySignInList0: function () {
+                var vm = this;
+                activityApi.activitySignInList({
+                    page: this.page0,
+                    limit: this.limit,
+                    navActive: 0
+                }).then(function (res) {
+                    var data = res.data;
+                    vm.list0 = data.list;
+                    vm.total0 = data.count;
+                });
+            },
+            activitySignInList1: function () {
+                var vm = this;
+                activityApi.activitySignInList({
+                    page: this.page1,
+                    limit: this.limit,
+                    navActive: 1
+                }).then(function (res) {
+                    var data = res.data;
+                    vm.list1 = data.list;
+                    vm.total1 = data.count;
+                });
+            },
+            activitySignInList2: function () {
+                var vm = this;
+                activityApi.activitySignInList({
+                    page: this.page2,
+                    limit: this.limit,
+                    navActive: 2
+                }).then(function (res) {
+                    var data = res.data;
+                    vm.list2 = data.list;
+                    vm.total2 = data.count;
+                });
+            },
+            handleClick: function () {
+
+            }
+        },
+        template: html
+    };
+});

+ 119 - 0
public/pc/components/my/balance/index.css

xqd
@@ -0,0 +1,119 @@
+.my-balance {
+    padding-right: 55px;
+    padding-left: 55px;
+}
+
+.el-pagination {
+    padding: 50px 0 !important;
+    text-align: center;
+}
+
+.my-balance .total ul {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    padding-top: 65px;
+    padding-bottom: 35px;
+    font-size: 14px;
+    color: #969696;
+}
+
+.my-balance .total li ~ li {
+    margin-left: 170px;
+}
+
+.my-balance .total li > div:last-child {
+    margin-top: 15px;
+    font-weight: bold;
+    font-size: 32px;
+    color: #282828;
+}
+
+.my-balance .el-tabs.el-tabs--top {
+    margin-top: 0;
+}
+
+.my-balance .el-tabs__header.is-top {
+    padding-right: 0;
+    padding-left: 0;
+}
+
+.my-balance .el-tabs__nav-wrap.is-top::after {
+    display: block;
+    height: 1px;
+    background-color: #ececec;
+}
+
+.my-balance .el-tabs__item.is-top {
+    padding-right: 25px;
+    padding-left: 25px;
+    color: #999;
+}
+
+.my-balance .el-tabs.el-tabs--top .el-tabs__item.is-top:nth-child(2) {
+    padding-left: 25px;
+}
+
+.my-balance .el-tabs.el-tabs--top .el-tabs__item.is-top:last-child {
+    padding-right: 25px;
+}
+
+.my-balance .el-tabs.el-tabs--top .el-tab-pane > ul > li {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    height: 86px;
+    padding-right: 10px;
+    padding-left: 10px;
+    border-bottom: 1px dashed #d0d0d0;
+    font-size: 14px;
+    color: #969696;
+}
+
+.my-balance .el-tabs.el-tabs--top li > div > div:first-child {
+    margin-bottom: 10px;
+    font-size: 16px;
+    color: #282828;
+}
+
+.my-balance .el-tabs.el-tabs--top li > div:last-child {
+    font-weight: bold;
+    font-size: 16px;
+    color: #2c8eff;
+}
+
+.my-balance .el-tabs.el-tabs--top li > .red:last-child {
+    color: #FF6B00;
+}
+
+.my-balance > div:last-child {
+    padding-top: 41px;
+    padding-bottom: 53px;
+    font-size: 12px;
+    color: #969696;
+}
+
+.my-balance .el-tab-pane .el-icon-warning {
+    margin-right: 8px;
+    font-size: 14px;
+    color: #ff6b00;
+}
+
+.my-balance .empty {
+    height: 488px;
+    background: url("../../../images/empty7.png") center/274px no-repeat;
+}

+ 60 - 0
public/pc/components/my/balance/index.html

xqd
@@ -0,0 +1,60 @@
+<div class="my-balance">
+    <div class="total">
+        <ul>
+            <li>
+                <div>账户可用余额(元):</div>
+                <div>{{ balance }}</div>
+            </li>
+            <li>
+                <div>累计充值(元):</div>
+                <div>{{ recharge }}</div>
+            </li>
+            <li>
+                <div>累计消费(元):</div>
+                <div>{{ consumption }}</div>
+            </li>
+        </ul>
+    </div>
+    <el-tabs v-if="activeName === 'balance'" v-model="active" @tab-click="handleClick">
+        <el-tab-pane label="全部" name="first">
+            <ul v-if="balanceList1.length">
+                <li v-for="(item, index) in balanceList1" :key="index">
+                    <div>
+                        <div>{{ item.title }}</div>
+                        <div>{{ item.add_time }}</div>
+                    </div>
+                    <div :class="{ red: item.pm }">{{ item.pm ? '+' : '-' }}¥{{ item.number }}</div>
+                </li>
+            </ul>
+            <div v-else class="empty"></div>
+            <el-pagination :page-size="limit" :total="total1" :current-page="page1" layout="prev, pager, next" prev-text="上一页" next-text="下一页" hide-on-single-page @current-change="get_user_balance_list1"></el-pagination>
+        </el-tab-pane>
+        <el-tab-pane label="收入明细" name="second">
+            <ul v-if="balanceList2.length">
+                <li v-for="(item, index) in balanceList2" :key="index">
+                    <div>
+                        <div>{{ item.title }}</div>
+                        <div>{{ item.add_time }}</div>
+                    </div>
+                    <div :class="{ red: item.pm }">{{ item.pm ? '+' : '-' }}¥{{ item.number }}</div>
+                </li>
+            </ul>
+            <div v-else class="empty"></div>
+            <el-pagination :page-size="limit" :total="total2" :current-page="page2" layout="prev, pager, next" prev-text="上一页" next-text="下一页" hide-on-single-page @current-change="get_user_balance_list2"></el-pagination>
+        </el-tab-pane>
+        <el-tab-pane label="支出明细" name="third">
+            <ul v-if="balanceList3.length">
+                <li v-for="(item, index) in balanceList3" :key="index">
+                    <div>
+                        <div>{{ item.title }}</div>
+                        <div>{{ item.add_time }}</div>
+                    </div>
+                    <div>{{ item.pm ? '+' : '-' }}¥{{ item.number }}</div>
+                </li>
+            </ul>
+            <div v-else class="empty"></div>
+            <el-pagination :page-size="limit" :total="total3" :current-page="page3" layout="prev, pager, next" prev-text="上一页" next-text="下一页" hide-on-single-page @current-change="get_user_balance_list3"></el-pagination>
+        </el-tab-pane>
+    </el-tabs>
+    <div><i class="el-icon-warning"></i>系统仅显示您两年之内的余额明细,更早的余额明细不再显示</div>
+</div>

+ 101 - 0
public/pc/components/my/balance/index.js

xqd
@@ -0,0 +1,101 @@
+define([
+    'api/auth',
+    'text!./index.html',
+    'css!./index.css'
+], function(authApi, html) {
+    return {
+        props: {
+            activeName: {
+                type: String,
+                default: 'balance'
+            },
+            isLogin: {
+                type: Boolean,
+                default: false
+            }
+        },
+        data: function () {
+            return {
+                balance: '',
+                consumption: '',
+                recharge: '',
+                active: 'first',
+                page1: 1,
+                page2: 1,
+                page3: 1,
+                limit: 20,
+                balanceList1: [],
+                balanceList2: [],
+                balanceList3: [],
+                total1: 0,
+                total2: 0,
+                total3: 0
+            };
+        },
+        watch: {
+            isLogin: function (value) {
+                if (value) {
+                    this.get_user_balance();
+                    this.get_user_balance_list1();
+                    this.get_user_balance_list2();
+                    this.get_user_balance_list3();
+                }
+            }
+        },
+        methods: {
+            get_user_balance: function () {
+                var vm = this;
+                authApi.get_user_balance({}).then(function (res) {
+                    var data = res.data;
+                    vm.balance = data.balance;
+                    vm.consumption = data.consumption;
+                    vm.recharge = data.recharge;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            get_user_balance_list1: function () {
+                var vm = this;
+                authApi.get_user_balance_list({
+                    page: this.page1,
+                    limit: this.limit,
+                    index: ''
+                }).then(function (res) {
+                    vm.balanceList1 = res.data.list;
+                    vm.total1 = res.data.count;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            get_user_balance_list2: function () {
+                var vm = this;
+                authApi.get_user_balance_list({
+                    page: this.page2,
+                    limit: this.limit,
+                    index: 2
+                }).then(function (res) {
+                    vm.balanceList2 = res.data.list;
+                    vm.total2 = res.data.count;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            get_user_balance_list3: function () {
+                var vm = this;
+                authApi.get_user_balance_list({
+                    page: this.page3,
+                    limit: this.limit,
+                    index: 1
+                }).then(function (res) {
+                    vm.balanceList3 = res.data.list;
+                    vm.total3 = res.data.count;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            handleClick: function (tab, event) {
+            }
+        },
+        template: html
+    };
+});

+ 559 - 0
public/pc/components/my/coin/index.css

xqd
@@ -0,0 +1,559 @@
+.my-coin {
+    padding-right: 55px;
+    padding-left: 55px;
+}
+
+.my-coin .total ul {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    padding-top: 65px;
+    padding-bottom: 35px;
+    font-size: 14px;
+    color: #969696;
+}
+
+.my-coin .total li ~ li {
+    margin-left: 170px;
+}
+
+.my-coin .total li > div:last-child {
+    margin-top: 15px;
+    font-weight: bold;
+    font-size: 32px;
+    color: #282828;
+}
+
+.my-coin .el-tabs__nav-wrap::after {
+    height: 1px;
+    background-color: #ececec;
+}
+
+.my-coin .el-tabs__item {
+    height: 50px;
+    font-size: 16px;
+    line-height: 50px;
+    color: #999;
+}
+
+.my-coin .el-tabs__item.is-active {
+    color: #2c8eff;
+}
+
+.my-coin .el-tabs__active-bar {
+    background-color: #2c8eff;
+}
+
+.my-coin .el-tabs__item:hover {
+    color: #2c8eff;
+}
+
+.my-coin .recharge .section {
+    padding-top: 40px;
+    padding-bottom: 20px;
+    font-size: 18px;
+    color: #282828;
+}
+
+.my-coin .recharge .section > div:nth-child(2) {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-flex-wrap: wrap;
+        -ms-flex-wrap: wrap;
+            flex-wrap: wrap;
+    margin-top: 30px;
+}
+
+.my-coin .recharge .section:first-child > div:last-child {
+    margin-right: -22px;
+    margin-bottom: -22px;
+}
+
+.my-coin .recharge .section:first-child label {
+    margin-right: 22px;
+    margin-bottom: 22px;
+}
+
+.my-coin .recharge .section:first-child input + div {
+    position: relative;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+       -moz-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    width: 256px;
+    height: 100px;
+    border: 1px solid #d4d4d4;
+    border-radius: 8px;
+    overflow: hidden;
+    text-align: center;
+    color: #999;
+}
+
+.my-coin .recharge .section:first-child input + div:hover {
+    border-color: #c0c4cc;
+}
+
+.my-coin .recharge .section:first-child input:checked + div {
+    border-color: #2c8eff;
+}
+
+.my-coin .recharge .section:first-child input + div div:first-child {
+    padding-left: 42px;
+    margin-bottom: 10px;
+    background: left center/32px 32px no-repeat;
+    font-size: 30px;
+    color: #282828;
+}
+
+.my-coin .recharge .section:first-child .el-icon-check {
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    z-index: 2;
+    width: 17px;
+    height: 16px;
+    background-color: #2c8eff;
+    font-size: 14px;
+    line-height: 16px;
+    text-align: center;
+    color: #fff;
+    opacity: 0;
+    -webkit-transition: 0.3s;
+    -o-transition: 0.3s;
+    -moz-transition: 0.3s;
+    transition: 0.3s;
+}
+
+.my-coin .recharge .section:first-child .el-icon-check::after {
+    content: "";
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    z-index: -1;
+    border-width: 16px 17px;
+    border-style: solid;
+    border-color: transparent #2c8eff #2c8eff transparent;
+}
+
+.my-coin .recharge .section:first-child input:checked + div .el-icon-check {
+    opacity: 1;
+}
+
+.my-coin .el-input-number {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    -webkit-align-self: flex-start;
+        -ms-flex-item-align: start;
+            align-self: flex-start;
+    margin-left: 10px;
+}
+
+.my-coin .el-input__inner {
+    height: 102px;
+    border-color: #d4d4d4;
+    border-radius: 8px;
+    font-size: 18px;
+    line-height: 102px;
+}
+
+.my-coin .el-input-number.is-controls-right .el-input-number__increase {
+    border-top-right-radius: 8px;
+}
+
+.my-coin .el-input-number.is-controls-right .el-input-number__decrease {
+    border-bottom-right-radius: 8px;
+}
+
+.my-coin .el-input-number.is-controls-right .el-input-number__decrease, .my-coin .el-input-number.is-controls-right .el-input-number__increase {
+    line-height: 51px;
+}
+
+.my-coin .recharge .section:last-child {
+    padding-bottom: 0;
+}
+
+.my-coin .recharge .section:last-child label {
+    margin-right: 20px;
+}
+
+.my-coin .recharge .section:last-child input + div {
+    position: relative;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+       -moz-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    width: 220px;
+    height: 86px;
+    border: 1px solid #d4d4d4;
+    border-radius: 8px;
+    overflow: hidden;
+    font-size: 16px;
+    line-height: 36px;
+    color: #4e4e4e;
+}
+
+.my-coin .recharge .section:last-child input + div:hover {
+    border-color: #c0c4cc;
+}
+
+.my-coin .recharge .section:last-child input:checked + div {
+    border-color: #2c8eff;
+}
+
+.my-coin .recharge .section:last-child input + div > div {
+    padding-left: 48px;
+    background: url("../../../images/alipay.png") left center/36px 36px no-repeat;
+}
+
+.my-coin .recharge .section:last-child label:first-child input + div > div {
+    background-image: url("../../../images/yue.png");
+    -o-background-size: 40px;
+       background-size: 40px;
+    line-height: 1.15;
+}
+
+.my-coin .recharge .section:last-child label:nth-child(2) input + div > div {
+    padding-left: 52px;
+    background-image: url("../../../images/wxpay.png");
+    -o-background-size: 40px 36px;
+       background-size: 40px 36px;
+}
+
+.my-coin .recharge .section:last-child > div:last-child {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    padding-top: 87px;
+    padding-bottom: 100px;
+}
+
+.my-coin .recharge .section:last-child input + div > div > div {
+    margin-top: 6px;
+    font-size: 14px;
+    color: #969696;
+}
+
+.my-coin .recharge .section:last-child > div > div:nth-child(2) {
+    margin-top: 30px;
+    font-size: 18px;
+    color: #666;
+}
+
+.my-coin .recharge .section:last-child > div > .btn-group {
+    font-size: 0;
+}
+
+.my-coin .recharge .section:last-child > div > .btn-group a {
+    display: inline-block;
+    width: 150px;
+    height: 42px;
+    border-radius: 21px;
+    margin: 50px 0 0;
+    background: #2C8EFF;
+    font-size: 16px;
+    line-height: 42px;
+    text-align: center;
+    color: #FFFFFF;
+}
+
+.my-coin .recharge .section:last-child > div > .btn-group a ~ a {
+    display: inline-block;
+    border: 1px solid #999999;
+    border-radius: 21px;
+    margin: 0 0 0 30px;
+    background: transparent;
+    font-size: 16px;
+    line-height: 40px;
+    text-align: center;
+    color: #999999;
+}
+
+.my-coin .recharge .section:last-child div > span {
+    vertical-align: sub;
+    font-weight: bold;
+    font-size: 30px;
+    color: #FF6B00;
+}
+
+.my-coin .recharge .section:last-child .el-button {
+    padding: 14px 68px;
+    border-color: #2c8eff;
+    border-radius: 23px;
+    background-color: #2c8eff;
+    font-size: 16px;
+    color: #fff;
+}
+
+.my-coin .recharge .section:last-child .el-button:focus, .my-coin .recharge .section:last-child .el-button:hover {
+    border-color: #66b1ff;
+    background-color: #66b1ff;
+}
+
+.my-coin .recharge .section:last-child .el-icon-check {
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    z-index: 2;
+    width: 17px;
+    height: 16px;
+    background-color: #2c8eff;
+    font-size: 14px;
+    line-height: 16px;
+    text-align: center;
+    color: #fff;
+    opacity: 0;
+    -webkit-transition: 0.3s;
+    -o-transition: 0.3s;
+    -moz-transition: 0.3s;
+    transition: 0.3s;
+}
+
+.my-coin .recharge .section:last-child .el-icon-check::after {
+    content: "";
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    z-index: -1;
+    border-width: 16px 17px;
+    border-style: solid;
+    border-color: transparent #2c8eff #2c8eff transparent;
+}
+
+.my-coin .recharge .section:last-child input:checked + div .el-icon-check {
+    opacity: 1;
+}
+
+.my-coin .el-tabs.el-tabs--top .el-tab-pane > ul > li {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    height: 86px;
+    padding-right: 10px;
+    padding-left: 10px;
+    border-bottom: 1px dashed #d0d0d0;
+    font-size: 14px;
+    color: #969696;
+}
+
+.my-coin .el-tabs.el-tabs--top li > div > div:first-child {
+    margin-bottom: 10px;
+    font-size: 16px;
+    color: #282828;
+}
+
+.my-coin .el-tabs.el-tabs--top li > div:last-child {
+    font-weight: bold;
+    font-size: 16px;
+    color: #2c8eff;
+}
+
+.my-coin .el-tabs.el-tabs--top li > .red:last-child {
+    color: #FF6B00;
+}
+
+.my-coin .detail-tip {
+    padding: 23px 0 46px;
+    font-size: 12px;
+    line-height: 16px;
+    color: #969696;
+}
+
+.my-coin .detail-tip .el-icon-warning {
+    margin: 0 8px 0 0;
+    font-size: 14px;
+    color: #FF6B00;
+}
+
+.my-coin .empty {
+    height: 623px;
+    background: url("../../../images/empty7.png") center/274px no-repeat;
+}
+
+.my-coin .el-tabs__content .el-tabs__active-bar {
+    display: none;
+}
+
+.my-coin .el-tabs__content .el-tabs__item {
+    min-width: 70px;
+    height: 35px;
+    padding: 0 15px;
+    border: 1px solid #D4D4D4;
+    border-radius: 4px;
+    line-height: 33px;
+    text-align: center;
+    color: #999999;
+}
+
+.my-coin .el-tabs__content .el-tabs__item ~ .el-tabs__item {
+    margin: 0 0 0 18px;
+}
+
+.my-coin .el-tabs__content .el-tabs--top .el-tabs__item.is-top:nth-child(2), .my-coin .el-tabs__content .el-tabs--top .el-tabs__item.is-top:last-child {
+    padding: 0 15px;
+}
+
+.my-coin .el-tabs__content .el-tabs__item.is-active {
+    border-color: #2C8EFF;
+}
+
+.input-number-label {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    width: 534px;
+    /* height: 100px; */
+}
+
+.input-number-label span {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    /* -webkit-align-self: center;
+        -ms-flex-item-align: center;
+            align-self: center;
+    font-size: 20px;
+    color: #2c8eff; */
+}
+
+.input-number-wrap {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    width: 534px;
+    height: 100px;
+    border: 1px solid #D4D4D4;
+    border-radius: 8px;
+    overflow: hidden;
+}
+
+.input-number-wrap div {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    min-width: 0;
+}
+
+.input-number-wrap div:first-child {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    padding: 0 60px 0 40px;
+    background: url("../../../images/icon.png") right center/30px 31px no-repeat;
+}
+
+.input-number-wrap input {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    min-width: 0;
+    border: 0;
+    outline: 0;
+    font-size: 30px;
+}
+
+.input-number-wrap input::-webkit-inner-spin-button, .input-number-wrap input::-webkit-outer-spin-button {
+    -webkit-appearance: none;
+}
+
+.input-number-wrap input[type="number"] {
+    -moz-appearance: textfield;
+}
+
+.input-number-wrap input + span {
+    -webkit-align-self: center;
+        -ms-flex-item-align: center;
+            align-self: center;
+    margin-left: 10px;
+    font-size: 20px;
+    color: #999999;
+}
+
+.input-number-wrap div:last-child {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    padding-left: 72px;
+    background: 30px center/32px 32px no-repeat;
+}

+ 126 - 0
public/pc/components/my/coin/index.html

xqd
@@ -0,0 +1,126 @@
+<div class="my-coin">
+    <div class="total">
+        <ul>
+            <li>
+                <div>我的金币(个):</div>
+                <div>{{ user_gold_num }}</div>
+            </li>
+            <li>
+                <div>累计充值(个):</div>
+                <div>{{ recharge }}</div>
+            </li>
+            <li>
+                <div>累计消费(个):</div>
+                <div>{{ consumption }}</div>
+            </li>
+        </ul>
+    </div>
+    <el-tabs v-if="activeName === 'coin'" v-model="active1">
+        <el-tab-pane label="充值" name="first">
+            <div class="recharge">
+                <div class="section">
+                    <div>充值数量</div>
+                    <div>
+                        <label v-for="(item, index) in recharge_price_list" :key="item">
+                            <input v-model="filterData.picked" :value="index" type="radio" hidden>
+                            <div>
+                                <div :style="{ backgroundImage: 'url(' + gold_image + ')' }">{{ item }}</div>
+                                <div>¥{{ item / gold_rate }}</div>
+                                <i class="el-icon-check"></i>
+                            </div>
+                        </label>
+                        <!-- <div class="input-number-wrap">
+                            <div>¥</div><el-input-number v-model="custom" controls-position="right" @change="handleChange" :min="1"
+                                         :max="9999999" placeholder="自定义充值数量(1-9999999)" @focus="inputNumberFocus"></el-input-number>
+                        </div> -->
+                        <div class="input-number-wrap">
+                            <div>
+                                <input v-model.number="custom" type="number" max="9999999" min="1" @focus="inputNumberFocus"><span>元</span>
+                            </div>
+                            <div :style="{ backgroundImage: 'url(' + gold_image + ')'}">{{ customIcon }}</div>
+                        </div>
+                    </div>
+                </div>
+                <div class="section">
+                    <div>支付方式</div>
+                    <div>
+                        <label v-if="isYue">
+                            <input v-model="filterData.payType" type="radio" value="yue" hidden>
+                            <div>
+                                <div>
+                                    余额支付
+                                    <div>余额:¥{{ nowMoney }}</div>
+                                </div>
+                                <i class="el-icon-check"></i>
+                            </div>
+                        </label>
+                        <label v-if="isWechat">
+                            <input v-model="filterData.payType" type="radio" value="weixin" hidden>
+                            <div>
+                                <div>微信支付</div>
+                                <i class="el-icon-check"></i>
+                            </div>
+                        </label>
+                        <label v-if="isAlipay">
+                            <input v-model="filterData.payType" type="radio" value="zhifubao" hidden>
+                            <div>
+                                <div>支付宝支付</div>
+                                <i class="el-icon-check"></i>
+                            </div>
+                        </label>
+                    </div>
+                    <div>
+                        <div v-show="!isReset" ref="qrcode"></div>
+                        <div v-show="!isReset" class="pay-tip">请用{{ filterData.payType === 'weixin' ? '微信' : '支付宝' }}扫码支付,支付<span>{{ (filterData.picked === -1 ? custom : (recharge_price_list[filterData.picked]) / gold_rate) }}</span>元
+                        </div>
+                        <el-button v-show="isReset" @click="create_order" :disabled="!filterData.payType">去支付</el-button>
+                    </div>
+                </div>
+            </div>
+        </el-tab-pane>
+        <el-tab-pane label="明细" name="second">
+            <el-tabs v-model="active2">
+                <el-tab-pane label="全部" name="">
+                    <ul v-if="goldList1.length">
+                        <li v-for="(item, index) in goldList1" :key="index">
+                            <div>
+                                <div>{{ item.title }}</div>
+                                <div>{{ item.add_time }}</div>
+                            </div>
+                            <div :class="{ red: item.pm }">{{ item.pm ? '+' : '-' }}¥{{ item.number }}</div>
+                        </li>
+                    </ul>
+                    <div v-else class="empty"></div>
+                    <el-pagination v-if="goldList1.length" :current-page.sync="page1" :page-size="limit" :total="total1" layout="prev, pager, next" prev-text="上一页" next-text="下一页" @current-change="user_gold_num_list1"></el-pagination>
+                </el-tab-pane>
+                <el-tab-pane label="收入明细" name="1">
+                    <ul v-if="goldList3.length">
+                        <li v-for="(item, index) in goldList3" :key="index">
+                            <div>
+                                <div>{{ item.title }}</div>
+                                <div>{{ item.add_time }}</div>
+                            </div>
+                            <div :class="{ red: item.pm }">{{ item.pm ? '+' : '-' }}¥{{ item.number }}</div>
+                        </li>
+                    </ul>
+                    <div v-else class="empty"></div>
+                    <el-pagination v-if="goldList3.length" :current-page.sync="page3" :page-size="limit" :total="total3" layout="prev, pager, next" prev-text="上一页" next-text="下一页" @current-change="user_gold_num_list3"></el-pagination>
+                </el-tab-pane>
+                <el-tab-pane label="支出明细" name="2">
+                    <ul v-if="goldList2.length">
+                        <li v-for="(item, index) in goldList2" :key="index">
+                            <div>
+                                <div>{{ item.title }}</div>
+                                <div>{{ item.add_time }}</div>
+                            </div>
+                            <div>{{ item.pm ? '+' : '-' }}¥{{ item.number }}</div>
+                        </li>
+                    </ul>
+                    <div v-else class="empty"></div>
+                    <el-pagination v-if="goldList2.length" :current-page.sync="page2" :page-size="limit" :total="total2" layout="prev, pager, next" prev-text="上一页" next-text="下一页" @current-change="user_gold_num_list2"></el-pagination>
+                </el-tab-pane>
+                <div class="detail-tip"><i class="el-icon-warning"></i>系统仅显示您两年之内的余额明细,更早的余额明细不再显示</div>
+            </el-tabs>
+        </el-tab-pane>
+    </el-tabs>
+</div>

+ 258 - 0
public/pc/components/my/coin/index.js

xqd
@@ -0,0 +1,258 @@
+define([
+    'api/auth',
+    'qrcode',
+    'text!components/my/coin/index.html',
+    'css!components/my/coin/index.css'
+], function (authApi, QRCode, html) {
+    return {
+        props: {
+            activeName: {
+                type: String,
+                default: 'coin'
+            },
+            isYue: {
+                type: Boolean,
+                default: true
+            },
+            isAlipay: {
+                type: Boolean,
+                default: true
+            },
+            isWechat: {
+                type: Boolean,
+                default: true
+            },
+            nowMoney: {
+                type: String,
+                default: '0'
+            },
+            isLogin: {
+                type: Boolean,
+                default: false
+            }
+        },
+        data: function () {
+            return {
+                active1: 'first',
+                custom: 1,
+                user_gold_num: 0,
+                recharge: 0,
+                consumption: 0,
+                recharge_price_list: [],
+                gold_image: '',
+                gold_rate: 1,
+                active2: '',
+                goldList1: [],
+                goldList2: [],
+                goldList3: [],
+                page1: 1,
+                page2: 1,
+                page3: 1,
+                limit: 20,
+                total1: 0,
+                total2: 0,
+                total3: 0,
+                filterData: {
+                    picked: 0,
+                    payType: 'yue',
+                },
+                isReset: true,
+                count: 0
+            };
+        },
+        computed: {
+            customIcon: function () {
+                return this.custom * this.gold_rate;
+            }
+        },
+        watch: {
+            isLogin: function (value) {
+                if (value) {
+                    this.get_gold_coins();
+                    this.user_gold_num_list1();
+                    this.user_gold_num_list2();
+                    this.user_gold_num_list3();
+                }
+            },
+            filterData: {
+                handler: function () {
+                    this.isReset = true;
+                },
+                deep: true
+            }
+        },
+        mounted: function () {
+            this.$nextTick(function () {
+                if (!this.isYue) {
+                    if (this.isWechat) {
+                        this.filterData.payType = 'weixin';
+                    } else {
+                        if (this.isAlipay) {
+                            this.filterData.payType = 'zhifubao';
+                        } else {
+                            this.filterData.payType = '';
+                        }
+                    }
+                }
+                
+            });
+        },
+        methods: {
+            // 我的金币
+            get_gold_coins: function () {
+                var vm = this;
+                authApi.get_gold_coins().then(function (res) {
+                    var data = res.data;
+                    vm.user_gold_num = data.user_gold_num;
+                    vm.recharge = data.recharge;
+                    vm.consumption = data.consumption;
+                    vm.recharge_price_list = data.recharge_price_list;
+                    vm.gold_image = data.gold_info.gold_image;
+                    vm.gold_rate = data.gold_info.gold_rate;
+                    vm.$parent.$parent.$parent.tabs.forEach(function (item) {
+                        if (item.value == "coin") {
+                            item.name = data.gold_name + '充值';
+                        }
+                    });
+                });
+            },
+            // 支付
+            create_order: function () {
+                var vm = this;
+                authApi.create_order({
+                    special_id: (this.filterData.picked == -1 ? this.custom : (this.recharge_price_list[this.filterData.picked]) / this.gold_rate),
+                    pay_type_num: 30,
+                    payType: this.filterData.payType
+                }).then(function (res) {
+                    switch (res.data.status) {
+                        case "PAY_ERROR":
+                        case 'ORDER_EXIST':
+                        case 'ORDER_ERROR':
+                            vm.$message.error(res.msg);
+                            break;
+                        case 'WECHAT_PAY':
+                            vm.isReset = false;
+                            if (vm.qrcode) {
+                                vm.qrcode.makeCode(res.data.result.jsConfig);
+                            } else {
+                                vm.$nextTick(function () {
+                                    vm.qrcode = new QRCode(vm.$refs.qrcode, res.data.result.jsConfig); 
+                                });
+                            }
+                            vm.testing_order_state(res.data.result.orderId);
+                            break;
+                        case 'ZHIFUBAO_PAY':
+                            vm.isReset = false;
+                            if (vm.qrcode) {
+                                vm.qrcode.makeCode(res.data.result.jsConfig);
+                            } else {
+                                vm.$nextTick(function () {
+                                    vm.qrcode = new QRCode(vm.$refs.qrcode, res.data.result.jsConfig); 
+                                });
+                            }
+                            vm.testing_order_state(res.data.result.orderId);
+                            break;
+                        case 'SUCCESS':
+                            vm.$message.success(res.msg);
+                            vm.payAfterClick();
+                            break;
+                    }
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            // 明细
+            user_gold_num_list1: function () {
+                var vm = this;
+                authApi.user_gold_num_list({
+                    page: this.page1,
+                    limit: this.limit,
+                    index: ''
+                }).then(function (res) {
+                    vm.goldList1 = res.data.list;
+                    vm.total1 = res.data.count;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            user_gold_num_list2: function () {
+                var vm = this;
+                authApi.user_gold_num_list({
+                    page: this.page2,
+                    limit: this.limit,
+                    index: 1
+                }).then(function (res) {
+                    vm.goldList2 = res.data.list;
+                    vm.total2 = res.data.count;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            user_gold_num_list3: function () {
+                var vm = this;
+                authApi.user_gold_num_list({
+                    page: this.page3,
+                    limit: this.limit,
+                    index: 2
+                }).then(function (res) {
+                    vm.goldList3 = res.data.list;
+                    vm.total3 = res.data.count;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            handleChange: function () {
+                this.filterData.picked = -1;
+            },
+            inputNumberFocus: function () {
+                this.filterData.picked = -1;
+                this.isReset = true;
+            },
+            payAfterClick: function () {
+                var vm = this;
+                vm.custom = 1;
+                vm.isReset = true;
+                vm.get_gold_coins();
+                vm.$emit('update-user');
+                vm.page1 = 1;
+                vm.page2 = 1;
+                vm.page3 = 1;
+                vm.goldList1 = [];
+                vm.goldList2 = [];
+                vm.goldList3 = [];
+                vm.user_gold_num_list1();
+                vm.user_gold_num_list2();
+                vm.user_gold_num_list3();
+            },
+            // 扫码回调
+            testing_order_state: function (orderId) {
+                var vm = this;
+                if (vm.timer) {
+                    return;
+                }
+                this.timer = setInterval(function () {
+                    vm.count++;
+                    authApi.testing_order_state({
+                        order_id: orderId,
+                        type: 2
+                    }).then(function (res) {
+                        if (res.data == 1) {
+                            clearInterval(vm.timer);
+                            vm.count = 0;
+                            vm.timer = null;
+                            vm.payAfterClick();
+                        }
+                    }).catch(function (err) {
+                        console.error(err.msg);
+                    });
+                    if (vm.count == 12) {
+                        clearInterval(vm.timer);
+                        vm.count = 0;
+                        vm.timer = null;
+                    }
+                }, 5000);
+            }
+        },
+        template: html
+    };
+});

+ 141 - 0
public/pc/components/my/course/index.css

xqd
@@ -0,0 +1,141 @@
+.my-course {
+    padding: 40px 50px;
+}
+
+.my-course .el-col {
+    padding-right: 7px !important;
+    padding-left: 7px !important;
+    margin-bottom: 14px;
+}
+
+.my-course a {
+    display: block;
+    border-radius: 8px;
+    overflow: hidden;
+    -webkit-box-shadow: 0 2px 15px rgba(79, 109, 143, 0.15);
+            box-shadow: 0 2px 15px rgba(79, 109, 143, 0.15);
+}
+
+.my-course .el-image {
+    display: block;
+    width: 100%;
+    height: 146px;
+}
+
+.my-course .el-image + div {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    height: 124px;
+    padding: 13px 15px 15px;
+}
+
+.my-course .title {
+    overflow: hidden;
+    white-space: nowrap;
+    -o-text-overflow: ellipsis;
+       text-overflow: ellipsis;
+    font-size: 16px;
+    color: #282828;
+}
+
+.my-course .label {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    min-height: 0;
+    margin-top: 12px;
+    font-size: 0;
+}
+
+.my-course .el-tag {
+    height: 22px;
+    padding-right: 7px;
+    padding-left: 7px;
+    border-color: rgba(44, 142, 255, 0.06);
+    border-radius: 2px;
+    background-color: rgba(44, 142, 255, 0.06);
+    line-height: 20px;
+    color: #2c8eff;
+}
+
+.my-course .el-tag ~ .el-tag {
+    margin-left: 10px;
+}
+
+.my-course .money-count {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    font-size: 14px;
+    color: #999;
+}
+
+.my-course .money-vip {
+    font-size: 0;
+}
+
+.my-course .money {
+    display: inline-block;
+    vertical-align: middle;
+    font-size: 12px;
+    color: #ff6b00;
+}
+
+.my-course .money.free {
+    font-size: 18px;
+}
+
+.my-course .money span {
+    font-size: 20px;
+}
+
+.my-course .vip {
+    display: inline-block;
+    padding-left: 25px;
+    margin-left: 8px;
+    background: url("../../../images/vip_money.png") left center/21px 13px no-repeat;
+    vertical-align: middle;
+    font-size: 12px;
+    line-height: 13px;
+    color: #282828;
+}
+
+.my-course .el-pagination {
+    padding-top: 58px;
+    padding-bottom: 58px;
+    text-align: center;
+}
+
+.my-course .empty {
+    height: 600px;
+    background: url("../../../images/empty8.png") center/274px no-repeat;
+}

+ 29 - 0
public/pc/components/my/course/index.html

xqd
@@ -0,0 +1,29 @@
+<div class="my-course">
+    <template>
+        <el-row v-if="specialList.length" :gutter="20">
+            <el-col v-for="item in specialList" :key="item.id" :span="6">
+                <a :href="(item.is_light ? router.single_details :  router.special_details) + '?id=' + item.id">
+                    <el-image :src="item.image" fit="cover"></el-image>
+                    <div>
+                        <div class="title">{{ item.title }}</div>
+                        <div class="label">
+                            <el-tag v-for="label in item.label">{{ label }}</el-tag>
+                        </div>
+                        <div class="money-count">
+                            <div class="money-vip">
+                                <template v-if="item.pay_type">
+                                    <div class="money">¥<span>{{ item.money }}</span></div>
+                                    <div class="vip">¥{{ item.member_money }}</div>
+                                </template>
+                                <div v-else class="money free">免费</div>
+                            </div>
+                            <div v-if="item.type !== 4 && !item.is_light">共{{ item.count }}节</div>
+                        </div>
+                    </div>
+                </a>
+            </el-col>
+        </el-row>
+        <el-pagination layout="prev, pager, next" :total="count" :page-size="limit" :current-page.sync="page" prev-text="上一页" next-text="下一页"></el-pagination>
+    </template>
+    <div v-else class="empty"></div>
+</div>

+ 48 - 0
public/pc/components/my/course/index.js

xqd
@@ -0,0 +1,48 @@
+define([
+    'api/auth',
+    'text!components/my/course/index.html',
+    'css!components/my/course/index.css'
+], function(authApi, html) {
+    return {
+        props: {
+            isLogin: {
+                type: Boolean,
+                default: false
+            }
+        },
+        data: function () {
+            return {
+                page: 1,
+                limit: 16,
+                count: 0,
+                specialList: [],
+                finished: false
+            };
+        },
+        watch: {
+            isLogin: function (value) {
+                if (value) {
+                    this.my_special_list();   
+                }
+            }
+        },
+        methods: {
+            // 课程列表
+            my_special_list: function () {
+                var vm = this;
+                authApi.my_special_list({
+                    page: this.page,
+                    limit: this.limit
+                }).then(function (res) {
+                    var data = res.data;
+                    vm.count = data.count;
+                    vm.specialList = data.list;
+                    vm.finished = vm.limit > data.list.length;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            }
+        },
+        template: html
+    };
+});

+ 559 - 0
public/pc/components/my/currency/index.css

xqd
@@ -0,0 +1,559 @@
+.my-coin {
+    padding-right: 55px;
+    padding-left: 55px;
+}
+
+.my-coin .total ul {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    padding-top: 65px;
+    padding-bottom: 35px;
+    font-size: 14px;
+    color: #969696;
+}
+
+.my-coin .total li ~ li {
+    margin-left: 170px;
+}
+
+.my-coin .total li > div:last-child {
+    margin-top: 15px;
+    font-weight: bold;
+    font-size: 32px;
+    color: #282828;
+}
+
+.my-coin .el-tabs__nav-wrap::after {
+    height: 1px;
+    background-color: #ececec;
+}
+
+.my-coin .el-tabs__item {
+    height: 50px;
+    font-size: 16px;
+    line-height: 50px;
+    color: #999;
+}
+
+.my-coin .el-tabs__item.is-active {
+    color: #2c8eff;
+}
+
+.my-coin .el-tabs__active-bar {
+    background-color: #2c8eff;
+}
+
+.my-coin .el-tabs__item:hover {
+    color: #2c8eff;
+}
+
+.my-coin .recharge .section {
+    padding-top: 40px;
+    padding-bottom: 20px;
+    font-size: 18px;
+    color: #282828;
+}
+
+.my-coin .recharge .section > div:nth-child(2) {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-flex-wrap: wrap;
+        -ms-flex-wrap: wrap;
+            flex-wrap: wrap;
+    margin-top: 30px;
+}
+
+.my-coin .recharge .section:first-child > div:last-child {
+    margin-right: -22px;
+    margin-bottom: -22px;
+}
+
+.my-coin .recharge .section:first-child label {
+    margin-right: 22px;
+    margin-bottom: 22px;
+}
+
+.my-coin .recharge .section:first-child input + div {
+    position: relative;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+       -moz-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    width: 256px;
+    height: 100px;
+    border: 1px solid #d4d4d4;
+    border-radius: 8px;
+    overflow: hidden;
+    text-align: center;
+    color: #999;
+}
+
+.my-coin .recharge .section:first-child input + div:hover {
+    border-color: #c0c4cc;
+}
+
+.my-coin .recharge .section:first-child input:checked + div {
+    border-color: #2c8eff;
+}
+
+.my-coin .recharge .section:first-child input + div div:first-child {
+    padding-left: 42px;
+    margin-bottom: 10px;
+    background: left center/32px 32px no-repeat;
+    font-size: 30px;
+    color: #282828;
+}
+
+.my-coin .recharge .section:first-child .el-icon-check {
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    z-index: 2;
+    width: 17px;
+    height: 16px;
+    background-color: #2c8eff;
+    font-size: 14px;
+    line-height: 16px;
+    text-align: center;
+    color: #fff;
+    opacity: 0;
+    -webkit-transition: 0.3s;
+    -o-transition: 0.3s;
+    -moz-transition: 0.3s;
+    transition: 0.3s;
+}
+
+.my-coin .recharge .section:first-child .el-icon-check::after {
+    content: "";
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    z-index: -1;
+    border-width: 16px 17px;
+    border-style: solid;
+    border-color: transparent #2c8eff #2c8eff transparent;
+}
+
+.my-coin .recharge .section:first-child input:checked + div .el-icon-check {
+    opacity: 1;
+}
+
+.my-coin .el-input-number {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    -webkit-align-self: flex-start;
+        -ms-flex-item-align: start;
+            align-self: flex-start;
+    margin-left: 10px;
+}
+
+.my-coin .el-input__inner {
+    height: 102px;
+    border-color: #d4d4d4;
+    border-radius: 8px;
+    font-size: 18px;
+    line-height: 102px;
+}
+
+.my-coin .el-input-number.is-controls-right .el-input-number__increase {
+    border-top-right-radius: 8px;
+}
+
+.my-coin .el-input-number.is-controls-right .el-input-number__decrease {
+    border-bottom-right-radius: 8px;
+}
+
+.my-coin .el-input-number.is-controls-right .el-input-number__decrease, .my-coin .el-input-number.is-controls-right .el-input-number__increase {
+    line-height: 51px;
+}
+
+.my-coin .recharge .section:last-child {
+    padding-bottom: 0;
+}
+
+.my-coin .recharge .section:last-child label {
+    margin-right: 20px;
+}
+
+.my-coin .recharge .section:last-child input + div {
+    position: relative;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+       -moz-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    width: 220px;
+    height: 86px;
+    border: 1px solid #d4d4d4;
+    border-radius: 8px;
+    overflow: hidden;
+    font-size: 16px;
+    line-height: 36px;
+    color: #4e4e4e;
+}
+
+.my-coin .recharge .section:last-child input + div:hover {
+    border-color: #c0c4cc;
+}
+
+.my-coin .recharge .section:last-child input:checked + div {
+    border-color: #2c8eff;
+}
+
+.my-coin .recharge .section:last-child input + div > div {
+    padding-left: 48px;
+    background: url("../../../images/alipay.png") left center/36px 36px no-repeat;
+}
+
+.my-coin .recharge .section:last-child label:first-child input + div > div {
+    background-image: url("../../../images/yue.png");
+    -o-background-size: 40px;
+       background-size: 40px;
+    line-height: 1.15;
+}
+
+.my-coin .recharge .section:last-child label:nth-child(2) input + div > div {
+    padding-left: 52px;
+    background-image: url("../../../images/wxpay.png");
+    -o-background-size: 40px 36px;
+       background-size: 40px 36px;
+}
+
+.my-coin .recharge .section:last-child > div:last-child {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    padding-top: 87px;
+    padding-bottom: 100px;
+}
+
+.my-coin .recharge .section:last-child input + div > div > div {
+    margin-top: 6px;
+    font-size: 14px;
+    color: #969696;
+}
+
+.my-coin .recharge .section:last-child > div > div:nth-child(2) {
+    margin-top: 30px;
+    font-size: 18px;
+    color: #666;
+}
+
+.my-coin .recharge .section:last-child > div > .btn-group {
+    font-size: 0;
+}
+
+.my-coin .recharge .section:last-child > div > .btn-group a {
+    display: inline-block;
+    width: 150px;
+    height: 42px;
+    border-radius: 21px;
+    margin: 50px 0 0;
+    background: #2C8EFF;
+    font-size: 16px;
+    line-height: 42px;
+    text-align: center;
+    color: #FFFFFF;
+}
+
+.my-coin .recharge .section:last-child > div > .btn-group a ~ a {
+    display: inline-block;
+    border: 1px solid #999999;
+    border-radius: 21px;
+    margin: 0 0 0 30px;
+    background: transparent;
+    font-size: 16px;
+    line-height: 40px;
+    text-align: center;
+    color: #999999;
+}
+
+.my-coin .recharge .section:last-child div > span {
+    vertical-align: sub;
+    font-weight: bold;
+    font-size: 30px;
+    color: #FF6B00;
+}
+
+.my-coin .recharge .section:last-child .el-button {
+    padding: 14px 68px;
+    border-color: #2c8eff;
+    border-radius: 23px;
+    background-color: #2c8eff;
+    font-size: 16px;
+    color: #fff;
+}
+
+.my-coin .recharge .section:last-child .el-button:focus, .my-coin .recharge .section:last-child .el-button:hover {
+    border-color: #66b1ff;
+    background-color: #66b1ff;
+}
+
+.my-coin .recharge .section:last-child .el-icon-check {
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    z-index: 2;
+    width: 17px;
+    height: 16px;
+    background-color: #2c8eff;
+    font-size: 14px;
+    line-height: 16px;
+    text-align: center;
+    color: #fff;
+    opacity: 0;
+    -webkit-transition: 0.3s;
+    -o-transition: 0.3s;
+    -moz-transition: 0.3s;
+    transition: 0.3s;
+}
+
+.my-coin .recharge .section:last-child .el-icon-check::after {
+    content: "";
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    z-index: -1;
+    border-width: 16px 17px;
+    border-style: solid;
+    border-color: transparent #2c8eff #2c8eff transparent;
+}
+
+.my-coin .recharge .section:last-child input:checked + div .el-icon-check {
+    opacity: 1;
+}
+
+.my-coin .el-tabs.el-tabs--top .el-tab-pane > ul > li {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    height: 86px;
+    padding-right: 10px;
+    padding-left: 10px;
+    border-bottom: 1px dashed #d0d0d0;
+    font-size: 14px;
+    color: #969696;
+}
+
+.my-coin .el-tabs.el-tabs--top li > div > div:first-child {
+    margin-bottom: 10px;
+    font-size: 16px;
+    color: #282828;
+}
+
+.my-coin .el-tabs.el-tabs--top li > div:last-child {
+    font-weight: bold;
+    font-size: 16px;
+    color: #2c8eff;
+}
+
+.my-coin .el-tabs.el-tabs--top li > .red:last-child {
+    color: #FF6B00;
+}
+
+.my-coin .detail-tip {
+    padding: 23px 0 46px;
+    font-size: 12px;
+    line-height: 16px;
+    color: #969696;
+}
+
+.my-coin .detail-tip .el-icon-warning {
+    margin: 0 8px 0 0;
+    font-size: 14px;
+    color: #FF6B00;
+}
+
+.my-coin .empty {
+    height: 623px;
+    background: url("../../../images/empty7.png") center/274px no-repeat;
+}
+
+.my-coin .el-tabs__content .el-tabs__active-bar {
+    display: none;
+}
+
+.my-coin .el-tabs__content .el-tabs__item {
+    min-width: 70px;
+    height: 35px;
+    padding: 0 15px;
+    border: 1px solid #D4D4D4;
+    border-radius: 4px;
+    line-height: 33px;
+    text-align: center;
+    color: #999999;
+}
+
+.my-coin .el-tabs__content .el-tabs__item ~ .el-tabs__item {
+    margin: 0 0 0 18px;
+}
+
+.my-coin .el-tabs__content .el-tabs--top .el-tabs__item.is-top:nth-child(2), .my-coin .el-tabs__content .el-tabs--top .el-tabs__item.is-top:last-child {
+    padding: 0 15px;
+}
+
+.my-coin .el-tabs__content .el-tabs__item.is-active {
+    border-color: #2C8EFF;
+}
+
+.input-number-label {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    width: 534px;
+    /* height: 100px; */
+}
+
+.input-number-label span {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    /* -webkit-align-self: center;
+        -ms-flex-item-align: center;
+            align-self: center;
+    font-size: 20px;
+    color: #2c8eff; */
+}
+
+.input-number-wrap {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    width: 534px;
+    height: 100px;
+    border: 1px solid #D4D4D4;
+    border-radius: 8px;
+    overflow: hidden;
+}
+
+.input-number-wrap div {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    min-width: 0;
+}
+
+.input-number-wrap div:first-child {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    padding: 0 60px 0 40px;
+    background: url("../../../images/icon.png") right center/30px 31px no-repeat;
+}
+
+.input-number-wrap input {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    min-width: 0;
+    border: 0;
+    outline: 0;
+    font-size: 30px;
+}
+
+.input-number-wrap input::-webkit-inner-spin-button, .input-number-wrap input::-webkit-outer-spin-button {
+    -webkit-appearance: none;
+}
+
+.input-number-wrap input[type="number"] {
+    -moz-appearance: textfield;
+}
+
+.input-number-wrap input + span {
+    -webkit-align-self: center;
+        -ms-flex-item-align: center;
+            align-self: center;
+    margin-left: 10px;
+    font-size: 20px;
+    color: #999999;
+}
+
+.input-number-wrap div:last-child {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    padding-left: 72px;
+    background: 30px center/32px 32px no-repeat;
+}

+ 126 - 0
public/pc/components/my/currency/index.html

xqd
@@ -0,0 +1,126 @@
+<div class="my-coin">
+    <div class="total">
+        <ul>
+            <li>
+                <div>我的金币(个):</div>
+                <div>{{ user_gold_num }}</div>
+            </li>
+            <li>
+                <div>累计充值(个):</div>
+                <div>{{ recharge }}</div>
+            </li>
+            <li>
+                <div>累计消费(个):</div>
+                <div>{{ consumption }}</div>
+            </li>
+        </ul>
+    </div>
+    <el-tabs v-if="activeName === 'currency'" v-model="active1">
+        <el-tab-pane label="充值" name="first">
+            <div class="recharge">
+                <div class="section">
+                    <div>充值数量</div>
+                    <div>
+                        <label v-for="(item, index) in recharge_price_list" :key="item">
+                            <input v-model="filterData.picked" :value="index" type="radio" hidden>
+                            <div>
+                                <div :style="{ backgroundImage: 'url(' + gold_image + ')' }">{{ item }}</div>
+                                <div>¥{{ item / gold_rate }}</div>
+                                <i class="el-icon-check"></i>
+                            </div>
+                        </label>
+                        <!-- <div class="input-number-wrap">
+                            <div>¥</div><el-input-number v-model="custom" controls-position="right" @change="handleChange" :min="1"
+                                         :max="9999999" placeholder="自定义充值数量(1-9999999)" @focus="inputNumberFocus"></el-input-number>
+                        </div> -->
+                        <div class="input-number-wrap">
+                            <div>
+                                <input v-model.number="custom" type="number" max="9999999" min="1" @focus="inputNumberFocus"><span>元</span>
+                            </div>
+                            <div :style="{ backgroundImage: 'url(' + gold_image + ')'}">{{ customIcon }}</div>
+                        </div>
+                    </div>
+                </div>
+                <div class="section">
+                    <div>支付方式</div>
+                    <div>
+                        <label v-if="isYue">
+                            <input v-model="filterData.payType" type="radio" value="yue" hidden>
+                            <div>
+                                <div>
+                                    余额支付
+                                    <div>余额:¥{{ nowMoney }}</div>
+                                </div>
+                                <i class="el-icon-check"></i>
+                            </div>
+                        </label>
+                        <label v-if="isWechat">
+                            <input v-model="filterData.payType" type="radio" value="weixin" hidden>
+                            <div>
+                                <div>微信支付</div>
+                                <i class="el-icon-check"></i>
+                            </div>
+                        </label>
+                        <label v-if="isAlipay">
+                            <input v-model="filterData.payType" type="radio" value="zhifubao" hidden>
+                            <div>
+                                <div>支付宝支付</div>
+                                <i class="el-icon-check"></i>
+                            </div>
+                        </label>
+                    </div>
+                    <div>
+                        <div v-show="!isReset" ref="qrcode"></div>
+                        <div v-show="!isReset" class="pay-tip">请用{{ filterData.payType === 'weixin' ? '微信' : '支付宝' }}扫码支付,支付<span>{{ (filterData.picked === -1 ? custom : (recharge_price_list[filterData.picked]) / gold_rate) }}</span>元
+                        </div>
+                        <el-button v-show="isReset" @click="create_order" :disabled="!filterData.payType">去支付</el-button>
+                    </div>
+                </div>
+            </div>
+        </el-tab-pane>
+        <el-tab-pane label="明细" name="second">
+            <el-tabs v-model="active2">
+                <el-tab-pane label="全部" name="">
+                    <ul v-if="goldList1.length">
+                        <li v-for="(item, index) in goldList1" :key="index">
+                            <div>
+                                <div>{{ item.title }}</div>
+                                <div>{{ item.add_time }}</div>
+                            </div>
+                            <div :class="{ red: item.pm }">{{ item.pm ? '+' : '-' }}¥{{ item.number }}</div>
+                        </li>
+                    </ul>
+                    <div v-else class="empty"></div>
+                    <el-pagination :page-size="limit" :total="total1" :current-page="page1" layout="prev, pager, next" prev-text="上一页" next-text="下一页" hide-on-single-page @current-change="user_gold_num_list1"></el-pagination>
+                </el-tab-pane>
+                <el-tab-pane label="收入明细" name="1">
+                    <ul v-if="goldList3.length">
+                        <li v-for="(item, index) in goldList3" :key="index">
+                            <div>
+                                <div>{{ item.title }}</div>
+                                <div>{{ item.add_time }}</div>
+                            </div>
+                            <div :class="{ red: item.pm }">{{ item.pm ? '+' : '-' }}¥{{ item.number }}</div>
+                        </li>
+                    </ul>
+                    <div v-else class="empty"></div>
+                    <el-pagination :page-size="limit" :total="total3" :current-page="page3" layout="prev, pager, next" prev-text="上一页" next-text="下一页" hide-on-single-page @current-change="user_gold_num_list3"></el-pagination>
+                </el-tab-pane>
+                <el-tab-pane label="支出明细" name="2">
+                    <ul v-if="goldList2.length">
+                        <li v-for="(item, index) in goldList2" :key="index">
+                            <div>
+                                <div>{{ item.title }}</div>
+                                <div>{{ item.add_time }}</div>
+                            </div>
+                            <div>{{ item.pm ? '+' : '-' }}¥{{ item.number }}</div>
+                        </li>
+                    </ul>
+                    <div v-else class="empty"></div>
+                    <el-pagination :page-size="limit" :total="total2" :current-page="page2" layout="prev, pager, next" prev-text="上一页" next-text="下一页" hide-on-single-page @current-change="user_gold_num_list2"></el-pagination>
+                </el-tab-pane>
+                <div class="detail-tip"><i class="el-icon-warning"></i>系统仅显示您两年之内的余额明细,更早的余额明细不再显示</div>
+            </el-tabs>
+        </el-tab-pane>
+    </el-tabs>
+</div>

+ 258 - 0
public/pc/components/my/currency/index.js

xqd
@@ -0,0 +1,258 @@
+define([
+    'api/auth',
+    'qrcode',
+    'text!./index.html',
+    'css!./index.css'
+], function (authApi, QRCode, html) {
+    return {
+        props: {
+            activeName: {
+                type: String,
+                default: 'coin'
+            },
+            isYue: {
+                type: Boolean,
+                default: true
+            },
+            isAlipay: {
+                type: Boolean,
+                default: true
+            },
+            isWechat: {
+                type: Boolean,
+                default: true
+            },
+            nowMoney: {
+                type: String,
+                default: '0'
+            },
+            isLogin: {
+                type: Boolean,
+                default: false
+            }
+        },
+        data: function () {
+            return {
+                active1: 'first',
+                custom: 1,
+                user_gold_num: 0,
+                recharge: 0,
+                consumption: 0,
+                recharge_price_list: [],
+                gold_image: '',
+                gold_rate: 1,
+                active2: '',
+                goldList1: [],
+                goldList2: [],
+                goldList3: [],
+                page1: 1,
+                page2: 1,
+                page3: 1,
+                limit: 20,
+                total1: 0,
+                total2: 0,
+                total3: 0,
+                filterData: {
+                    picked: 0,
+                    payType: 'yue',
+                },
+                isReset: true,
+                count: 0
+            };
+        },
+        computed: {
+            customIcon: function () {
+                return this.custom * this.gold_rate;
+            }
+        },
+        watch: {
+            isLogin: function (value) {
+                if (value) {
+                    this.get_gold_coins();
+                    this.user_gold_num_list1();
+                    this.user_gold_num_list2();
+                    this.user_gold_num_list3();
+                }
+            },
+            filterData: {
+                handler: function () {
+                    this.isReset = true;
+                },
+                deep: true
+            }
+        },
+        mounted: function () {
+            this.$nextTick(function () {
+                if (!this.isYue) {
+                    if (this.isWechat) {
+                        this.filterData.payType = 'weixin';
+                    } else {
+                        if (this.isAlipay) {
+                            this.filterData.payType = 'zhifubao';
+                        } else {
+                            this.filterData.payType = '';
+                        }
+                    }
+                }
+                
+            });
+        },
+        methods: {
+            // 我的金币
+            get_gold_coins: function () {
+                var vm = this;
+                authApi.get_gold_coins().then(function (res) {
+                    var data = res.data;
+                    vm.user_gold_num = data.user_gold_num;
+                    vm.recharge = data.recharge;
+                    vm.consumption = data.consumption;
+                    vm.recharge_price_list = data.recharge_price_list;
+                    vm.gold_image = data.gold_info.gold_image;
+                    vm.gold_rate = data.gold_info.gold_rate;
+                    vm.$parent.$parent.$parent.tabs.forEach(function (item) {
+                        if (item.value == "coin") {
+                            item.name = data.gold_name + '充值';
+                        }
+                    });
+                });
+            },
+            // 支付
+            create_order: function () {
+                var vm = this;
+                authApi.create_order({
+                    special_id: (this.filterData.picked == -1 ? this.custom : (this.recharge_price_list[this.filterData.picked]) / this.gold_rate),
+                    pay_type_num: 30,
+                    payType: this.filterData.payType
+                }).then(function (res) {
+                    switch (res.data.status) {
+                        case "PAY_ERROR":
+                        case 'ORDER_EXIST':
+                        case 'ORDER_ERROR':
+                            vm.$message.error(res.msg);
+                            break;
+                        case 'WECHAT_PAY':
+                            vm.isReset = false;
+                            if (vm.qrcode) {
+                                vm.qrcode.makeCode(res.data.result.jsConfig);
+                            } else {
+                                vm.$nextTick(function () {
+                                    vm.qrcode = new QRCode(vm.$refs.qrcode, res.data.result.jsConfig); 
+                                });
+                            }
+                            vm.testing_order_state(res.data.result.orderId);
+                            break;
+                        case 'ZHIFUBAO_PAY':
+                            vm.isReset = false;
+                            if (vm.qrcode) {
+                                vm.qrcode.makeCode(res.data.result.jsConfig);
+                            } else {
+                                vm.$nextTick(function () {
+                                    vm.qrcode = new QRCode(vm.$refs.qrcode, res.data.result.jsConfig); 
+                                });
+                            }
+                            vm.testing_order_state(res.data.result.orderId);
+                            break;
+                        case 'SUCCESS':
+                            vm.$message.success(res.msg);
+                            vm.payAfterClick();
+                            break;
+                    }
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            // 明细
+            user_gold_num_list1: function () {
+                var vm = this;
+                authApi.user_gold_num_list({
+                    page: this.page1,
+                    limit: this.limit,
+                    index: ''
+                }).then(function (res) {
+                    vm.goldList1 = res.data.list;
+                    vm.total1 = res.data.count;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            user_gold_num_list2: function () {
+                var vm = this;
+                authApi.user_gold_num_list({
+                    page: this.page2,
+                    limit: this.limit,
+                    index: 1
+                }).then(function (res) {
+                    vm.goldList2 = res.data.list;
+                    vm.total2 = res.data.count;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            user_gold_num_list3: function () {
+                var vm = this;
+                authApi.user_gold_num_list({
+                    page: this.page3,
+                    limit: this.limit,
+                    index: 2
+                }).then(function (res) {
+                    vm.goldList3 = res.data.list;
+                    vm.total3 = res.data.count;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            handleChange: function () {
+                this.filterData.picked = -1;
+            },
+            inputNumberFocus: function () {
+                this.filterData.picked = -1;
+                this.isReset = true;
+            },
+            payAfterClick: function () {
+                var vm = this;
+                vm.custom = 1;
+                vm.isReset = true;
+                vm.get_gold_coins();
+                vm.$emit('update-user');
+                vm.page1 = 1;
+                vm.page2 = 1;
+                vm.page3 = 1;
+                vm.goldList1 = [];
+                vm.goldList2 = [];
+                vm.goldList3 = [];
+                vm.user_gold_num_list1();
+                vm.user_gold_num_list2();
+                vm.user_gold_num_list3();
+            },
+            // 扫码回调
+            testing_order_state: function (orderId) {
+                var vm = this;
+                if (vm.timer) {
+                    return;
+                }
+                this.timer = setInterval(function () {
+                    vm.count++;
+                    authApi.testing_order_state({
+                        order_id: orderId,
+                        type: 2
+                    }).then(function (res) {
+                        if (res.data == 1) {
+                            clearInterval(vm.timer);
+                            vm.count = 0;
+                            vm.timer = null;
+                            vm.payAfterClick();
+                        }
+                    }).catch(function (err) {
+                        console.error(err.msg);
+                    });
+                    if (vm.count == 12) {
+                        clearInterval(vm.timer);
+                        vm.count = 0;
+                        vm.timer = null;
+                    }
+                }, 5000);
+            }
+        },
+        template: html
+    };
+});

+ 333 - 0
public/pc/components/my/favor/index.css

xqd
@@ -0,0 +1,333 @@
+.my-favor.el-tabs.el-tabs--top {
+    padding-left: 50px;
+    margin-top: 0;
+}
+
+.my-favor .el-tabs__header.is-top {
+    padding-right: 0;
+    padding-left: 0;
+    margin-bottom: 0;
+}
+
+.my-favor .el-tabs__nav-wrap.is-top::after {
+    display: block;
+    height: 1px;
+    background-color: #ececec;
+}
+
+.my-favor .el-tabs__item.is-top {
+    height: 60px;
+    padding-right: 25px;
+    padding-left: 25px;
+    line-height: 60px;
+    color: #999;
+}
+
+.my-favor .el-tabs__header.is-top .el-tabs__item.is-top:nth-child(2) {
+    padding-left: 25px;
+}
+
+.my-favor .el-tabs__header.is-top .el-tabs__item.is-top:last-child {
+    padding-right: 25px;
+}
+
+.my-favor .el-tabs__content {
+    padding-top: 30px;
+    padding-right: 50px;
+}
+
+.my-favor .el-col {
+    padding-right: 7px !important;
+    padding-left: 7px !important;
+    margin-bottom: 14px;
+}
+
+.my-favor .el-col a {
+    display: block;
+    border-radius: 8px;
+    overflow: hidden;
+    -webkit-box-shadow: 0 2px 15px rgba(79, 109, 143, 0.15);
+            box-shadow: 0 2px 15px rgba(79, 109, 143, 0.15);
+}
+
+.my-favor .image-group {
+    position: relative;
+}
+
+.my-favor .image-group .el-image:first-child {
+    display: block;
+    width: 100%;
+    height: 146px;
+}
+
+.my-favor .image-group .el-image:nth-child(2) {
+    position: absolute;
+    right: 7px;
+    bottom: 7px;
+    z-index: 2;
+    width: 20px;
+    height: 20px;
+    padding: 5px;
+    border-radius: 50%;
+    background-color: rgba(0, 0, 0, 0.5);
+}
+
+.my-favor .image-group .el-button {
+    position: absolute;
+    top: 10px;
+    right: 10px;
+    z-index: 2;
+    padding: 5px;
+    border: 0;
+    border-radius: 2px;
+    background-color: rgba(0, 0, 0, 0.5);
+    font-size: 12px;
+    color: #FFFFFF;
+    opacity: 0;
+}
+
+.my-favor .el-col a:hover .image-group .el-button {
+    opacity: 1;
+}
+
+.my-favor .image-group + div {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    height: 124px;
+    padding: 13px 15px 15px 20px;
+}
+
+.my-favor .title {
+    overflow: hidden;
+    white-space: nowrap;
+    -o-text-overflow: ellipsis;
+       text-overflow: ellipsis;
+    font-size: 16px;
+    color: #282828;
+}
+
+.my-favor .label {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    min-height: 0;
+    margin-top: 12px;
+    font-size: 0;
+}
+
+.my-favor .el-tag {
+    height: 22px;
+    padding-right: 7px;
+    padding-left: 7px;
+    border-color: rgba(44, 142, 255, 0.06);
+    border-radius: 2px;
+    background-color: rgba(44, 142, 255, 0.06);
+    line-height: 20px;
+    color: #2c8eff;
+}
+
+.my-favor .el-tag ~ .el-tag {
+    margin-left: 10px;
+}
+
+.my-favor .money-count {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    font-size: 14px;
+    color: #999;
+}
+
+.my-favor .money-vip {
+    font-size: 0;
+}
+
+.my-favor .money {
+    display: inline-block;
+    vertical-align: middle;
+    font-size: 12px;
+    color: #ff6b00;
+}
+
+.my-favor .money.free {
+    font-size: 18px;
+}
+
+.my-favor .money span {
+    font-size: 20px;
+}
+
+.my-favor .vip {
+    display: inline-block;
+    padding-left: 25px;
+    margin-left: 8px;
+    background: url("../../../images/vip_money.png") left center/21px 13px no-repeat;
+    vertical-align: middle;
+    font-size: 12px;
+    line-height: 13px;
+    color: #282828;
+}
+
+.my-favor .material-list a {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    padding-top: 30px;
+    padding-bottom: 30px;
+    border-bottom: 1px dashed #d0d0d0;
+}
+
+.my-favor .material-list a > div:first-child {
+    position: relative;
+}
+
+.my-favor .material-list .el-image {
+    display: block;
+    width: 202px;
+    height: 114px;
+    border-radius: 8px;
+}
+
+.my-favor .material-list .el-image + .el-button {
+    position: absolute;
+    top: 10px;
+    right: 10px;
+    z-index: 2;
+    padding: 5px;
+    border: 0;
+    border-radius: 2px;
+    background-color: rgba(0, 0, 0, 0.5);
+    font-size: 12px;
+    color: #FFFFFF;
+    opacity: 0;
+}
+
+.my-favor .material-list a:hover .el-image + .el-button {
+    opacity: 1;
+}
+
+.my-favor .material-list a > div:nth-child(2) {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    min-width: 0;
+    padding: 8px 20px 11px;
+}
+
+.my-favor .material-list .title {
+    overflow: hidden;
+    white-space: nowrap;
+    -o-text-overflow: ellipsis;
+       text-overflow: ellipsis;
+    font-size: 18px;
+    color: #282828;
+}
+
+.my-favor .material-list .people {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    min-height: 0;
+    margin-top: 10px;
+    font-size: 14px;
+    color: #999;
+}
+
+.my-favor .material-list .money-vip {
+    font-size: 0;
+}
+
+.my-favor .material-list .money {
+    display: inline-block;
+    vertical-align: middle;
+    font-size: 14px;
+    color: #ff6b00;
+}
+
+.my-favor .material-list .money.free {
+    font-size: 16px;
+}
+
+.my-favor .material-list .money span {
+    font-size: 18px;
+}
+
+.my-favor .material-list .vip {
+    display: inline-block;
+    padding-right: 25px;
+    margin-left: 8px;
+    background: url("../../../images/vip_money.png") left center/21px 13px no-repeat;
+    vertical-align: middle;
+    font-size: 12px;
+    line-height: 13px;
+    color: #282828;
+}
+
+.my-favor .material-list .el-button {
+    -webkit-align-self: center;
+        -ms-flex-item-align: center;
+            align-self: center;
+    padding: 10px 23px;
+    border-color: #2c8eff;
+    border-radius: 19px;
+    font-size: 16px;
+    color: #2c8eff;
+}
+
+.my-favor .el-pagination {
+    padding-top: 58px;
+    padding-bottom: 58px;
+    text-align: center;
+}
+
+.my-favor .el-tabs__content .empty {
+    height: 539px;
+    background: url("../../../images/empty6.png") center/274px no-repeat;
+}

+ 63 - 0
public/pc/components/my/favor/index.html

xqd
@@ -0,0 +1,63 @@
+<el-tabs v-if="activeName === 'favor'" v-model="active" class="my-favor" @tab-click="tabClick">
+    <el-tab-pane label="收藏课程" name="0">
+        <template v-if="list1.length">
+            <el-row :gutter="20">
+                <el-col v-for="item in list1" :span="6">
+                    <a :href="(item.is_light ? router.single_details : router.special_details) + '?id=' + item.id">
+                        <div class="image-group">
+                            <el-image :src="item.image" fit="cover"></el-image>
+                            <el-image v-if="item.type === 1" src="/pc/images/course3.png" fit="cover"></el-image>
+                            <el-image v-else-if="item.type === 2" src="/pc/images/course2.png" fit="cover"></el-image>
+                            <el-image v-else-if="item.type === 3" src="/pc/images/course1.png" fit="cover"></el-image>
+                            <el-button icon="el-icon-close" @click.prevent="specialCollect(item.id)">移除</el-button>
+                        </div>
+                        <div>
+                            <div class="title">{{ item.title }}</div>
+                            <div class="label">
+                                <el-tag v-for="label in item.label">{{ label }}</el-tag>
+                            </div>
+                            <div class="money-count">
+                                <div class="money-vip">
+                                    <template v-if="item.pay_type">
+                                        <div class="money">¥<span>{{ item.money }}</span></div>
+                                        <div class="vip">¥{{ item.member_money }}</div>
+                                    </template>
+                                    <div v-else class="money free">免费</div>
+                                </div>
+                                <div v-if="item.type !== 4 && !item.is_light">共{{ item.count }}节</div>
+                            </div>
+                        </div>
+                    </a>
+                </el-col>
+            </el-row>
+            <el-pagination layout="prev, pager, next" :current-page.sync="page1" :page-size="limit" :total="count1" prev-text="上一页" next-text="下一页"></el-pagination>
+        </template>
+        <div v-else class="empty"></div>
+    </el-tab-pane>
+    <el-tab-pane label="收藏资料" name="1">
+        <template v-if="list2.length">
+            <div class="material-list">
+                <a v-for="item in list2" :href="router.material_details + '?id=' + item.id">
+                    <div>
+                        <el-image :src="item.image" fit="cover"></el-image>
+                        <el-button icon="el-icon-close" @click.prevent="materialCollect(item.id)">移除</el-button>
+                    </div>
+                    <div>
+                        <div class="title">{{ item.title }}</div>
+                        <div class="people">{{ item.ficti + item.sales }}人已下载</div>
+                        <div class="money-vip">
+                            <template v-if="item.pay_type">
+                                <div class="money">¥<span>{{ item.money }}</span></div>
+                                <div class="vip">¥{{ item.member_money }}</div>
+                            </template>
+                            <div v-else class="money free">免费</div>
+                        </div>
+                    </div>
+                    <el-button icon="el-icon-download">去下载</el-button>
+                </a>
+            </div>
+            <el-pagination layout="prev, pager, next" :current-page.sync="page2" :page-size="limit" :total="count2" prev-text="上一页" next-text="下一页"></el-pagination>
+        </template>
+        <div v-else class="empty"></div>
+    </el-tab-pane>
+</el-tabs>

+ 119 - 0
public/pc/components/my/favor/index.js

xqd
@@ -0,0 +1,119 @@
+define([
+    'api/auth',
+    'api/special',
+    'api/material',
+    'text!components/my/favor/index.html',
+    'css!components/my/favor/index.css'
+], function(authApi, specialApi, materialApi, html) {
+    return {
+        props: {
+            activeName: {
+                type: String,
+                default: 'favor'
+            },
+            isLogin: {
+                type: Boolean,
+                default: false
+            }
+        },
+        data: function () {
+            return {
+                page1: 1,
+                page2: 1,
+                limit: 16,
+                active: '0',
+                list1: [],
+                list2: [],
+                finished1: false,
+                finished2: false,
+                count1: 0,
+                count2: 0
+            };
+        },
+        watch: {
+            isLogin: function (value) {
+                if (value) {
+                    this.get_grade_list1();
+                    this.get_grade_list2();
+                }
+            },
+            page1: function () {
+                this.get_grade_list1();
+            },
+            page2: function () {
+                this.get_grade_list2();
+            }
+        },
+        methods: {
+            // 课程
+            get_grade_list1: function () {
+                var vm = this;
+                authApi.get_grade_list({
+                    page: this.page1,
+                    limit: this.limit,
+                    active: 0
+                }).then(function (res) {
+                    var data = res.data;
+                    vm.count1 = data.count;
+                    vm.list1 = data.list;
+                    // vm.finished1 = vm.limit > data.list.length;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            // 资料
+            get_grade_list2: function () {
+                var vm = this;
+                authApi.get_grade_list({
+                    page: this.page2,
+                    limit: this.limit,
+                    active: 1
+                }).then(function (res) {
+                    var data = res.data;
+                    vm.count2 = data.count;
+                    vm.list2 = data.list;
+                    // vm.finished2 = vm.limit > data.list.length;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            // 取消课程收藏
+            specialCollect: function (id) {
+                var vm = this;
+                specialApi.collect({
+                    id: id
+                }).then(function () {
+                    vm.$message.success('取消收藏成功');
+                    if (!(vm.list1.length - 1)) {
+                        if (vm.page1 > 1) {
+                            vm.page1--;
+                        }
+                    }
+                    vm.get_grade_list1();
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            // 取消资料收藏
+            materialCollect: function (id) {
+                var vm = this;
+                materialApi.collect({
+                    id: id
+                }).then(function () {
+                    vm.$message.success('取消收藏成功');
+                    if (!(vm.list2.length - 1)) {
+                        if (vm.page2 > 1) {
+                            vm.page2--;
+                        }
+                    }
+                    vm.get_grade_list2();
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            tabClick: function (params) {
+            }
+        },
+        template: html
+    };
+});

+ 333 - 0
public/pc/components/my/favorite/index.css

xqd
@@ -0,0 +1,333 @@
+.my-favor.el-tabs.el-tabs--top {
+    padding-left: 50px;
+    margin-top: 0;
+}
+
+.my-favor .el-tabs__header.is-top {
+    padding-right: 0;
+    padding-left: 0;
+    margin-bottom: 0;
+}
+
+.my-favor .el-tabs__nav-wrap.is-top::after {
+    display: block;
+    height: 1px;
+    background-color: #ececec;
+}
+
+.my-favor .el-tabs__item.is-top {
+    height: 60px;
+    padding-right: 25px;
+    padding-left: 25px;
+    line-height: 60px;
+    color: #999;
+}
+
+.my-favor .el-tabs__header.is-top .el-tabs__item.is-top:nth-child(2) {
+    padding-left: 25px;
+}
+
+.my-favor .el-tabs__header.is-top .el-tabs__item.is-top:last-child {
+    padding-right: 25px;
+}
+
+.my-favor .el-tabs__content {
+    padding-top: 30px;
+    padding-right: 50px;
+}
+
+.my-favor .el-col {
+    padding-right: 7px !important;
+    padding-left: 7px !important;
+    margin-bottom: 14px;
+}
+
+.my-favor .el-col a {
+    display: block;
+    border-radius: 8px;
+    overflow: hidden;
+    -webkit-box-shadow: 0 2px 15px rgba(79, 109, 143, 0.15);
+            box-shadow: 0 2px 15px rgba(79, 109, 143, 0.15);
+}
+
+.my-favor .image-group {
+    position: relative;
+}
+
+.my-favor .image-group .el-image:first-child {
+    display: block;
+    width: 100%;
+    height: 146px;
+}
+
+.my-favor .image-group .el-image:nth-child(2) {
+    position: absolute;
+    right: 7px;
+    bottom: 7px;
+    z-index: 2;
+    width: 20px;
+    height: 20px;
+    padding: 5px;
+    border-radius: 50%;
+    background-color: rgba(0, 0, 0, 0.5);
+}
+
+.my-favor .image-group .el-button {
+    position: absolute;
+    top: 10px;
+    right: 10px;
+    z-index: 2;
+    padding: 5px;
+    border: 0;
+    border-radius: 2px;
+    background-color: rgba(0, 0, 0, 0.5);
+    font-size: 12px;
+    color: #FFFFFF;
+    opacity: 0;
+}
+
+.my-favor .el-col a:hover .image-group .el-button {
+    opacity: 1;
+}
+
+.my-favor .image-group + div {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    height: 124px;
+    padding: 13px 15px 15px 20px;
+}
+
+.my-favor .title {
+    overflow: hidden;
+    white-space: nowrap;
+    -o-text-overflow: ellipsis;
+       text-overflow: ellipsis;
+    font-size: 16px;
+    color: #282828;
+}
+
+.my-favor .label {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    min-height: 0;
+    margin-top: 12px;
+    font-size: 0;
+}
+
+.my-favor .el-tag {
+    height: 22px;
+    padding-right: 7px;
+    padding-left: 7px;
+    border-color: rgba(44, 142, 255, 0.06);
+    border-radius: 2px;
+    background-color: rgba(44, 142, 255, 0.06);
+    line-height: 20px;
+    color: #2c8eff;
+}
+
+.my-favor .el-tag ~ .el-tag {
+    margin-left: 10px;
+}
+
+.my-favor .money-count {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    font-size: 14px;
+    color: #999;
+}
+
+.my-favor .money-vip {
+    font-size: 0;
+}
+
+.my-favor .money {
+    display: inline-block;
+    vertical-align: middle;
+    font-size: 12px;
+    color: #ff6b00;
+}
+
+.my-favor .money.free {
+    font-size: 18px;
+}
+
+.my-favor .money span {
+    font-size: 20px;
+}
+
+.my-favor .vip {
+    display: inline-block;
+    padding-left: 25px;
+    margin-left: 8px;
+    background: url("../../../images/vip_money.png") left center/21px 13px no-repeat;
+    vertical-align: middle;
+    font-size: 12px;
+    line-height: 13px;
+    color: #282828;
+}
+
+.my-favor .material-list a {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    padding-top: 30px;
+    padding-bottom: 30px;
+    border-bottom: 1px dashed #d0d0d0;
+}
+
+.my-favor .material-list a > div:first-child {
+    position: relative;
+}
+
+.my-favor .material-list .el-image {
+    display: block;
+    width: 202px;
+    height: 114px;
+    border-radius: 8px;
+}
+
+.my-favor .material-list .el-image + .el-button {
+    position: absolute;
+    top: 10px;
+    right: 10px;
+    z-index: 2;
+    padding: 5px;
+    border: 0;
+    border-radius: 2px;
+    background-color: rgba(0, 0, 0, 0.5);
+    font-size: 12px;
+    color: #FFFFFF;
+    opacity: 0;
+}
+
+.my-favor .material-list a:hover .el-image + .el-button {
+    opacity: 1;
+}
+
+.my-favor .material-list a > div:nth-child(2) {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    min-width: 0;
+    padding: 8px 20px 11px;
+}
+
+.my-favor .material-list .title {
+    overflow: hidden;
+    white-space: nowrap;
+    -o-text-overflow: ellipsis;
+       text-overflow: ellipsis;
+    font-size: 18px;
+    color: #282828;
+}
+
+.my-favor .material-list .people {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    min-height: 0;
+    margin-top: 10px;
+    font-size: 14px;
+    color: #999;
+}
+
+.my-favor .material-list .money-vip {
+    font-size: 0;
+}
+
+.my-favor .material-list .money {
+    display: inline-block;
+    vertical-align: middle;
+    font-size: 14px;
+    color: #ff6b00;
+}
+
+.my-favor .material-list .money.free {
+    font-size: 16px;
+}
+
+.my-favor .material-list .money span {
+    font-size: 18px;
+}
+
+.my-favor .material-list .vip {
+    display: inline-block;
+    padding-right: 25px;
+    margin-left: 8px;
+    background: url("../../../images/vip_money.png") left center/21px 13px no-repeat;
+    vertical-align: middle;
+    font-size: 12px;
+    line-height: 13px;
+    color: #282828;
+}
+
+.my-favor .material-list .el-button {
+    -webkit-align-self: center;
+        -ms-flex-item-align: center;
+            align-self: center;
+    padding: 10px 23px;
+    border-color: #2c8eff;
+    border-radius: 19px;
+    font-size: 16px;
+    color: #2c8eff;
+}
+
+.my-favor .el-pagination {
+    padding-top: 58px;
+    padding-bottom: 58px;
+    text-align: center;
+}
+
+.my-favor .el-tabs__content .empty {
+    height: 539px;
+    background: url("../../../images/empty6.png") center/274px no-repeat;
+}

+ 63 - 0
public/pc/components/my/favorite/index.html

xqd
@@ -0,0 +1,63 @@
+<el-tabs v-if="activeName === 'favorite'" v-model="active" class="my-favor" @tab-click="tabClick">
+    <el-tab-pane label="收藏课程" name="0">
+        <template v-if="list1.length">
+            <el-row :gutter="20">
+                <el-col v-for="item in list1" :span="6">
+                    <a :href="(item.is_light ? $router.single_detail : $router.special_detail) + '?id=' + item.id">
+                        <div class="image-group">
+                            <el-image :src="item.image" fit="cover"></el-image>
+                            <el-image v-if="item.type === 1" src="/pc/images/course3.png" fit="cover"></el-image>
+                            <el-image v-else-if="item.type === 2" src="/pc/images/course2.png" fit="cover"></el-image>
+                            <el-image v-else-if="item.type === 3" src="/pc/images/course1.png" fit="cover"></el-image>
+                            <el-button icon="el-icon-close" @click.prevent="specialCollect(item.id)">移除</el-button>
+                        </div>
+                        <div>
+                            <div class="title">{{ item.title }}</div>
+                            <div class="label">
+                                <el-tag v-for="label in item.label">{{ label }}</el-tag>
+                            </div>
+                            <div class="money-count">
+                                <div class="money-vip">
+                                    <template v-if="item.pay_type">
+                                        <div class="money">¥<span>{{ item.money }}</span></div>
+                                        <div class="vip">¥{{ item.member_money }}</div>
+                                    </template>
+                                    <div v-else class="money free">免费</div>
+                                </div>
+                                <div v-if="item.type !== 4 && !item.is_light">共{{ item.count }}节</div>
+                            </div>
+                        </div>
+                    </a>
+                </el-col>
+            </el-row>
+            <el-pagination :page-size="limit" :total="count1" :current-page="page1" layout="prev, pager, next" prev-text="上一页" next-text="下一页" hide-on-single-page @current-change="get_grade_list1"></el-pagination>
+        </template>
+        <div v-else class="empty"></div>
+    </el-tab-pane>
+    <el-tab-pane label="收藏资料" name="1">
+        <template v-if="list2.length">
+            <div class="material-list">
+                <a v-for="item in list2" :href="$router.material_detail + '?id=' + item.id">
+                    <div>
+                        <el-image :src="item.image" fit="cover"></el-image>
+                        <el-button icon="el-icon-close" @click.prevent="materialCollect(item.id)">移除</el-button>
+                    </div>
+                    <div>
+                        <div class="title">{{ item.title }}</div>
+                        <div class="people">{{ item.ficti + item.sales }}人已下载</div>
+                        <div class="money-vip">
+                            <template v-if="item.pay_type">
+                                <div class="money">¥<span>{{ item.money }}</span></div>
+                                <div class="vip">¥{{ item.member_money }}</div>
+                            </template>
+                            <div v-else class="money free">免费</div>
+                        </div>
+                    </div>
+                    <el-button icon="el-icon-download">去下载</el-button>
+                </a>
+            </div>
+            <el-pagination :page-size="limit" :total="count2" :current-page="page2" layout="prev, pager, next" prev-text="上一页" next-text="下一页" hide-on-single-page @current-change="get_grade_list2"></el-pagination>
+        </template>
+        <div v-else class="empty"></div>
+    </el-tab-pane>
+</el-tabs>

+ 113 - 0
public/pc/components/my/favorite/index.js

xqd
@@ -0,0 +1,113 @@
+define([
+    'api/auth',
+    'api/special',
+    'api/material',
+    'text!./index.html',
+    'css!./index.css'
+], function(authApi, specialApi, materialApi, html) {
+    return {
+        props: {
+            activeName: {
+                type: String,
+                default: 'favor'
+            },
+            isLogin: {
+                type: Boolean,
+                default: false
+            }
+        },
+        data: function () {
+            return {
+                page1: 1,
+                page2: 1,
+                limit: 16,
+                active: '0',
+                list1: [],
+                list2: [],
+                finished1: false,
+                finished2: false,
+                count1: 0,
+                count2: 0
+            };
+        },
+        watch: {
+            isLogin: function (value) {
+                if (value) {
+                    this.get_grade_list1();
+                    this.get_grade_list2();
+                }
+            }
+        },
+        methods: {
+            // 课程
+            get_grade_list1: function () {
+                var vm = this;
+                authApi.get_grade_list({
+                    page: this.page1,
+                    limit: this.limit,
+                    active: 0
+                }).then(function (res) {
+                    var data = res.data;
+                    vm.count1 = data.count;
+                    vm.list1 = data.list;
+                    // vm.finished1 = vm.limit > data.list.length;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            // 资料
+            get_grade_list2: function () {
+                var vm = this;
+                authApi.get_grade_list({
+                    page: this.page2,
+                    limit: this.limit,
+                    active: 1
+                }).then(function (res) {
+                    var data = res.data;
+                    vm.count2 = data.count;
+                    vm.list2 = data.list;
+                    // vm.finished2 = vm.limit > data.list.length;
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            // 取消课程收藏
+            specialCollect: function (id) {
+                var vm = this;
+                specialApi.collect({
+                    id: id
+                }).then(function () {
+                    vm.$message.success('取消收藏成功');
+                    if (!(vm.list1.length - 1)) {
+                        if (vm.page1 > 1) {
+                            vm.page1--;
+                        }
+                    }
+                    vm.get_grade_list1();
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            // 取消资料收藏
+            materialCollect: function (id) {
+                var vm = this;
+                materialApi.collect({
+                    id: id
+                }).then(function () {
+                    vm.$message.success('取消收藏成功');
+                    if (!(vm.list2.length - 1)) {
+                        if (vm.page2 > 1) {
+                            vm.page2--;
+                        }
+                    }
+                    vm.get_grade_list2();
+                }).catch(function (err) {
+                    vm.$message.error(err.msg);
+                });
+            },
+            tabClick: function (params) {
+            }
+        },
+        template: html
+    };
+});

+ 126 - 0
public/pc/components/my/lecturer/index.css

xqd
@@ -0,0 +1,126 @@
+.my-lecturer .lecturer-list {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-flex-wrap: wrap;
+    -ms-flex-wrap: wrap;
+    flex-wrap: wrap;
+    -webkit-align-content: flex-start;
+    -ms-flex-line-pack: start;
+    align-content: flex-start;
+    padding: 40px 0 0 39px;
+}
+
+.my-lecturer .item {
+    position: relative;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+    -moz-box-orient: vertical;
+    -moz-box-direction: normal;
+    -ms-flex-direction: column;
+    flex-direction: column;
+    width: 264px;
+    height: 310px;
+    padding-top: 31px;
+    margin: 0 22px 22px 0;
+    -webkit-box-shadow: 0 3px 20px rgba(0, 0, 0, 0.1);
+    box-shadow: 0 3px 20px rgba(0, 0, 0, 0.1);
+}
+
+.my-lecturer .avatar {
+    width: 96px;
+    height: 96px;
+    border-radius: 50%;
+    margin: 0 auto 15px;
+    overflow: hidden;
+}
+
+.my-lecturer .avatar img {
+    width: 100%;
+    height: 100%;
+}
+
+.my-lecturer .item .name {
+    padding: 0 20px;
+    margin-bottom: 15px;
+    overflow: hidden;
+    white-space: nowrap;
+    -o-text-overflow: ellipsis;
+    text-overflow: ellipsis;
+    text-align: center;
+    font-weight: bold;
+    font-size: 18px;
+    line-height: 24px;
+    color: #333333;
+}
+
+.my-lecturer .tags {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-flex-wrap: wrap;
+    -ms-flex-wrap: wrap;
+    flex-wrap: wrap;
+    -webkit-align-content: flex-start;
+    -ms-flex-line-pack: start;
+    align-content: flex-start;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+    -moz-box-pack: center;
+    -ms-flex-pack: center;
+    justify-content: center;
+    padding: 0 20px;
+    margin: 0 -10px 12px 0;
+}
+
+.my-lecturer .tag {
+    height: 24px;
+    padding: 0 10px;
+    border-radius: 2px;
+    margin: 0 10px 10px 0;
+    background-color: #FFF0E5;
+    font-size: 12px;
+    line-height: 24px;
+    color: #FF6B00;
+}
+
+.my-lecturer .info {
+    padding: 0 20px;
+    font-size: 14px;
+    line-height: 22px;
+    color: #707070;
+}
+
+.my-lecturer .item button {
+    position: absolute;
+    top: 12px;
+    right: 12px;
+    z-index: 2;
+    display: none;
+    height: 22px;
+    padding: 0 7px;
+    border: none;
+    border-radius: 2px;
+    background-color: rgba(0, 0, 0, 0.1);
+    font-size: 12px;
+    color: #666666;
+}
+
+.my-lecturer .item:hover button {
+    display: block;
+}
+
+.my-lecturer .item .iconfont {
+    margin-right: 6px;
+    font-size: 12px;
+}

+ 19 - 0
public/pc/components/my/lecturer/index.html

xqd
@@ -0,0 +1,19 @@
+<div class="my-lecturer">
+    <div v-if="followList.length" class="lecturer-list">
+        <a v-for="item in followList" :key="item.id" :href="$router.teacher_detail + '?id=' + item.id" class="item">
+            <button @click.prevent="follow(item)"><i class="iconfont iconguanbi"></i>取消关注</button>
+            <div class="avatar">
+                <img :src="item.lecturer_head" alt="">
+            </div>
+            <div class="name">{{ item.lecturer_name }}</div>
+            <div class="tags">
+                <div v-for="label in item.label" :key="label" class="tag">{{ label }}</div>
+            </div>
+            <div class="info">{{ item.explain }}</div>
+        </a>
+    </div>
+    <el-empty v-if="!followList.length && finished" description=" "></el-empty>
+    <el-pagination :page-size="limit" :total="total" :current-page.sync="page" layout="prev, pager, next" prev-text="上一页" next-text="下一页"
+                   hide-on-single-page>
+    </el-pagination>
+</div>

+ 71 - 0
public/pc/components/my/lecturer/index.js

xqd
@@ -0,0 +1,71 @@
+define([
+    'require',
+    'api/merchant',
+    'text!./index.html',
+    'css!./index.css'
+], function (require, merchantApi, html) {
+    return {
+        props: {
+            activeName: {
+                type: String,
+                default: ''
+            }
+        },
+        data: function () {
+            return {
+                page: 1,
+                limit: 16,
+                total: 0,
+                followList: [],
+                finished: false
+            };
+        },
+        watch: {
+            activeName: function (value) {
+                if (value === 'lecturer') {
+                    this.getFollowList();
+                }
+            },
+            page: function () {
+                this.getFollowList();
+            }
+        },
+        methods: {
+            getFollowList: function () {
+                var vm = this;
+                merchantApi.get_user_follow_list({
+                    page: this.page,
+                    limit: this.limit
+                }).then(function (res) {
+                    var list = res.data.data;
+                    list.forEach(function (item) {
+                        item.label = JSON.parse(item.label);
+                    });
+                    vm.total = res.data.count;
+                    vm.followList = list;
+                    vm.finished = vm.limit > list.length;
+                });
+            },
+            follow: function (item) {
+                var vm = this;
+                merchantApi.user_follow({
+                    mer_id: item.mer_id,
+                    is_follow: 0
+                }).then(function (res) {
+                    if (vm.followList.length > 1) {
+                        vm.getFollowList();
+                    } else {
+                        if (vm.page > 1) {
+                            vm.page -= 1
+                            vm.getFollowList();
+                        } else {
+                            vm.followList = [];
+                        }
+                    }
+                    vm.$message.success('移除成功');
+                });
+            }
+        },
+        template: html
+    };
+});

+ 95 - 0
public/pc/components/my/material/index.css

xqd
@@ -0,0 +1,95 @@
+.my-material .el-row {
+    padding: 40px 50px;
+}
+
+.my-material .el-col {
+    margin-bottom: 20px;
+}
+
+.my-material .el-col a {
+    display: block;
+    border-radius: 8px;
+    overflow: hidden;
+    -webkit-box-shadow: 0 2px 15px rgba(79, 109, 143, 0.15);
+            box-shadow: 0 2px 15px rgba(79, 109, 143, 0.15);
+}
+
+.my-material .el-image {
+    display: block;
+    width: 100%;
+    height: 146px;
+}
+
+.my-material .el-image + div {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+       -moz-box-pack: justify;
+        -ms-flex-pack: justify;
+            justify-content: space-between;
+    height: 124px;
+    padding: 13px 20px 18px;
+    font-size: 14px;
+    color: #999;
+}
+
+.my-material .title {
+    overflow: hidden;
+    white-space: nowrap;
+    -o-text-overflow: ellipsis;
+       text-overflow: ellipsis;
+    font-size: 16px;
+    color: #282828;
+}
+
+.my-material .money-vip {
+    font-size: 0;
+}
+
+.my-material .money {
+    display: inline-block;
+    vertical-align: middle;
+    font-size: 12px;
+    color: #ff6b00;
+}
+
+.my-material .money.free {
+    font-size: 18px;
+}
+
+.my-material .money span {
+    font-size: 20px;
+}
+
+.my-material .vip {
+    display: inline-block;
+    padding-left: 25px;
+    margin-left: 8px;
+    background: url("../../../images/vip_money.png") left center/21px 13px no-repeat;
+    vertical-align: middle;
+    font-size: 12px;
+    line-height: 13px;
+    color: #282828;
+}
+
+.my-material .el-pagination {
+    padding-top: 58px;
+    padding-bottom: 58px;
+    text-align: center;
+}
+
+.my-material .empty {
+    height: 600px;
+    background: url("../../../images/empty8.png") center/274px no-repeat;
+}

+ 24 - 0
public/pc/components/my/material/index.html

xqd
@@ -0,0 +1,24 @@
+<div class="my-material">
+    <template v-if="materialList.length">
+        <el-row :gutter="20">
+            <el-col v-for="(item, index) in materialList" :key="index" :span="6">
+                <a :href="$router.material_detail + '?id=' + item.id">
+                    <el-image :src="item.image" fit="cover"></el-image>
+                    <div>
+                        <div class="title">{{ item.title }}</div>
+                        <div class="money-vip">
+                            <template v-if="item.pay_type">
+                                <div class="money">¥<span>{{ item.money }}</span></div>
+                                <div class="vip">¥{{ item.member_money }}</div>
+                            </template>
+                            <div v-else class="money free">免费</div>
+                        </div>
+                        <div>{{ item.ficti + item.sales }}次下载</div>
+                    </div>
+                </a>
+            </el-col>
+        </el-row>
+        <el-pagination :page-size="limit" :total="total" :current-page="page" layout="prev, pager, next" prev-text="上一页" next-text="下一页" hide-on-single-page @current-change="my_material_list"></el-pagination>
+    </template>
+    <div v-else class="empty"></div>
+</div>

+ 46 - 0
public/pc/components/my/material/index.js

xqd
@@ -0,0 +1,46 @@
+define([
+    'api/auth',
+    'text!./index.html',
+    'css!./index.css'
+], function(authApi, html) {
+    return {
+        props: {
+            isLogin: {
+                type: Boolean,
+                default: false
+            }
+        },
+        data: function () {
+            return {
+                page: 1,
+                limit: 16,
+                total: 0,
+                materialList: [],
+                finished: false
+            };
+        },
+        watch: {
+            isLogin: function (value) {
+                if (value) {
+                    this.my_material_list();
+                }
+            }
+        },
+        methods: {
+            // 资料列表
+            my_material_list: function () {
+                var vm = this;
+                authApi.my_material_list({
+                    page: this.page,
+                    limit: this.limit
+                }).then(function (res) {
+                    var data = res.data;
+                    vm.total = data.count;
+                    vm.materialList = data.data;
+                    vm.finished = vm.limit > data.data.length;
+                });
+            }
+        },
+        template: html
+    };
+});

+ 500 - 0
public/pc/components/my/member/index.css

xqd
@@ -0,0 +1,500 @@
+.my-member {
+    padding-right: 55px;
+    padding-left: 55px;
+}
+
+.my-member .section {
+    padding-top: 40px;
+    padding-bottom: 40px;
+    font-size: 18px;
+    color: #282828;
+}
+
+.my-member .section > div:nth-child(2) {
+    position: relative;
+    padding: 0 50px;
+    margin: 40px 0 0;
+}
+
+.my-member .section:first-child > div:last-child {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+}
+
+.my-member .section:first-child ul {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+}
+
+.my-member .section:first-child li {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+}
+
+.my-member .section:first-child li ~ li {
+    margin-left: 105px;
+}
+
+.my-member .section:first-child img {
+    display: block;
+    width: 60px;
+    height: 60px;
+    padding: 7px;
+    border-radius: 50%;
+    background-color: #fff5e8;
+}
+
+.my-member .section:first-child li > div:last-child {
+    -webkit-box-flex: 1;
+    -webkit-flex: 1;
+       -moz-box-flex: 1;
+        -ms-flex: 1;
+            flex: 1;
+    margin-left: 20px;
+}
+
+.my-member .section:first-child li > div > div:last-child {
+    margin-top: 5px;
+    font-size: 14px;
+    color: #999;
+}
+
+.my-member .section:first-child .el-button {
+    padding: 14px 40px;
+    border-color: #fbe1b8;
+    border-radius: 22px;
+    background: -webkit-gradient(linear, right top, left top, from(#eeb669), to(#fbe1b8));
+    background: -webkit-linear-gradient(right, #eeb669 0%, #fbe1b8 100%);
+    background: -moz-linear-gradient(right, #eeb669 0%, #fbe1b8 100%);
+    background: -o-linear-gradient(right, #eeb669 0%, #fbe1b8 100%);
+    background: linear-gradient(270deg, #eeb669 0%, #fbe1b8 100%);
+    -webkit-box-shadow: 0 3px 20px rgba(235, 209, 173, 0.8);
+            box-shadow: 0 3px 20px rgba(235, 209, 173, 0.8);
+    font-weight: bold;
+    font-size: 16px;
+    color: #9f620e;
+}
+
+.my-member .section:nth-child(2) .swiper-slide {
+    /* width: auto; */
+    width: 380px;
+}
+
+.my-member .section:nth-child(2) .swiper-slide label {
+    /* display: block; */
+}
+
+.my-member .section:nth-child(2) input + div {
+    position: relative;
+    /* width: 280px; */
+    padding: 0 15px;
+    border: 1px solid #D4D4D4;
+    border-radius: 8px;
+}
+
+.my-member .section:nth-child(2) input:checked + div {
+    border-color: #CCA568;
+    -webkit-box-shadow: 0px 3px 15px rgba(161, 126, 71, 0.2);
+            box-shadow: 0px 3px 15px rgba(161, 126, 71, 0.2);
+}
+
+.my-member .section:nth-child(2) input + div > div:first-child {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+       -moz-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    height: 150px;
+    font-size: 20px;
+    color: #282828;
+}
+
+.my-member .section:nth-child(2) img {
+    display: block;
+    width: 50px;
+    height: 45px;
+    margin-bottom: 15px;
+    -o-object-fit: cover;
+       object-fit: cover;
+}
+
+.my-member .section:nth-child(2) input + div > div:nth-child(2) {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+       -moz-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    height: 70px;
+    border-top: 1px dashed #d4d4d4;
+    overflow: hidden;
+    font-size: 16px;
+    line-height: 70px;
+    text-align: center;
+    color: #cca568;
+}
+
+.my-member .section:nth-child(2) input + div .el-icon-check {
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    z-index: 2;
+    width: 22px;
+    height: 21px;
+    border-radius: 0 0 8px 0;
+    background-color: #cca568;
+    font-size: 16px;
+    line-height: 21px;
+    text-align: center;
+    color: #fff;
+    opacity: 0;
+    -webkit-transition: 0.3s;
+    -o-transition: 0.3s;
+    -moz-transition: 0.3s;
+    transition: 0.3s;
+}
+
+.my-member .section:nth-child(2) input + div .el-icon-check::after {
+    content: "";
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    z-index: -1;
+    border-width: 21px 22px;
+    border-style: solid;
+    border-color: transparent #cca568 #CCA568 transparent;
+    border-radius: 0 0 8px 0;
+}
+
+.my-member .section:nth-child(2) input:checked + div .el-icon-check {
+    opacity: 1;
+}
+
+.my-member .section:nth-child(2) span:first-child {
+    font-size: 36px;
+}
+
+.my-member .section:nth-child(2) span:last-child,
+.my-member .section:nth-child(2) del {
+    margin-left: 5px;
+}
+
+.my-member .section:nth-child(3) > div:nth-child(2) {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+}
+
+.my-member .section:nth-child(3) label ~ label {
+    margin-left: 20px;
+}
+
+.my-member .section:nth-child(3) input + div {
+    position: relative;
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+       -moz-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    width: 220px;
+    height: 86px;
+    border: 1px solid #d4d4d4;
+    border-radius: 8px;
+    overflow: hidden;
+    font-size: 16px;
+    line-height: 36px;
+    color: #4e4e4e;
+}
+
+.my-member .section:nth-child(3) input:checked + div {
+    border-color: #2c8eff;
+}
+
+.my-member .section:nth-child(3) input + div > div {
+    padding-left: 48px;
+    background: url("../../../images/alipay.png") left center/36px 36px no-repeat;
+}
+
+.my-member .section:nth-child(3) label:first-child input + div > div {
+    padding-left: 52px;
+    background-image: url("../../../images/wxpay.png");
+    -o-background-size: 40px 36px;
+       background-size: 40px 36px;
+}
+
+.my-member .section:nth-child(3) input + div > div > div {
+    margin-top: 6px;
+    font-size: 14px;
+    color: #969696;
+}
+
+.my-member .section:nth-child(3) > div:last-child {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -moz-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+       -moz-box-orient: vertical;
+       -moz-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+       -moz-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+       -moz-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    padding-top: 87px;
+    padding-bottom: 100px;
+    margin-bottom: -40px;
+}
+
+.my-member .section:nth-child(3) > div:last-child .pay-tip {
+    margin-top: 30px;
+}
+
+.my-member .section:nth-child(3) > div:last-child .btn-group {
+    font-size: 0;
+}
+
+.my-member .section:nth-child(3) > div:last-child .btn-group a {
+    display: inline-block;
+    width: 150px;
+    height: 42px;
+    border-radius: 21px;
+    margin: 50px 0 0;
+    background: #2C8EFF;
+    font-size: 16px;
+    line-height: 42px;
+    text-align: center;
+    color: #FFFFFF;
+}
+
+.my-member .section:nth-child(3) > div:last-child .btn-group a ~ a {
+    display: inline-block;
+    border: 1px solid #999999;
+    border-radius: 21px;
+    margin: 0 0 0 30px;
+    background: transparent;
+    font-size: 16px;
+    line-height: 40px;
+    text-align: center;
+    color: #999999;
+}
+
+.my-member .section:nth-child(3) > div > div:last-child {
+    margin-top: 30px;
+    font-size: 18px;
+    color: #666;
+}
+
+.my-member .section:nth-child(3) div > span {
+    vertical-align: sub;
+    font-weight: bold;
+    font-size: 30px;
+    color: #ff6b00;
+}
+
+.my-member .section:nth-child(3) .el-icon-check {
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    z-index: 2;
+    width: 17px;
+    height: 16px;
+    background-color: #2c8eff;
+    font-size: 14px;
+    line-height: 16px;
+    text-align: center;
+    color: #fff;
+    opacity: 0;
+    -webkit-transition: 0.3s;
+    -o-transition: 0.3s;
+    -moz-transition: 0.3s;
+    transition: 0.3s;
+}
+
+.my-member .section:nth-child(3) .el-icon-check::after {
+    content: "";
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    z-index: -1;
+    border-width: 16px 17px;
+    border-style: solid;
+    border-color: transparent #2c8eff #2c8eff transparent;
+}
+
+.my-member .section:nth-child(3) input:checked + div .el-icon-check {
+    opacity: 1;
+}
+
+.my-member .section:nth-child(3) .el-button {
+    padding: 15px 68px;
+    border-color: #2c8eff;
+    border-radius: 23px;
+    background-color: #2c8eff;
+    font-size: 16px;
+    color: #fff;
+}
+
+.my-member .el-button:focus, .my-member .el-button:hover {
+    border-color: #c6e2ff;
+    background-color: #ecf5ff;
+}
+
+.my-member .section:nth-child(3) .el-button--primary:focus, .my-member .section:nth-child(3) .el-button--primary:hover {
+    border-color: #66b1ff;
+    background-color: #66b1ff;
+}
+
+.my-member .section:nth-child(4) {
+    border-top: 1px dashed #d0d0d0;
+}
+
+.my-member .section:nth-child(4) ol {
+    padding-left: 1em;
+    font-size: 16px;
+    line-height: 26px;
+    color: #999;
+}
+
+.my-member .el-dialog {
+    border-radius: 8px;
+}
+
+.my-member .el-dialog__headerbtn {
+    font-size: 20px;
+}
+
+.my-member .el-dialog__headerbtn .el-dialog__close {
+    color: #8a8a8a;
+}
+
+.my-member .el-dialog__header {
+    padding-top: 30px;
+    padding-bottom: 0;
+}
+
+.my-member .el-dialog__title {
+    padding-right: 114px;
+    padding-left: 114px;
+    background: url("../../../images/member1.png") right center/94px 12px no-repeat,url("../../../images/member2.png") left center/94px 12px no-repeat;
+    font-weight: bold;
+    font-size: 24px;
+    color: #9f620e;
+}
+
+.my-member .el-dialog--center .el-dialog__body {
+    padding: 40px 50px;
+}
+
+.my-member .el-form-item {
+    margin-bottom: 20px;
+}
+
+.my-member .el-form-item:last-child {
+    margin-top: 50px;
+    margin-bottom: 0;
+}
+
+.my-member .el-input__inner {
+    height: 50px;
+    border-color: #dbdbdb;
+    border-radius: 25px;
+    font-size: 16px;
+    line-height: 50px;
+}
+
+.my-member .el-input__inner:hover {
+    border-color: #c0c4cc;
+}
+
+.my-member .el-input.is-active .el-input__inner, .my-member .el-input__inner:focus {
+    border-color: #cca568;
+}
+
+.my-member .el-dialog .el-button {
+    width: 100%;
+    padding-top: 16px;
+    padding-bottom: 16px;
+    border-color: #cca568;
+    border-radius: 25px;
+    background-color: #cca568;
+    font-size: 16px;
+    color: #fff;
+}
+
+.my-member .swiper-button-next:after, .my-member .swiper-button-prev:after {
+    font-size: 35px;
+    color: #E5E5E5;
+}

+ 94 - 0
public/pc/components/my/member/index.html

xqd
@@ -0,0 +1,94 @@
+<div class="my-member">
+    <div class="section">
+        <div>会员权益</div>
+        <div>
+            <ul>
+                <li v-for="item in interests" :key="item.id">
+                    <el-image :src="item.pic" fit="cover">
+                        <div slot="error" class="image-slot">
+                            <i class="el-icon-picture-outline"></i>
+                        </div>
+                    </el-image>
+                    <div>
+                        <div>{{ item.name }}</div>
+                        <div>{{ item.explain }}</div>
+                    </div>
+                </li>
+            </ul>
+            <el-button :disabled="userInfo.level && userInfo.is_permanent" @click="exchangeVisible = true">卡密兑换</el-button>
+        </div>
+    </div>
+    <div class="section">
+        <div>会员套餐</div>
+        <div>
+            <div class="swiper-container">
+                <div class="swiper-wrapper">
+                    <div v-for="(item, index) in memberShipList" :key="item.id" class="swiper-slide">
+                        <label>
+                            <input v-model="filterData.type" :value="index" type="radio" hidden>
+                            <div>
+                                <div>
+                                    <el-image :src="item.img" fit="cover"></el-image>
+                                    <div>{{ item.title }}</div>
+                                </div>
+                                <!-- <div v-if="item.is_free"><span>0</span>元/体验 试用{{ item.vip_day }}天</div>
+                                <div v-else><span>{{ item.price | priceReal }}</span>元<del>{{ item.original_price | priceReal }}元</del></div> -->
+                                <div v-if="item.is_free"><span>0</span>元/体验 试用{{ item.vip_day }}天</div>
+                                <div v-else>¥<span>{{ item.price | priceReal }}</span><del>¥{{ item.original_price | priceReal }}</del></div>
+                                <i class="el-icon-check"></i>
+                            </div>
+                        </label>
+                    </div>
+                </div>
+            </div>
+            <div class="swiper-button-prev swiper-button-black"></div>
+            <div class="swiper-button-next swiper-button-black"></div>
+        </div>
+    </div>
+    <div v-show="!userInfo.level || !userInfo.is_permanent" class="section">
+        <div>支付方式</div>
+        <div>
+            <label v-if="isWechat">
+                <input v-model="filterData.payType" value="weixin" type="radio" hidden>
+                <div>
+                    <div>微信支付</div>
+                    <i class="el-icon-check"></i>
+                </div>
+            </label>
+            <label v-if="isAlipay">
+                <input v-model="filterData.payType" value="zhifubao" type="radio" hidden>
+                <div>
+                    <div>支付宝支付</div>
+                    <i class="el-icon-check"></i>
+                </div>
+            </label>
+        </div>
+        <div>
+            <div v-show="!isReset" ref="qrcode"></div>
+            <div v-show="!isReset" class="pay-tip">请用{{ filterData.payType === 'weixin' ? '微信' : '支付宝' }}扫码支付,支付<span>{{ memberShipList.length && memberShipList[filterData.type].price | priceReal }}</span>元
+            </div>
+            <el-button v-show="isReset" @click="create_order" :disabled="!filterData.payType">去支付</el-button>
+        </div>
+    </div>
+    <div class="section">
+        <div>会员说明</div>
+        <div>
+            <ol>
+                <li v-for="item in description" :key="item.id">{{ item.text }}</li>
+            </ol>
+        </div>
+    </div>
+    <el-dialog title="激活会员卡" :visible.sync="exchangeVisible" width="512px" center>
+        <el-form>
+            <el-form-item>
+                <el-input v-model.trim="member_code" type="text" placeholder="请输入卡号" autocomplete="off"></el-input>
+            </el-form-item>
+            <el-form-item>
+                <el-input v-model.trim="member_pwd" placeholder="请输入卡密" autocomplete="off" show-password></el-input>
+            </el-form-item>
+            <el-form-item>
+                <el-button @click.native="confirm_activation">确定</el-button>
+            </el-form-item>
+        </el-form>
+    </el-dialog>
+</div>

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