walter 11 bulan lalu
induk
melakukan
cf939de44d
59 mengubah file dengan 7716 tambahan dan 835 penghapusan
  1. 1 0
      .gitignore
  2. 1 0
      build/webpack.dev.conf.js
  3. 2 2
      config/index.js
  4. 68 0
      package-lock.json
  5. 6 2
      package.json
  6. 3 3
      src/App.vue
  7. 13 1
      src/api/websocketTow.js
  8. 29 0
      src/assets/iconfont.css
  9. TEMPAT SAMPAH
      src/assets/images/courseLogin.png
  10. TEMPAT SAMPAH
      src/assets/images/courseUser.png
  11. TEMPAT SAMPAH
      src/assets/images/headLogo.jpg
  12. 40 36
      src/main.js
  13. 8 1
      src/okr/view/okrHome.vue
  14. 8 1
      src/okr/view/project/projectList.vue
  15. 59 19
      src/permission.js
  16. 143 5
      src/point/view/pointHome.vue
  17. 102 0
      src/router/course.js
  18. 9 0
      src/router/index.js
  19. 4 1
      src/store/getters.js
  20. 1 0
      src/store/modules/user.js
  21. 51 0
      src/utils/auth.js
  22. 167 0
      src/utils/axiosKc.js
  23. 13 5
      src/utils/axiosUser.js
  24. 338 0
      src/view/course/api/index.js
  25. 159 0
      src/view/course/components/CourseTeam.vue
  26. 296 0
      src/view/course/components/courseList.vue
  27. 203 0
      src/view/course/deal/dealOrder.vue
  28. 172 0
      src/view/course/deal/limitRecord.vue
  29. 257 0
      src/view/course/deal/transfer.vue
  30. 33 0
      src/view/course/error.vue
  31. 238 0
      src/view/course/home.vue
  32. 546 0
      src/view/course/user.vue
  33. 439 0
      src/view/course/user/courseAdDeal.vue
  34. 423 0
      src/view/course/user/courseDeal.vue
  35. 403 0
      src/view/course/user/deal.vue
  36. 208 0
      src/view/course/user/login.vue
  37. 160 0
      src/view/course/user/team.vue
  38. 155 0
      src/view/course/user/wxAuth.vue
  39. 591 0
      src/view/course/user_qr2img_next.vue
  40. 266 0
      src/view/course/utils/convas2Images.js
  41. 152 0
      src/view/course/utils/index.js
  42. 16 0
      src/view/course/utils/navBar.scss
  43. 338 0
      src/view/course/video/courseVideo.vue
  44. 310 0
      src/view/course/video/freeVideo.vue
  45. 2 0
      src/view/user/account.vue
  46. 56 64
      src/view/user/accountSet.vue
  47. 9 3
      src/view/user/accountVf.vue
  48. 44 3
      src/view/user/create_company.vue
  49. 222 0
      src/view/user/iosIntercept.vue
  50. 699 576
      src/view/user/login.vue
  51. 41 5
      src/view/user/login_company_list.vue
  52. 3 1
      src/view/user/regWx.vue
  53. 5 1
      src/view/user/registration_experience.vue
  54. 28 4
      src/view/user/verify.vue
  55. 176 102
      src/view/user/wxInit.vue
  56. TEMPAT SAMPAH
      static/images/course_dingdan.png
  57. TEMPAT SAMPAH
      static/images/course_ewm.png
  58. TEMPAT SAMPAH
      static/images/course_logo.png
  59. TEMPAT SAMPAH
      static/images/course_team.png

+ 1 - 0
.gitignore

@@ -1,6 +1,7 @@
 .DS_Store
 node_modules/
 /dist/
+/devtest/
 npm-debug.log*
 yarn-debug.log*
 yarn-error.log*

+ 1 - 0
build/webpack.dev.conf.js

@@ -36,6 +36,7 @@ const devWebpackConfig = merge(baseWebpackConfig, {
     compress: true,
     host: HOST || config.dev.host,
     port: PORT || config.dev.port,
+    disableHostCheck: true,
     open: config.dev.autoOpenBrowser,
     overlay: config.dev.errorOverlay ?
       {

+ 2 - 2
config/index.js

@@ -13,8 +13,8 @@ module.exports = {
     proxyTable: {},
 
     // Various Dev Server settings
-    host: 'localhost', // can be overwritten by process.env.HOST
-    port: 8089, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
+    host: '0.0.0.0', // can be overwritten by process.env.HOST
+    port: 8088, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
     autoOpenBrowser: false,
     errorOverlay: true,
     notifyOnErrors: true,

+ 68 - 0
package-lock.json

@@ -2724,6 +2724,16 @@
       "integrity": "sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg==",
       "dev": true
     },
+    "clipboard": {
+      "version": "2.0.11",
+      "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
+      "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
+      "requires": {
+        "good-listener": "^1.2.2",
+        "select": "^1.1.2",
+        "tiny-emitter": "^2.0.0"
+      }
+    },
     "cliui": {
       "version": "2.1.0",
       "resolved": "https://registry.npmmirror.com/cliui/-/cliui-2.1.0.tgz",
@@ -3945,6 +3955,11 @@
       "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
       "dev": true
     },
+    "delegate": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
+      "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw=="
+    },
     "delegates": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/delegates/-/delegates-1.0.0.tgz",
@@ -5806,6 +5821,14 @@
         }
       }
     },
+    "good-listener": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
+      "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==",
+      "requires": {
+        "delegate": "^3.1.2"
+      }
+    },
     "gopd": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz",
@@ -8487,6 +8510,11 @@
         "through2": "^2.0.0"
       }
     },
+    "mitt": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/mitt/-/mitt-2.1.0.tgz",
+      "integrity": "sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg=="
+    },
     "mixin-deep": {
       "version": "1.3.2",
       "resolved": "https://registry.npmmirror.com/mixin-deep/-/mixin-deep-1.3.2.tgz",
@@ -11241,6 +11269,11 @@
       "resolved": "https://registry.npmmirror.com/qrcode.vue/-/qrcode.vue-1.7.0.tgz",
       "integrity": "sha512-R7t6Y3fDDtcU7L4rtqwGUDP9xD64gJhIwpfjhRCTKmBoYF6SS49PIJHRJ048cse6OI7iwTwgyy2C46N9Ygoc6g=="
     },
+    "qrcodejs2": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmmirror.com/qrcodejs2/-/qrcodejs2-0.0.2.tgz",
+      "integrity": "sha512-+Y4HA+cb6qUzdgvI3KML8GYpMFwB24dFwzMkS/yXq6hwtUGNUnZQdUnksrV1XGMc2mid5ROw5SAuY9XhI3ValA=="
+    },
     "qs": {
       "version": "6.11.2",
       "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
@@ -12321,6 +12354,11 @@
         }
       }
     },
+    "select": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
+      "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA=="
+    },
     "select-hose": {
       "version": "2.0.0",
       "resolved": "https://registry.npmmirror.com/select-hose/-/select-hose-2.0.0.tgz",
@@ -13802,6 +13840,11 @@
       "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==",
       "dev": true
     },
+    "tiny-emitter": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
+      "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
+    },
     "to-arraybuffer": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
@@ -14598,6 +14641,16 @@
         }
       }
     },
+    "vue-observe-visibility": {
+      "version": "2.0.0-alpha.1",
+      "resolved": "https://registry.npmmirror.com/vue-observe-visibility/-/vue-observe-visibility-2.0.0-alpha.1.tgz",
+      "integrity": "sha512-flFbp/gs9pZniXR6fans8smv1kDScJ8RS7rEpMjhVabiKeq7Qz3D9+eGsypncjfIyyU84saU88XZ0zjbD6Gq/g=="
+    },
+    "vue-resize": {
+      "version": "2.0.0-alpha.1",
+      "resolved": "https://registry.npmmirror.com/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz",
+      "integrity": "sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg=="
+    },
     "vue-router": {
       "version": "3.6.5",
       "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-3.6.5.tgz",
@@ -14645,6 +14698,16 @@
       "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
       "dev": true
     },
+    "vue-virtual-scroller": {
+      "version": "2.0.0-beta.8",
+      "resolved": "https://registry.npmmirror.com/vue-virtual-scroller/-/vue-virtual-scroller-2.0.0-beta.8.tgz",
+      "integrity": "sha512-b8/f5NQ5nIEBRTNi6GcPItE4s7kxNHw2AIHLtDp+2QvqdTjVN0FgONwX9cr53jWRgnu+HRLPaWDOR2JPI5MTfQ==",
+      "requires": {
+        "mitt": "^2.1.0",
+        "vue-observe-visibility": "^2.0.0-alpha.1",
+        "vue-resize": "^2.0.0-alpha.1"
+      }
+    },
     "vue2-svg-icon": {
       "version": "1.3.2",
       "resolved": "https://registry.npmmirror.com/vue2-svg-icon/-/vue2-svg-icon-1.3.2.tgz",
@@ -16515,6 +16578,11 @@
       "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
       "dev": true
     },
+    "weixin-js-sdk": {
+      "version": "1.6.5",
+      "resolved": "https://registry.npmmirror.com/weixin-js-sdk/-/weixin-js-sdk-1.6.5.tgz",
+      "integrity": "sha512-Gph1WAWB2YN/lMOFB/ymb+hbU/wYazzJgu6PMMktCy9cSCeW5wA6Zwt0dpahJbJ+RJEwtTv2x9iIu0U4enuVSQ=="
+    },
     "when": {
       "version": "3.6.4",
       "resolved": "https://registry.npmmirror.com/when/-/when-3.6.4.tgz",

+ 6 - 2
package.json

@@ -14,16 +14,18 @@
   "dependencies": {
     "axios": "^0.18.1",
     "better-scroll": "^1.15.2",
+    "clipboard": "^2.0.11",
     "dayjs": "^1.10.5",
     "echarts": "^4.7.0",
     "exif-js": "^2.3.0",
     "fastclick": "^1.0.6",
     "html2canvas": "^1.0.0-rc.3",
-    "jsencrypt": "^3.2.1",
+    "jsencrypt": "^3.3.2",
     "lrz": "^4.9.40",
     "moment": "^2.24.0",
     "px2rem-loader": "^0.1.9",
     "qrcode.vue": "^1.6.3",
+    "qrcodejs2": "0.0.2",
     "qs": "^6.9.6",
     "sortablejs": "^1.14.0",
     "swiper": "^5.2.1",
@@ -40,10 +42,12 @@
     "vue-router": "^3.1.6",
     "vue-scroller": "^2.2.4",
     "vue-shepherd": "^3.0.0",
+    "vue-virtual-scroller": "^2.0.0-beta.8",
     "vue2-svg-icon": "^1.3.2",
     "vuex": "^3.3.0",
     "vuex-persistedstate": "^3.1.0",
-    "webpack-bundle-analyzer": "^4.4.2"
+    "webpack-bundle-analyzer": "^4.4.2",
+    "weixin-js-sdk": "^1.6.5"
   },
   "devDependencies": {
     "autoprefixer": "^7.1.2",

+ 3 - 3
src/App.vue

@@ -1,11 +1,10 @@
 <template>
   <div style="width:100%; height: 100%; position: relative;">
-     <vc-keep-alive :ignorePaths="['/help_detail']" :ignoreParams="[]">
+     <vc-keep-alive :ignorePaths="ignorePaths" :ignoreParams="ignoreParams">
         <router-view style="width:100%;height:100%"></router-view>
      </vc-keep-alive>
   </div>
 </template>
-
 <script>
   import Vue from 'vue';
   import FastClick from 'fastclick'
@@ -15,7 +14,8 @@
     name: 'App',
     data() {
       return {
-
+        ignorePaths:['/help_detail'],
+        ignoreParams:[]
       };
     },
     methods: {

+ 13 - 1
src/api/websocketTow.js

@@ -16,6 +16,7 @@ let websocketonmessage = e => {
 			ws.send('保持连接')
 		}
 	}
+  if(typeof weboscket_callback !== 'function') return null;
 	return weboscket_callback(data);
 }
 
@@ -65,6 +66,16 @@ let initWebSocket = () => {
 	ws.onclose = websocketclose
 }
 
+let authWebSocket = (callback) => {
+  if(!ws) initWebSocket();
+  let params = {
+    type: 'auth',
+    token: getToken(),
+    machine:generateUUID()
+  };
+  sendData(params,callback);
+}
+
 // 发送数据
 let sendData = (data, callback) => {
 	weboscket_callback = callback
@@ -99,5 +110,6 @@ let sendData = (data, callback) => {
 export {
 	initWebSocket,
 	sendData,
-	closewebsocket
+	closewebsocket,
+  authWebSocket
 }

+ 29 - 0
src/assets/iconfont.css

@@ -0,0 +1,29 @@
+@font-face {
+  font-family: "courseIcon"; /* Project id 4478034 */
+  src: url("//at.alicdn.com/t/c/font_4478034_feuwvdh5ol8.woff2?t=1711172080312")
+      format("woff2"),
+    url("//at.alicdn.com/t/c/font_4478034_feuwvdh5ol8.woff?t=1711172080312")
+      format("woff"),
+    url("//at.alicdn.com/t/c/font_4478034_feuwvdh5ol8.ttf?t=1711172080312")
+      format("truetype");
+}
+
+.courseIcon {
+  font-family: "courseIcon" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-shenfenzheng:before {
+  content: "\e61b";
+}
+
+.icon-erweima:before {
+  content: "\e7ad";
+}
+
+.icon-fuzhi:before {
+  content: "\e8b0";
+}

TEMPAT SAMPAH
src/assets/images/courseLogin.png


TEMPAT SAMPAH
src/assets/images/courseUser.png


TEMPAT SAMPAH
src/assets/images/headLogo.jpg


+ 40 - 36
src/main.js

@@ -20,17 +20,18 @@ import * as socketApiTow from '@/api/websocketTow'
 import axios from '@/utils/axios'
 import axiosKq from '@/utils/axiosKq'
 import axiosUser from '@/utils/axiosUser'
+import axiosKc from '@/utils/axiosKc'
 import 'shepherd.js/dist/css/shepherd.css';
 
-import {Tabbar,Empty,TabbarItem,Grid,GridItem,Field,NavBar,Row,Col, Cell,CellGroup,Toast,Popup,Dialog,RadioGroup,Radio,Notify,Button,Icon} from 'vant'
-import {getIsIdentity,supremeAuthority, getIsWx,getTypes, getTypesName,getUserData, getEmployeeMap,getCache,setCache,removeCache,returnDeptName,getEmployeeMapItem,returnFh } from '@/utils/auth'
+import { Tabbar, Empty, TabbarItem, ShareSheet, Loading, Divider, Overlay,Grid, GridItem, Form, Field, NavBar, Row, Col, List, Picker, Cell, CellGroup, Toast, Popup, Dialog, RadioGroup, Radio, Notify, Button, Icon, Tab, Tabs } from 'vant'
+import { getWxToken, setWxToken, getIsIdentity, supremeAuthority, getIsWx, getTypes, getTypesName, getUserData, getEmployeeMap, getCache, setCache, removeCache, returnDeptName, getEmployeeMapItem, returnFh } from '@/utils/auth'
 Vue.prototype.$echarts = echarts
 Vue.prototype.$moment = moment
 Vue.prototype.$getTypesName = getTypesName
 Vue.prototype.$getTypes = getTypes()
 Vue.prototype.$userInfo = getUserData;
 Vue.prototype.$getEmployeeMap = getEmployeeMap
-Vue.prototype.$getEmployeeMapItem= getEmployeeMapItem
+Vue.prototype.$getEmployeeMapItem = getEmployeeMapItem
 Vue.prototype.$getCache = getCache
 Vue.prototype.$setCache = setCache
 Vue.prototype.$getIsIdentity = getIsIdentity
@@ -38,25 +39,28 @@ Vue.prototype.$supremeAuthority = supremeAuthority
 Vue.prototype.$axios = axios
 Vue.prototype.$axiosUser = axiosUser
 Vue.prototype.$axiosKq = axiosKq
+Vue.prototype.$axiosKc = axiosKc
 Vue.prototype.$removeCache = removeCache
 Vue.prototype.$returnDeptName = returnDeptName
 Vue.prototype.$socketApi = socketApi   //长连接
 Vue.prototype.$socketApiTow = socketApiTow   //长连接
 Vue.prototype.$returnFh = returnFh
-Vue.prototype.$isWx=getIsWx()
+Vue.prototype.$isWx = getIsWx()
+
+// localStorage.setItem('Wx-Token','eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjE3ODIzNDkxMTYyMzI4OTI0MTcsIm5iZiI6MTcxMzg0MzIzMjY2Niwicm9sZSI6Im1rdF91c2VyIiwicHJ2IjoiMGU1ZWM0NzM3NDk3NmFmY2NlZGJiY2Y1ZGVlNzVmMDE0Y2E1YjliNSIsImV4cCI6LTEsImlhdCI6MTcxMzg0MzIzMjY2NiwianRpIjoieGJ5N3ljbWxqNGduYXcybyJ9.Iv04__mjBDEV75QU8kbrJX2umQIKDZE87-kTD5LG4vg')
+// localStorage.setItem('wx_user_info',JSON.stringify({"id":"1782349116232892417","name":"雷阳","mobile":"15270803986","statistics":{"teamAmount":0,"saleAmount":0},"imgUrl":"","marketable":1,"utoken":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjE3ODIzNDkxMTYyMzI4OTI0MTcsIm5iZiI6MTcxMzg0MzIzMjY2Niwicm9sZSI6Im1rdF91c2VyIiwicHJ2IjoiMGU1ZWM0NzM3NDk3NmFmY2NlZGJiY2Y1ZGVlNzVmMDE0Y2E1YjliNSIsImV4cCI6LTEsImlhdCI6MTcxMzg0MzIzMjY2NiwianRpIjoieGJ5N3ljbWxqNGduYXcybyJ9.Iv04__mjBDEV75QU8kbrJX2umQIKDZE87-kTD5LG4vg"}))
 
 // true为APP打包,false为M端打包
 Vue.prototype.$isApp = true
 
-
 Vue.use(VueScroller)
 Vue.component('icon', icon)
 Vue.component('noData', noData)
 Vue.component('userImage', userImage)
-Vue.use(Button).use(Tabbar).use(TabbarItem).use(Grid).use(GridItem).use(Field).use(NavBar).use(Row).use(Col).use(Cell).use(CellGroup).use(Toast).use(Popup).use(Dialog).use(RadioGroup).use(Radio).use(Icon).use(Notify).use(Empty)
+Vue.use(Button).use(Tabbar).use(TabbarItem).use(ShareSheet).use(Grid).use(Overlay).use(Loading).use(Divider).use(GridItem).use(Picker).use(Form).use(Field).use(List).use(Tabs).use(Tab).use(NavBar).use(Row).use(Col).use(Cell).use(CellGroup).use(Toast).use(Popup).use(Dialog).use(RadioGroup).use(Radio).use(Icon).use(Notify).use(Empty)
 
-Vue.prototype.$route_back = function(setp) {
-  if (typeof(setp) == 'undefined') {
+Vue.prototype.$route_back = function (setp) {
+  if (typeof (setp) == 'undefined') {
     setp = -1
   }
   if (window.history.length <= 1 && window.plus) {
@@ -71,36 +75,36 @@ Vue.prototype.$route_back = function(setp) {
 }
 
 Vue.directive('isKeyboard', function (el) {
-    let isAndroid=true;
-    if (navigator.userAgent.indexOf('Android') > 0) {
-      isAndroid=true;
-    } else {
-      isAndroid=false;
-    }
-    if (isAndroid) {
-      //获取原窗口的高度
-      var originalHeight = document.documentElement.clientHeight || document.body.clientHeight;
-      window.onresize = function() {
-        //键盘弹起与隐藏都会引起窗口的高度发生变化
-        var resizeHeight =document.documentElement.clientHeight || document.body.clientHeight;
-        if (resizeHeight - 0 < originalHeight - 0) {
-          // console.log("键盘收起")
-          el.style['display'] = 'none'
-        } else {
-           // console.log("键盘放下")
-          el.style['display'] = 'block'
-        }
-      };
-    }else {  // ios:focusin和focusout支持冒泡,对应focus和blur, 使用focusin和focusout的原因是focusin和focusout可以冒泡,focus和blur不会冒泡,这样就可以使用事件代理,处理多个输入框存在的情况。
-      document.body.addEventListener("focusin", () => {
-        //软键盘弹出的事件处理
+  let isAndroid = true;
+  if (navigator.userAgent.indexOf('Android') > 0) {
+    isAndroid = true;
+  } else {
+    isAndroid = false;
+  }
+  if (isAndroid) {
+    //获取原窗口的高度
+    var originalHeight = document.documentElement.clientHeight || document.body.clientHeight;
+    window.onresize = function () {
+      //键盘弹起与隐藏都会引起窗口的高度发生变化
+      var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
+      if (resizeHeight - 0 < originalHeight - 0) {
+        // console.log("键盘收起")
         el.style['display'] = 'none'
-      });
-      document.body.addEventListener("focusout", () => {
-        //软键盘收起的事件处理
+      } else {
+        // console.log("键盘放下")
         el.style['display'] = 'block'
-      });
-    }
+      }
+    };
+  } else {  // ios:focusin和focusout支持冒泡,对应focus和blur, 使用focusin和focusout的原因是focusin和focusout可以冒泡,focus和blur不会冒泡,这样就可以使用事件代理,处理多个输入框存在的情况。
+    document.body.addEventListener("focusin", () => {
+      //软键盘弹出的事件处理
+      el.style['display'] = 'none'
+    });
+    document.body.addEventListener("focusout", () => {
+      //软键盘收起的事件处理
+      el.style['display'] = 'block'
+    });
+  }
 })
 
 Vue.config.productionTip = false

+ 8 - 1
src/okr/view/okrHome.vue

@@ -108,7 +108,7 @@
                 <van-circle
                   layer-color="#E5E9F2"
                   v-model="item.currentRate"
-                  :color="item.day<0 ? '#f56c6c' : ' #2879ff'"
+                  :color="barColor(item)"
                   :rate="item.process"
                   :key="index"
                   size="50px"
@@ -167,6 +167,13 @@ export default {
     this.getTaskList();
     this.getProjectList();
   },
+  computed:{
+    barColor(){
+      return function (item) { 
+        return item.day<0 ? (item.composite_state == 4?'#2879ff':'#f56c6c'):'#2879ff'
+       }
+    },
+  },
   methods: {
     getUnitList(){
       this.$axiosUser('get', '/api/pro/okr/kr/unit_list').then(res => {

+ 8 - 1
src/okr/view/project/projectList.vue

@@ -40,7 +40,7 @@
                 @click.stop="openDetail(item)"
                 layer-color="#E5E9F2"
                 v-model="item.currentRate"
-                :color="item.day<0 ? '#f56c6c' : ' #2879ff'"
+                :color="barColor(item)"
                 :rate="item.process"
                 :key="index"
                 size="50px"
@@ -166,6 +166,13 @@ export default {
 
     },
   },
+  computed:{
+    barColor(){
+      return function (item) { 
+        return item.day<0 ? (item.composite_state == 4?'#2879ff':'#f56c6c'):'#2879ff'
+       }
+    },
+  },
   methods: {
     confirmDept(val){
       this.selected_data=val;

+ 59 - 19
src/permission.js

@@ -1,19 +1,27 @@
 import Vue from 'vue'
 import router from './router'
 import store from './store'
-import {getToken} from '@/utils/auth'
+import { getToken, getWxToken } from '@/utils/auth'
+//课程免登录名单
+const whiteList = ['/courseHome', '/courseLogin','/courseUser','/courseError','/courseAuth','/courseDeal', '/course/adlist', '/course/limitChange', '/course/courseManage', '/course/courseCreate', '/course/dealerManage']
+const whiteList2 = ['/courseDeal/', '/courseDetail/','/courseTeam/', '/courseAdDetail/', '/course/limitChange/', '/course/transfer/', '/course/video/', '/course/dealOrder/']
+function filterWhite(path) {
+  return whiteList2.some(item => {
+    return path.includes(item)
+  })
+}
 router.beforeEach((to, from, next) => {
   if (Vue.$httpRequestList.length > 0) { //强行中断时才向下执行
     Vue.$httpRequestList.forEach(item => {
       item('interrupt'); //给个标志,中断请求
     })
   }
-  if (getToken()) {
-    if (to.path == '/login'||to.path == '/') { // 在免登录白名单,直接进入
-      next({ name: 'home'})
+  if (getToken() && whiteList.indexOf(to.path) == -1 && !filterWhite(to.path)) {
+    if (to.path == '/login' || to.path == '/') { // 在免登录白名单,直接进入
+      next({ name: 'home' })
       return false
     }
-    if (typeof(window.$routes_map[to.name]) != 'undefined') {
+    if (typeof (window.$routes_map[to.name]) != 'undefined') {
       window.document.title = window.$routes_map[to.name].label
     } else {
       window.document.title = '管理中心'
@@ -21,16 +29,48 @@ router.beforeEach((to, from, next) => {
     // 初始一些数据
     init(next);
     // next();
-  } else {
-      if (!window.$routes_map[to.name].need_login) { // 在免登录白名单,直接进入
-        if (typeof(window.$routes_map[to.name]) != 'undefined') {
-          window.document.title = window.$routes_map[to.name].label
-        }
-        next()
+  } else if (whiteList.indexOf(to.path) != -1 || filterWhite(to.path)) {
+    if ((getWxToken()&&localStorage.getItem('wx_user_info')) || to.path == '/courseAuth') {
+      if (typeof (window.$routes_map[to.name]) != 'undefined') {
+        window.document.title = window.$routes_map[to.name].label
       } else {
-        window.document.title = '用户登录'
-        next('/login')
+        window.document.title = '功道云课程'
       }
+      next()
+    } else{
+      if(to.path.includes('/courseDetail/')&&to.query&&to.query.code){
+        next({
+          path:`/courseAuth`,
+          query:{
+            code:`${to.query.code}-${to.params.id}`
+          }
+        })
+      }else if(to.fullPath.includes('/courseLogin')&&to.query&&to.query.pid != undefined){
+        next({
+          path:`/courseAuth`,
+          query:{
+            pid:to.query.pid
+          }
+        })
+      }else{
+        // sessionStorage.setItem('cur_path',to.path)
+        next({
+          path:`/courseAuth`,
+        })
+      }
+    }
+  }else if(((to.path == '/verify') || (to.path == '/accountVf') || (to.path == '/iosIntercept')) && localStorage.getItem('a-token-temp')){
+    next()
+  } else {
+    if (!window.$routes_map[to.name].need_login) { // 在免登录白名单,直接进入
+      if (typeof (window.$routes_map[to.name]) != 'undefined') {
+        window.document.title = window.$routes_map[to.name].label
+      }
+      next()
+    } else {         
+      window.document.title = '用户登录'
+      next('/login')
+    }
   }
 })
 /* 路由异常错误处理,尝试解析一个异步组件时发生错误,重新渲染目标页面 */
@@ -45,17 +85,17 @@ router.onError((error) => {
 function init(next) {
   store.dispatch('get_user_info').then((res) => { //获取用户信息
     if (router.history.current.name == 'login') {
-      router.push({name: 'home'})
+      router.push({ name: 'home' })
       return false
     }
     next()
-  }).catch(()=>{
+  }).catch(() => {
     next()
   })
-  store.dispatch('get_point_types').then(res => {}); //获取积分类型
+  store.dispatch('get_point_types').then(res => { }); //获取积分类型
 
   // 数据更新,每两分钟更新一次
-  store.dispatch('get_employee_map').then((res) => {}); //获取人员列表
-  store.dispatch('get_account_info').then((res) => {}); //获取公司信息
-  store.dispatch('get_site_info').then((res) => {})//公司信息
+  store.dispatch('get_employee_map').then((res) => { }); //获取人员列表
+  store.dispatch('get_account_info').then((res) => { }); //获取公司信息
+  store.dispatch('get_site_info').then((res) => { })//公司信息
 }

+ 143 - 5
src/point/view/pointHome.vue

@@ -100,6 +100,7 @@
         </div>
       </div>
 
+
       <!-- 管理者奖扣 -->
       <div class="chart-statistics__item" v-if="!$supremeAuthority('employee')">
         <div style="padding: 0.28rem 0.32rem;border-bottom: 1px solid #f1f1f1;color: #222;">
@@ -137,6 +138,24 @@
           <i class="van-icon van-icon-arrow van-cell__right-icon"></i>
         </div>
       </div>
+
+<!--  团队PK    -->
+      <div class="rankingList" style="border-top: 0.2rem solid #f1f1f1;" v-if="pk.pkDocList.length > 0">
+        <van-cell title="团队PK" :value="pk.pkTimeScopeStr" is-link @click="openCalendar"></van-cell>
+        <van-tabs
+          v-model="pk.pkDocIndex"
+          @click="clickPkDoc"
+        >
+          <van-tab v-for="(doc,index) in pk.pkDocList" :key="index" :title="doc.name">
+            <van-cell-group v-if="pk.pkTeamList.length > 0">
+              <van-cell v-for="(team,index) in pk.pkTeamList" :key="index" :title="team.name" :value="team.point"  />
+            </van-cell-group>
+            <no-data v-if="pk.pkTeamList.length === 0"></no-data>
+          </van-tab>
+        </van-tabs>
+      </div>
+
+<!--   底部透明垫   -->
       <div style="height: 1rem;"></div>
     </scroller>
     <van-dialog v-model="isShowDialog">
@@ -146,15 +165,27 @@
         <div>其他排名:除上述两种系统预设的排名,企业也可以前往【PC端】自行组合排名条件,设置适合自身使用的积分排名</div>
       </div>
     </van-dialog>
+    <van-calendar
+      v-model="pk.showDocDatePicker"
+      type="range"
+      :allow-same-day="true"
+      @close="docCalendarClose"
+      @confirm="docCalendarConfirm"
+      :min-date="pk.minDate"
+      :max-date="pk.maxDate"
+      :default-date="pkTimeScope"
+      color="#26A2FF"
+    />
   </div>
 </template>
 
 <script>
 
 import {getToken, setToken} from '@/utils/auth';
-import moment from 'moment';
+import moment, {min} from 'moment';
 import Vue from 'vue';
 import { NoticeBar, Swipe, SwipeItem, Cell, Dialog,Popup  } from 'vant';
+import {authWebSocket} from "../../api/websocketTow";
 Vue.use(NoticeBar)
   .use(Swipe)
   .use(SwipeItem)
@@ -167,7 +198,7 @@ export default {
     return {
       userMonth:{task:{reward:{},deduction:{},exec:{}},ratio:{}},
 
-      rankingList: [], // 我的排名列表
+      // rankingList: [], // 我的排名列表
       rankingTotal: 0, // 我的排名列表数
       situationChart: '', // 管理者奖扣
       rankingIndex: 1,
@@ -205,6 +236,23 @@ export default {
       review_count: 0,
       task_count: 0,
       cuntNum: { deal: 0, notice: '' },
+      pkTimeScope:[],
+      pk:{
+        pkDocList:[],
+        minDate:null,
+        maxDate:null,
+        pkTimeScope:[],
+        pkTimeScopeStr:'',
+        currentDocIndex:0,
+        pkDocIndex:0,
+        showDocDatePicker:false,
+        teamLoading:false,
+        pkTeamList:[]
+      },
+      savedScrollPosition:{
+        left:0,
+        top:0
+      },
     };
   },
   created() {
@@ -212,6 +260,27 @@ export default {
     this.$store.dispatch('getMenu').then(res => {
       this.getMenu(res);
     });
+
+    //初始化pk配置
+    const today = new Date();
+    const minDate = new Date();
+    minDate.setTime(today.getTime() - 3600 * 1000 * 24 * 30 * 6);
+    const maxDate = new Date(today.getFullYear(),today.getMonth(),1);
+    maxDate.setMonth(maxDate.getMonth() + 1);
+    maxDate.setDate(0);
+
+    this.pk.minDate = minDate;
+    this.pk.maxDate = maxDate;
+
+    const startDate = new Date();
+    const endDate = new Date();
+    startDate.setTime(endDate.getTime() - 3600 * 1000 * 24 * 30);
+    this.pkTimeScope = [startDate,endDate]
+    this.pk.pkTimeScope[0] = startDate;
+    this.pk.pkTimeScope[1] = endDate;
+    this.pk.pkTimeScopeStr = this.$moment(startDate).format("MM/DD") + "-" + this.$moment(endDate).format("MM/DD");
+
+
   },
   activated() {
     this.$store.dispatch('getMenu').then(res => {
@@ -310,7 +379,7 @@ export default {
       let data = {
         group_id: item.target_id,
         start_date:'',
-        start_date:'',
+        // start_date:'',
       };
       if(item.date_interval==1){//本月
         data.start_date=this.$moment().startOf('month').format('YYYY-MM-DD');
@@ -471,7 +540,11 @@ export default {
       });
       var http1 = this.$axiosUser('get', '/api/pro/integral/statistics', { employee_id: this.userInfo.id, month: this.month }, 'v3'); // 获取个人统计
       this.rankingListname(); //排行榜
-      this.opneWebSocket();
+      this.$socketApiTow.authWebSocket(() =>{
+        this.getPkDocList();    //团队pk
+        this.opneWebSocket();   //本月B分奖扣
+      });
+
       Promise.all([http1]).then(res => {
           if (res[0].data.code === 1) {
             this.userStatistics = res[0].data.data;
@@ -495,7 +568,7 @@ export default {
               target_ratio: target_ratio
             }
             this.userMonth=data
-            this.$socketApiTow.closewebsocket();
+            // this.$socketApiTow.closewebsocket();
         }
       }, true);
     },
@@ -545,8 +618,73 @@ export default {
           break;
         }
       }
+    },
+    docCalendarConfirm(event){
+      const [start,end] = event;
+      this.pkTimeScope = [start,end];
+      this.pk.showDocDatePicker = false;
+    },
+    docCalendarClose(){
+      this.pk.showDocDatePicker = false;
+    },
+    openCalendar(){
+      this.pk.showDocDatePicker = true;
+    },
+    saveScrollerPosition(){
+      if (this.$refs.scroller) this.savedScrollPosition = this.$refs.scroller.getPosition();
+    },
+    restoreScrollerPosition(){
+      if (this.$refs.scroller) {
+        this.$refs.scroller.scrollTo(this.savedScrollPosition.left,this.savedScrollPosition.top,true);
+      }
+    },
+    clickPkDoc(index,name){
+      this.saveScrollerPosition();
+      if (this.pk.currentDocIndex !== index && this.pk.pkDocList.length > index){
+        this.pk.currentDocIndex = index;
+        this.getPkRankList(this.pk.pkDocList[index].id)
+      }
+    },
+    getPkDocList(){
+      this.$axiosUser('get','/api/pro/pk/doc/list/visible')
+        .then(res => {
+          this.pk.pkDocList = res.data.data.list;
+          if(this.pk.pkDocList.length > 0) this.getPkRankList(this.pk.pkDocList[0].id)
+        })
+    },
+    getPkRankList(docId){
+      this.pk.teamLoading = true;
+      if (!this.pk.pkTimeScope || this.pk.pkTimeScope.length !== 2) {
+        this.pk.pkTeamList = [];
+        return;
+      }
+      let type = "team_pk";
+      let params = {
+        type:type,
+        doc_id:docId,
+        start_date:this.$moment(this.pk.pkTimeScope[0]).format("YYYY-MM-DD"),
+        end_date:this.$moment(this.pk.pkTimeScope[1]).format("YYYY-MM-DD"),
+      }
+      this.$socketApiTow.sendData(params,(res)=>{
+        if (res.type !== type || res.code !== 1) return;
+        this.pk.pkTeamList = res.result.teams;
+        this.pk.teamLoading = false;
+      })
+      this.$nextTick(() => {
+        setTimeout(() => {
+          this.restoreScrollerPosition()
+        },50)
+      })
     }
   },
+  watch: {
+    pkTimeScope(val){
+      this.pk.pkTimeScope[0] = val[0]
+      this.pk.pkTimeScope[1] = val[1]
+      this.pk.pkTimeScopeStr = this.$moment(this.pk.pkTimeScope[0]).format("MM/DD") + "-" + this.$moment(this.pk.pkTimeScope[1]).format("MM/DD");
+      if (this.pk.pkDocList.length > this.pk.currentDocIndex) this.getPkRankList(this.pk.pkDocList[this.pk.currentDocIndex].id)
+    }
+  }
 };
 </script>
 

+ 102 - 0
src/router/course.js

@@ -0,0 +1,102 @@
+  // 在线课程相关
+  const routes = [
+    {
+      path: '/courseHome',
+      name: 'courseHome',
+      component: () => import('@/view/course/home'),
+      label: '首页',
+      need_login: true,
+    },
+    {
+      path: '/courseUser',
+      name: 'courseUser',
+      component: () => import('@/view/course/user'),
+      label: '我的',
+      need_login: true,
+    },
+    {
+      path: '/courseAuth',
+      name: 'courseAuth',
+      component: () => import('@/view/course/user/wxAuth'),
+      label: '微信授权',
+      need_login: true,
+    },
+    {
+      path: '/courseTeam/:id',
+      name: 'courseTeam',
+      component: () => import('@/view/course/user/team'),
+      label: '我的团队',
+      need_login: false,
+    },
+    {
+      path: '/courseDeal/:id',
+      name: 'courseDeal',
+      component: () => import('@/view/course/user/deal'),
+      label: '课程交易',
+      need_login: false,
+    },
+    {
+      path: '/courseDetail/:id',
+      name: 'courseDetail',
+      component: () => import('@/view/course/user/courseDeal'),
+      label: '课程详情',
+      need_login: false,
+    },
+    {
+      path: '/courseAdDetail/:id',
+      name: 'courseAdDetail',
+      component: () => import('@/view/course/user/courseAdDeal'),
+      label: '推广课程详情',
+      need_login: false,
+    },
+    {
+      path: '/course/limitChange',
+      name: 'limitChange',
+      component: () => import('@/view/course/deal/limitRecord'),
+      label: '名额变动明细',
+      need_login: false,
+    },
+    {
+      path: '/course/dealOrder/:id',
+      name: 'dealOrder',
+      component: () => import('@/view/course/deal/dealOrder'),
+      label: '课程名额交易',
+      need_login: false,
+    },
+    {
+      path: '/course/transfer/:id',
+      name: 'transfer',
+      component: () => import('@/view/course/deal/transfer'),
+      label: '课程名额转让',
+      need_login: false,
+    },
+    {
+      path: '/course/video/:id',
+      name: 'courseVideo',
+      component: () => import('@/view/course/video/courseVideo'),
+      label: '课程播放',
+      need_login: false,
+    },
+    {
+      path: '/freeCourse',
+      name: 'freeCourse',
+      component: () => import('@/view/course/video/freeVideo'),
+      label: '今日更新',
+      need_login: false,
+    },
+    {
+      path: '/courseLogin',
+      name: 'courseLogin',
+      component: () => import('@/view/course/user/login'),
+      label: '课程登录',
+      need_login: true,
+    },
+    {
+      path: '/courseError',
+      name: 'courseError',
+      component: () => import('@/view/course/error'),
+      label: '网络错误',
+      need_login: true,
+    },
+]
+export default routes

+ 9 - 0
src/router/index.js

@@ -5,6 +5,7 @@ import okrRouter from '@/router/okrRouter'
 import attRoute from '@/router/attRoute'
 import examineRouter from '@/router/examineRouter'
 import pointRoute from '@/router/pointRoute'
+import courseRoute from '@/router/course'
 
 //解决重复点击导航栏报错问题
 const originalPush = Router.prototype.replace
@@ -90,6 +91,13 @@ let routes = [
     label: '账号信息',
     need_login: true
   },
+  {
+    path: '/iosIntercept',
+    name: 'iosIntercept',
+    component: () => import('@/view/user/iosIntercept'),
+    label: '公道云',
+    need_login: true
+  },
   {
     path: '/verify',
     name: 'verify',
@@ -410,6 +418,7 @@ routers.push.apply(routers,attRoute);
 routers.push.apply(routers,okrRouter);
 routers.push.apply(routers,examineRouter);
 routers.push.apply(routers,pointRoute);
+routers.push.apply(routers,courseRoute);
 let routes_map = {}
 for (let i in routers) {
   routes_map[routers[i].name] = routers[i]

+ 4 - 1
src/store/getters.js

@@ -21,6 +21,9 @@ const getters = {
   selectDate: state => state.user.selectDate,
   monthTime: state => state.user.monthTime,
   selected:  state => state.attendanceApproval.selected,
-  pushCardData:state => state.user.pushCardData
+  pushCardData:state => state.user.pushCardData,
+
+  //test
+  wxid:state => state.user.wxid
 }
 export default getters

+ 1 - 0
src/store/modules/user.js

@@ -5,6 +5,7 @@ import moment from 'moment'
 
 const user = {
   state: {
+    wxid:11770,
     token: '',
     user_info: {},
     account_info: {},

+ 51 - 0
src/utils/auth.js

@@ -1,4 +1,5 @@
 const TokenKey = 'Admin-Token'
+const WxTokenKey = 'Wx-Token'
 import store from '@/store';
 import axios from '@/utils/axios'
 import { JSEncrypt } from 'jsencrypt'
@@ -82,6 +83,29 @@ export function returnJSEncrypt(data,is=true){
   }
   return arr
 }
+export function returnJSEncrypt1(data,is=true){
+  let jsencrypt = new JSEncrypt()
+  jsencrypt.setPublicKey(publicKey)
+  if(is){
+      data.st=Date.parse(new Date()).toString();
+  }
+  let s=JSON.stringify(data);
+  let arr=[];
+  if(s.length>100){
+    let reg=/.{100}/g;
+    let rs=s.match(reg);
+    rs.push(s.substring(rs.join('').length));
+    rs.forEach(item=>{
+      arr.push(jsencrypt.encrypt(item));
+    })
+    // if(arr[0]){
+    //   decrypt(arr[0])
+    // }
+  }else{
+    arr[0]=jsencrypt.encrypt(s)
+  }
+  return arr
+}
 // 解密
 export function decrypt (msg) {
   let privateKey=`MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDR+Yyjk8lMPNyy
@@ -353,3 +377,30 @@ export function removeToken() {
     return localStorage.removeItem(TokenKey)
   }
 }
+
+export function getWxUserId() {
+  return JSON.parse(localStorage.getItem('wx_user_info')).id
+}
+export function getWxToken() {
+  if (window.plus) {
+    return plus.storage.getItem(WxTokenKey)
+  } else {
+    return localStorage.getItem(WxTokenKey)
+  }
+}
+export function setWxToken(token) {
+  if (window.plus) {
+    return plus.storage.setItem(WxTokenKey, token)
+  } else {
+    return localStorage.setItem(WxTokenKey, token)
+  }
+}
+export function removeWxToken() {
+  if (window.plus) {
+    plus.storage.removeItem('wx_user_info')
+    return plus.storage.removeItem(WxTokenKey)
+  } else {
+    localStorage.removeItem('wx_user_info')
+    return localStorage.removeItem(WxTokenKey)
+  }
+}

+ 167 - 0
src/utils/axiosKc.js

@@ -0,0 +1,167 @@
+import router from '@/router'
+import axios from 'axios'
+import qs from 'qs'
+import Vue from 'vue'
+import { getWxToken, setWxToken, openError } from '@/utils/auth'
+import { Dialog, Notify ,Toast } from 'vant'
+Vue.use(Dialog).use(Notify)
+let pl = 'a'
+if (window.plus) {
+  if (navigator.userAgent.indexOf('Android') > 0) {
+    pl = 'a'
+  } else {
+    pl = 'i'
+  }
+} else {
+  pl = 'b'
+}
+let url = '';
+const request = axios.create({
+  // baseURL: process.env.BASE_API, 
+  baseURL: 'https://oa.g107.com',
+  timeout: 20000,
+  headers: {
+    'Content-Type': 'application/x-www-form-urlencoded',
+    'pl': pl
+  },
+})
+var bool = true; //五秒执行一次变量
+request.interceptors.request.use(
+  config => {
+    // url = config.url;
+    // if (getWxToken()) {
+    //   config.headers['A-Token'] = getWxToken()
+    // }
+    return config
+  },
+  error => {
+    Promise.reject(error)
+  }
+)
+
+request.interceptors.response.use(
+  response => {
+    if (response.data.code === 0) {//请求失败
+      Notify({
+        message: response.data.message,
+        color: '#ad0000',
+        background: '#d1d1d1',
+      });
+      return Promise.reject('error')
+    } else if (response.data.code === 2) {//未登录
+      localStorage.removeItem('Wx-Token')
+      localStorage.removeItem('wx_user_info')
+      router.replace({
+        name: 'courseAuth'
+      })
+      // return Promise.reject('error')
+    } else if (response.data.code === 3) {//无权限
+      router.replace({
+        name: 'courseHome'
+      })
+      // return Promise.reject('error')
+    } else if (response.data.code === 999) {//系统异常
+      localStorage.removeItem('Wx-Token')
+      localStorage.removeItem('wx_user_info')
+      router.replace({
+        name: 'courseAuth'
+      })
+      // return Promise.reject('error')
+    } else {
+      return response
+    }
+  },
+  error => {
+    if (error.message == 'interrupt') {
+      return Promise.reject(error.message)
+    }
+    //五秒内只执行一次
+    if (bool) {
+      if (error.message == 'timeout of 10000ms exceeded') {
+        Notify({
+          type: 'warning',
+          message: "网络连接超时,请稍后重试",
+          duration: 3000,
+        });
+      }
+      if (error.message == 'Network Error') {
+        Notify({
+          type: 'danger',
+          message: "网络连接失败,请检查您的网络",
+          duration: 3000,
+        });
+      }
+      bool = false
+      setTimeout(() => {
+        bool = true
+      }, 5000)
+    }
+    return Promise.reject(error)
+  }
+)
+
+// 接口再次封装
+var CancelToken = axios.CancelToken;
+Vue.$httpRequestList = [];
+//isToken  是微信的TOKEN  用来绑定
+export default (type, url, data, heaStr, isToken, Content_Type) => {
+  var Accept, ContentType
+  var Token = ''
+  switch (heaStr) {
+    case undefined:
+      Accept = 'application/json, text/plain, */*'
+      break
+    case '':
+      Accept = 'application/json, text/plain, */*'
+      break
+    case 'v2':
+      Accept = 'application/vnd.test.v2+json'
+      break;
+    case 'v3':
+      Accept = 'application/vnd.test.v3+json'
+      break;
+  }
+  if (getWxToken()) {
+    Token = getWxToken();
+  }else{
+    return Promise.reject(new Error('No token, request aborted.'));
+  }
+  if (isToken) {
+    Token = isToken
+  }
+  if (Content_Type == '' || Content_Type == undefined) {
+    // ContentType = 'application/x-www-form-urlencoded'
+    ContentType = 'application/json'
+  } else {
+    ContentType = Content_Type
+  }
+  return new Promise((resolve, reject) => { //封装ajax
+    var aa = {
+      method: type,
+      url: url,
+      headers: {
+        'Accept': Accept,
+        'A-Token': Token,
+        'Content-Type': ContentType
+      },
+      cancelToken: new CancelToken(c => { //强行中断请求要用到的
+        Vue.$httpRequestList.push(c);
+      })
+    }
+    var json = (type == 'get') ? Object.assign(aa, {
+      params: data
+    }) : Object.assign(aa, {
+      data: data
+    });
+    var ajax = request(json).then(res => {
+      resolve(res);
+    }).catch(error => { //中断请求和请求出错的处理
+      if (error == "interrupt") {
+        return;
+      } else {
+        reject(error);
+      }
+    })
+    return ajax;
+  })
+};

+ 13 - 5
src/utils/axiosUser.js

@@ -33,9 +33,9 @@ var bool = true; //五秒执行一次变量
 service.interceptors.request.use(
   config => {
     url = config.url;
-    if (getToken()) {
-      config.headers['A-Token'] = getToken()
-    }
+    // if (getToken()) {
+    //   config.headers['A-Token'] = getToken()
+    // }
     return config
   },
   error => {
@@ -141,7 +141,7 @@ service.interceptors.response.use(
 // 接口再次封装
 var CancelToken = axios.CancelToken; //中断请求
 Vue.$httpRequestList = [];
-export default (type, url, data, heaStr) => {
+export default (type, url, data, heaStr,isToken) => {
   var Accept='application/json, text/plain, */*', Token = '';
   switch (heaStr) {
     case '':
@@ -157,12 +157,20 @@ export default (type, url, data, heaStr) => {
       Accept = 'application/vnd.test.v4+json'
       break;
   }
+  if (getToken()) {
+    Token = getToken();
+  }
+  if (isToken) {
+    console.log(isToken)
+    Token = isToken
+  }
   return new Promise((resolve, reject) => { //封装ajax
     var aa = {
       method: type,
       url: url,
       headers: {
-        'Accept': Accept
+        'Accept': Accept,
+        'A-Token': Token,
       },
       cancelToken: new CancelToken(c => { //强行中断请求要用到的
         Vue.$httpRequestList.push(c);

+ 338 - 0
src/view/course/api/index.js

@@ -0,0 +1,338 @@
+import axiosKc from "../../../utils/axiosKc";
+import router from '@/router'
+import { Dialog, Notify, Toast } from 'vant'
+import { getWxToken, setWxToken, openError, getWxUserId } from '@/utils/auth'
+
+//手机号获取验证码
+export function getMobileYzm(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc('post', `/mkt/client/sms/${getWxUserId()}`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取微信公众号信息
+export function getWxConfigInfo(data,appId='wx65f4dde5ec7c31e7') {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/wx/mp/jsapi/wx65f4dde5ec7c31e7/config`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//wxid获取用户wxtoken
+export function getWxApiToken(wxId) {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/demo/token/wo/${wxId}`).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//根据code获取开放平台token
+export function getWxPlatToken(token){
+    return new Promise((resolve, reject) => {
+        axiosKc('post', `/api/wo/mp/code`, {code:token}).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//通过wxtoken获取用户wxApiToken
+export function getUSerInfo(token) {
+    return new Promise((resolve, reject) => {
+        axiosKc('post', `/mkt/client/login`, {}, '', token).then((res) => {
+            if (res.data.code == 1) {
+                // Toast(`获取到用户信息${res.data.data.marketable}`)
+                setWxToken(res.data.data.utoken)
+                localStorage.setItem('wx_user_info', JSON.stringify(res.data.data))
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//添加经销商
+export function addDealer(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc('post', `/mkt/client/${getWxUserId()}/join`, data).then((res) => {
+            if (res.data.code == 1) {
+                setWxToken(res.data.data.utoken)
+                localStorage.setItem('wx_user_info', JSON.stringify(res.data.data))
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+
+//获取经销商推广的课程
+export function getDealerCourseList() {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/client/${getWxUserId()}/capital/list`).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取所有课程
+export function getUserAllCourseList(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/client/subject/list`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取免费课程
+export function getFreeCourseList() {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/client/subject/free`).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取经销商推广的指定课程
+export function getDealerCourseDetail(id) {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/client/${getWxUserId()}/capital/info/${id}`).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取学员学习的课程
+export function getUserCourseList() {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/client/${getWxUserId()}/subject/list`).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取经销商推广的所有/指定课程的交易记录
+export function getCourseRecordList(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/client/${getWxUserId()}/capital/log`, data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取经销商的团队人员
+export function getDealerTeam(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/client/${getWxUserId()}/team/list`, data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取经销商的30天内交易的人员
+export function getDealerPerson(data, days = 30) {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/client/${getWxUserId()}/team/list/transfer/${days}`, data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取交易经销商的交易记录列表( 1-待接收 2-已接收 3-发起方主动取消 4-接收方退回 -1-待接收以外的记录 0-不区分状态 默认为0)
+export function getDealerRecord(targetUserId, data) {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/client/${getWxUserId()}/transfer/list/${targetUserId}`, data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//交易经销商的课程
+export function dealCourse(targetUserId, data) {
+    return new Promise((resolve, reject) => {
+        axiosKc('post', `/mkt/client/${getWxUserId()}/transfer/${targetUserId}`, data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//交易课程确认接收
+export function dealAccept(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc('post', `/mkt/client/${getWxUserId()}/transfer/confirm`, data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//交易课程确认退回
+export function dealRefund(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc('post', `/mkt/client/${getWxUserId()}/transfer/refund`, data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//交易课程确认撤回
+export function dealRecall(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc('post', `/mkt/client/${getWxUserId()}/transfer/cancel`, data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//学员课程详情
+export function learnerCourseDetail(id) {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/client/${getWxUserId()}/subject/${id}`).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//生成课程分享码
+export function createCourseCode(id,data) {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/client/${getWxUserId()}/sales/code/${id}`).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取课程分享码详情
+export function getCourseCodeDetail(salesCode) {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/client/${getWxUserId()}/sales/code/info/${salesCode}`).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//领取课程分享码的课程
+export function getCourseCode(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc('post', `/mkt/client/${getWxUserId()}/sales/code/`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取解析的视频地址
+export function getVideoSrc(data){
+    return new Promise((resolve, reject) => {
+        axiosKc('post', `/mkt/client/${getWxUserId()}/subject/presign`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                router.replace('/courseError')
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取解析的免费视频地址
+export function getFreeVideoSrc(data){
+    return new Promise((resolve, reject) => {
+        axiosKc('post', `/mkt/client/${getWxUserId()}/subject/presign/free`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Notify({ type: 'danger', message: data.message });
+                router.replace('/courseError')
+                reject(res.data.message)
+            }
+        })
+    })
+}

+ 159 - 0
src/view/course/components/CourseTeam.vue

@@ -0,0 +1,159 @@
+<template>
+  <div class="team-page">
+    <form action="/">
+      <van-search
+        v-model="searchValue"
+        placeholder="请输入用户名搜索"
+        @input="onSearch"
+      />
+    </form>
+    <div class="team-desc">
+      <p v-if="teamType == 1">团队人数:{{ count }}人</p>
+      <p v-if="teamType == 0">近{{ days }}天有交易的人</p>
+    </div>
+    <div class="team-list">
+      <div class="team-flex" v-for="(item, index) in teamList">
+        <userImage
+          class="about-me__avatar"
+          :img_url="item.imgUrl"
+          :user_name="item.name"
+          width=".8rem"
+          height=".8rem"
+          v-if="item.imgUrl"
+        ></userImage>
+        <div style="background: #26A2FF;border-radius: 50%;overflow: hidden;" v-else>
+          <userImage
+            class="about-me__avatar"
+            :img_url="defaultImgUrl"
+            user_name="用户"
+            width=".8rem"
+            height=".8rem"
+          ></userImage>
+        </div>
+        <div class="flex-r">
+          <div class="flex-tel">
+            <p>{{ item.name }}</p>
+            <span v-if="item.mobile != ''">手机:{{ item.mobile }}</span>
+          </div>
+          <div class="flex-deal" @click="otDealPage(item)">交易</div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "courseTeamMudule",
+  components: {},
+  props: {
+    teamType: {
+      type: String,
+      default: 1
+    },
+    days: {
+      type: Number,
+      default: 30
+    },
+    teamList:{
+      type:Array,
+      default:[]
+    },
+    count:{
+      type:Number,
+      default:0
+    }
+  },
+  data() {
+    return {
+      defaultImgUrl:require('../../../assets/images/courseUser.png'),
+      searchValue: "",
+      teamData: {
+        count: 0,
+        list: []
+      }
+    };
+  },
+  computed: {
+  },
+  created() {
+    this.init();
+  },
+  methods: {
+    //跳转人员交易记录
+    otDealPage(item) {
+      this.$router.push({
+        path: `/courseDeal/${item.id}`,
+        query:item
+      });
+    },
+    //初始化
+    init() {
+    },
+    //人员搜索
+    onSearch() {
+      this.$emit('search',this.searchValue)
+    },
+  }
+};
+</script>
+<style scoped lang="scss">
+* {
+  margin: 0;
+  padding: 0;
+}
+.team-page {
+  background-color: #fff;
+    position: relative;
+    .team-desc {
+      padding: 0 0.32rem 0.25rem;
+      border-bottom: 1px solid rgb(241, 241, 241);
+      p {
+        font-size: 0.28rem;
+        line-height: 0.8;
+        color: #000;
+        font-weight: 550;
+      }
+    }
+    .team-list {
+      padding: 0 0.32rem;
+      .team-flex {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        padding: 0.15rem 0;
+        border-bottom: 1px solid rgb(241, 241, 241);
+        .flex-r {
+          padding: 0 0.2rem;
+          display: flex;
+          flex: 1;
+          justify-content: space-between;
+          align-items: center;
+          .flex-tel {
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            p {
+              font-size: 0.32rem;
+              color: #000;
+              line-height: 1.5;
+            }
+            span {
+              font-size: 0.28rem;
+              color: #666;
+              line-height: 1.2;
+            }
+          }
+          .flex-deal {
+            font-size: 0.28rem;
+            color: #0075fc;
+            line-height: 1.4;
+          }
+        }
+      }
+    }
+}
+/deep/ .van-search .van-cell{
+  padding: 0.1rem 0.16rem 0.1rem 0.16rem;
+}
+</style>

+ 296 - 0
src/view/course/components/courseList.vue

@@ -0,0 +1,296 @@
+<template>
+  <div class="listOuer">
+    <div class="listInner">
+      <template v-if="dataList.length > 0">
+        <div
+          class="listLi"
+          v-for="(item, index) in dataList"
+          :key="index"
+          :class="{ marginGap: listType == 2 }"
+          :style="{ background: outBg }"
+        >
+          <div class="courseBtm" v-if="showNum == 2">
+            <p>剩余名额</p>
+            <span>{{ item.amount }}套</span>
+          </div>
+          <div class="listLiTit" v-if="item.toUserId && listType == 2">
+            <p>
+              {{ item.toUserId == user_info.id ? "收到" : "转出"
+              }}<span>【{{ item.dealAmount }}套】</span>课程
+            </p>
+          </div>
+          <div
+            class="listLiTop"
+            :class="{ listLiTopT: showNum == 2 }"
+            @click="toUrl(item)"
+          >
+            <img :src="item.subjectThumb" />
+            <div class="liInfo">
+              <div class="courseLiTit">
+                <p>{{ item.subjectName }}</p>
+              </div>
+              <div class="courseLiDesc">
+                <span v-if="showNum == 1">剩余{{ item.amount }}套</span>
+                <span v-else-if="showNum == 4">{{ item.clickNum }}次浏览</span>
+                <span v-else>共{{ item.sectionsNum }}节</span>
+                <span style="color: #F76146;">{{ item.subjectPrice }}</span>
+              </div>
+            </div>
+          </div>
+          <!-- <div class="courseBtm" v-if="showNum == 1">
+            <span>剩余名额:{{ item.amount }}套</span>
+            <span>已卖出:{{ item.statistics.saleAmount }}套</span>
+          </div> -->
+          <!-- <div
+            v-if="showNum == 0 && !(item.status && item.status !== 4)"
+            style="height: .2rem;"
+          ></div> -->
+          <div
+            class="dealComfirm"
+            @click="comfirm(item)"
+            v-if="item.status && item.status == 1 && listType == 2"
+            :class="payClass(item) ? '' : 'dealTo'"
+          >
+            <span>{{
+              item.toUserId == user_info.id ? "确认接收" : "待对方确认"
+            }}</span>
+          </div>
+        </div>
+      </template>
+      <template v-else>
+        <div class="noData">
+          <van-empty :description="courseNodata" />
+        </div>
+      </template>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "courseList",
+  components: {},
+  props: {
+    //数组列表
+    dataList: {
+      type: Array,
+      default: []
+    },
+    //背景色
+    outBg: {
+      type: String,
+      default: "#FFF"
+    },
+    //提示
+    fixedTitle: {
+      type: String,
+      default: ""
+    },
+    //是否有底部剩余数量
+    showNum: {
+      type: Number,
+      default: 0
+    },
+    //是否需要展示课程接收按钮(1不需要2需要)
+    listType: {
+      type: Number,
+      default: 1
+    },
+    // 是否是推广的课程
+    isNoAd: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      user_info: JSON.parse(localStorage.getItem("wx_user_info"))
+    };
+  },
+  computed: {
+    payClass(item) {
+      return function(item) {
+        if (item.toUserId == this.user_info.id && item.status == 1) {
+          return true;
+        }
+        return false;
+      };
+    },
+    courseNodata(){
+      return this.isNoAd?'暂无学习课程...':"暂无推广课程..."
+    },
+  },
+  created() {},
+  methods: {
+    // 查看课程详情
+    toUrl(item) {
+      if(this.isNoAd){
+        this.$router.push(`/courseDetail/${item.subjectId}`);
+      }else if(this.showNum == 1 ){
+        this.$router.push({
+          path: `/courseAdDetail/${item.id}-${item.subjectId}`
+        });
+      }else if(this.showNum == 2 ){
+        this.$router.push({
+          path: `/courseDetail/${item.subjectId}`
+        });
+      }else if(this.showNum == 3 ){
+        // this.$router.push({
+        //   path: `/courseAdDetail/${item.subjectId}`
+        // });
+      }else if(this.showNum == 4 ){
+        this.$router.push({
+          path: `/courseDetail/${item.subjectId}`
+        });
+      }else if(item.status == 1 && this.listType == 2){
+        this.comfirm(item)
+      }
+    },
+    // 接受名额转入
+    comfirm(item) {
+      this.$router.push({
+        path: `/course/transfer/${item.id}`,
+        query: item
+      });
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+* {
+  margin: 0;
+  padding: 0;
+}
+.listOuer {
+  border-radius: 0.1rem;
+  overflow: hidden;
+  // padding: 0.1rem 0;
+  .listTit {
+    display: flex;
+    align-items: center;
+    padding: 0 0.2rem;
+    justify-content: space-between;
+    p {
+      font-size: 0.3rem;
+      color: #000;
+      line-height: 2;
+      font-weight: 600;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: no-warp;
+    }
+    span {
+      font-size: 0.23rem;
+      color: #0075fc;
+    }
+  }
+  .listInner {
+    .noData {
+      width: 100%;
+      background: #fff;
+    }
+    .listLi {
+      // padding-top: 0.2rem;
+      // padding-bottom: 0.2rem;
+      padding: 0.2rem 0.15rem;
+      &:not(:nth-last-child(1)) {
+        // padding-bottom: 0.2rem;
+        border-bottom: 1px solid #efefef;
+      }
+      &.marginGap {
+        margin-bottom: 0.2rem;
+        border: 0;
+        border-radius: 0.1rem;
+        padding-bottom: 0;
+        &:not(:nth-last-child(1)) {
+          border-bottom: 0;
+        }
+      }
+      .listLiTit {
+        font-size: 0.3rem;
+        color: #000;
+        line-height: 2;
+        font-weight: 600;
+        span {
+          color: #0075fc;
+        }
+      }
+      .dealComfirm {
+        text-align: center;
+        span {
+          font-size: 0.3rem;
+          color: rgb(41, 121, 255);
+          line-height: 3;
+        }
+        &.dealTo {
+          span {
+            color: rgb(253, 209, 67);
+          }
+        }
+      }
+      .listLiTop {
+        display: flex;
+        justify-content: space-between;
+        &.listLiTopT {
+          padding: 0.2rem 0.1rem;
+          background: linear-gradient(90deg, #F3F2EE, #E7EFF9);
+          border-radius: 0.1rem;
+        }
+        & > img {
+          width: 2.5rem;
+          height: 1.5rem;
+          display: block;
+          border-radius: 0.1rem;
+        }
+        .liInfo {
+          flex: 1;
+          margin-left: 0.15rem;
+          display: flex;
+          flex-direction: column;
+          justify-content: space-between;
+          .courseLiTit {
+            overflow: hidden;
+            text-overflow: ellipsis;
+            display: -webkit-box;
+            -webkit-line-clamp: 2;
+            -webkit-box-orient: vertical;
+            p {
+              font-size: 0.3rem;
+              color: #333;
+              line-height: 1.5;
+              font-weight: 600;
+            }
+          }
+          .courseLiDesc {
+            display: flex;
+            justify-content: space-between;
+            span {
+              font-size: 0.28rem;
+              color: #888;
+              line-height: 1.3;
+              &:nth-child(1) {
+                margin-right: 0.3rem;
+              }
+            }
+          }
+        }
+      }
+      .courseBtm {
+        padding: 0.6rem;
+        text-align: center;
+        p {
+              font-size: 0.26rem;
+              color: #000;
+              line-height: 0.5rem;
+            }
+            span {
+              color: #000;
+              font-size: 0.45rem;
+              font-weight: 600;
+              line-height: 1.5;
+            }
+      }
+    }
+  }
+}
+</style>

+ 203 - 0
src/view/course/deal/dealOrder.vue

@@ -0,0 +1,203 @@
+<template>
+  <div class="page">
+    <van-nav-bar
+      title="课程交易"
+      left-text="返回"
+      left-arrow
+      @click-left="onClickLeft"
+    ></van-nav-bar>
+    <div class="orderContent">
+      <div class="form">
+        <van-field
+          readonly
+          clickable
+          label="选择课程"
+          :value="form.name"
+          placeholder="选择课程"
+          @click="showPop"
+        />
+        <div class="desc" v-if="form.id != 0">
+          <span>该课程名额剩余{{ coursesUsable }}套</span>
+        </div>
+        <van-field
+          readonly
+          label="选择交易数量"
+          :value="form.number"
+          placeholder="选择交易数量"
+          @touchstart.native.stop="numberShow = true"
+        />
+        <van-field
+          v-model="form.content"
+          rows="3"
+          autosize
+          label="备注"
+          type="textarea"
+          maxlength="100"
+          placeholder="备注留言"
+          show-word-limit
+        />
+        <div class="submit">
+          <van-button
+            color="#999"
+            style="padding: 0 .8rem;border-radius: 0.15rem;"
+            @click="$router.go(-1)"
+            >取消</van-button
+          >
+          <van-button style="background-color: #26A2FF;padding: 0 .8rem;color: #FFF;border-radius: 0.15rem;" @click="comfirm"
+            >确认</van-button
+          >
+        </div>
+      </div>
+    </div>
+    <van-popup v-model="popupShow" position="bottom" :style="{ height: '40%' }">
+      <van-picker
+        title="选择课程"
+        show-toolbar
+        :columns="columnsOptions"
+        @confirm="onConfirm"
+        @cancel="popupShow = false"
+      />
+    </van-popup>
+    <van-number-keyboard
+      :show="numberShow"
+      @blur="numberShow = false"
+      @input="onInput"
+      @delete="onDelete"
+    />
+  </div>
+</template>
+
+<script>
+import {getDealerCourseList,dealCourse} from '../api'
+import Vue from "vue";
+import { NumberKeyboard } from "vant";
+import {setWxConfig} from '../utils'
+Vue.use(NumberKeyboard);
+export default {
+  name: "dealOrder",
+  components: {},
+  data() {
+    return {
+      numberShow: false,
+      popupShow: false,
+      form: {
+        name: "",
+        id: 0,
+        number: 0,
+        content: ""
+      },
+      coursesUsable: 0,
+      courseList:[],
+      columnsOptions:[]
+    };
+  },
+  created() {
+    // this.getCourseList();
+  },
+  activated(){
+    this.getCourseList();
+    if(this.$isWx){
+      setWxConfig(info);
+    }
+  },
+  deactivated(){
+    this.resetList();
+  },
+  methods: {
+    resetList(){
+      this.courseList=[],
+      this.columnsOptions=[]
+    },
+    //获取可交易的课程
+    getCourseList(){
+      getDealerCourseList().then(res=>{
+        this.courseList = res.list;
+        let list = [];
+        res.list.forEach(item=>{
+          list.push(item.subjectName)
+        })
+        this.columnsOptions = list
+      })
+    },
+    //交易
+    postDeal(){
+      let data = {
+        subjectId:this.form.id,
+        amount:this.form.number,
+        content:this.form.content
+      }
+      dealCourse(this.$route.params.id,data).then(res=>{
+        this.$toast.success('交易成功')
+        this.form.id = 0;
+        this.form.number = 0;
+        this.form.content = "";
+        this.form.name = "";
+        this.$router.go(-1)
+      })
+    },
+    //交易提示
+    comfirm(){
+      this.$dialog.confirm({
+         title: '提示',
+         message: '确认要提交当前名额交易吗?',
+        }).then(() => {
+          if(this.form.id != 0 && this.form.number != 0){
+            this.postDeal();
+          }else{
+            this.$toast.fail('请填写正确的交易信息后提交')
+          }
+        })
+    },
+    //数字输入框加
+    onInput(key) {
+      this.form.number = Number(`${this.form.number}${key}`)
+    },
+    //数字输入框减
+    onDelete() {
+      this.form.number = Number(this.form.number.toString().slice(0,this.form.number.toString().length - 1))
+    },
+    //返回
+    onClickLeft() {
+      if(window.history.length>1){
+        this.$router.go(-1);
+      }else{
+        this.$router.replace('/courseHome')
+      }
+    },
+    //显示课程选择
+    showPop() {
+      this.popupShow = true;
+    },
+    //课程选择确认
+    onConfirm(e, index) {
+      this.form.name = this.courseList[index].subjectName;
+      this.form.id = this.courseList[index].subjectId;
+      this.coursesUsable = this.courseList[index].amount;
+      this.popupShow = false;
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+@import url('../utils/navBar.scss');
+.page {
+  background: #F3F2EE;
+  background: linear-gradient(90deg, #F3F2EE, #E7EFF9);
+  .orderContent {
+    .form {
+      .desc {
+        padding: 0 0.2rem;
+        font-size: 0.24rem;
+        color: #888;
+        line-height: 2;
+      }
+      .submit {
+        margin-top: 0.5rem;
+        display: flex;
+        justify-content: space-around;
+        align-items: center;
+      }
+    }
+  }
+}
+</style>

+ 172 - 0
src/view/course/deal/limitRecord.vue

@@ -0,0 +1,172 @@
+<template>
+  <div class="page">
+    <van-nav-bar
+      :title="title"
+      left-text="返回"
+      left-arrow
+      @click-left="onClickLeft"
+    ></van-nav-bar>
+    <div class="recordContent">
+      <scroller
+        ref="recordScroller"
+        :list="recordList"
+        noDataText="没有更多..."
+        :on-infinite='getMoreList'
+      >
+        <div class="recordList">
+          <div
+            class="recordLi"
+            v-for="(item, index) in recordList"
+            :key="index"
+          >
+            <div class="flex-name-num">
+              <p>{{ item.subjectName }}</p>
+              <span :style="{color:Number(item.amount)>0?'#26A2FF':'red'}">{{Number(item.amount)>0?`+${item.amount}`:item.amount}}</span
+              >
+            </div>
+            <p>{{ item.content }}</p>
+            <span>{{ item.createTime }}</span>
+          </div>
+        </div>
+        <noData :list="recordList" />
+      </scroller>
+    </div>
+  </div>
+</template>
+
+<script>
+import {getCourseRecordList} from '../api'
+import {setWxConfig} from '../utils'
+export default {
+  name: "limitRecord",
+  components: {},
+  props: [],
+  data() {
+    return {
+      noDate:false,
+      title: "名额变动明细",
+      page:{
+        cur:1,
+        size:10,
+        total:0
+      },
+      recordList: []
+    };
+  },
+  created() {
+    // this.getList();
+  },
+  activated(){
+    this.getList();
+    if(this.$isWx){
+      setWxConfig(info);
+    }
+  },
+  deactivated(){
+    this.page.cur = 1;
+    this.recordList = [];
+  },
+  methods: {
+    // 返回
+    onClickLeft() {
+      if(window.history.length>1){
+        this.$router.go(-1);
+      }else{
+        this.$router.replace('/courseHome')
+      }
+    },
+    //获取记录列表
+    getList(done){
+      let data = {
+        page:this.page.cur,
+        pageSize:this.page.size
+      }
+      getCourseRecordList(data).then(res=>{
+        this.recordList = this.recordList.concat(res.list)
+        this.page.cur = res.current
+        this.page.total = res.total
+        if (res.pages == this.page.cur || res.pages == 0) {
+          if (done) done(true);
+          this.noDate = true;
+        } else {
+          if (done) done();
+          this.page.cur++; //下拉一次页数+1
+          this.noDate = false;
+        }
+      })
+    },
+    // 触底加载
+    getMoreList(done){
+      console.log("到底了")
+      if (!this.noDate) {
+          setTimeout(() => {
+            this.getList(done);
+          }, 300);
+        } else {
+          this.$refs.recordScroller.finishInfinite(true);
+        }
+    },
+  },
+  computed: {}
+};
+</script>
+<style scoped lang="scss">
+@import url('../utils/navBar.scss');
+*{
+  margin: 0;
+  padding: 0;
+}
+img{
+  display: block;
+}
+.page {
+  background: #F3F2EE;
+  background: linear-gradient(90deg, #F3F2EE, #E7EFF9);
+  .recordContent {
+    height: calc(100vh - 0.92rem);
+    position: relative;
+    .recordList {
+      // border-top: 0.02rem solid #999;
+      // border-bottom: 1px solid #999;
+      .recordLi {
+        background: #fff;
+        padding: 0 0.2rem;
+        overflow: hidden;
+        &:not(:nth-last-child(1)) {
+          border-bottom: 1px solid #efefef;
+        }
+        .flex-name-num {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          padding-top: 0.1rem;
+          & > p {
+            font-size: 0.32rem;
+            color: #000;
+            line-height: 1.5;
+          }
+          & > span {
+            font-size: 0.32rem;
+            color: #000;
+            line-height: 2;
+            margin-left: .1rem;
+          }
+        }
+        & > p {
+          font-size: 0.28rem;
+          color: #666;
+          line-height: 1;
+        }
+        & > span {
+          font-size: 0.28rem;
+          color: #666;
+          line-height: 1;
+          display: block;
+          margin-top: 0.2rem;
+          margin-bottom: 0.1rem;
+        }
+      }
+    }
+  }
+}
+</style>

+ 257 - 0
src/view/course/deal/transfer.vue

@@ -0,0 +1,257 @@
+<template>
+  <div class="page">
+    <van-nav-bar
+      :title="title"
+      left-text="返回"
+      left-arrow
+      @click-left="onClickLeft"
+    ></van-nav-bar>
+    <div class="transferTop">
+      <van-icon name="clock-o" size=".8rem" color="#26A2FF"/>
+      <p>{{ transferInfo.dealAmount }}套</p>
+      <span>课程名额</span>
+    </div>
+    <div class="transferConetent">
+      <span>{{ transferInfo.name }}</span>
+      <courseList :dataList="courseInfo" :showNum="3"></courseList>
+      <div class="content">
+        <p>交易说明</p>
+        <p>{{ transferInfo.content }}</p>
+      </div>
+    </div>
+    <div class="transferBtm">
+      <van-button
+        style="padding:0 .5rem;border-radius: .15rem;background-color: #26A2FF;color: #FFF;"
+        v-if="transferInfo.toUserId == user_info.id"
+        @click="confirm"
+        >确认接收</van-button
+      >
+      <van-button
+        style="padding:0 .5rem;background-color: #999;color:#FFF;border-radius: .15rem;"
+        size="default"
+        v-else
+        >等待对方接收</van-button
+      >
+      <div class="transferTH">
+        <p>如交易名额有误,可先{{user_info.id == transferInfo.toUserId?'退还':'撤回'}}再重新交易。 <span @click="returnLimit()">{{user_info.id == transferInfo.toUserId?'立即退还':'立即撤回'}}</span></p>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import {dealAccept,dealRefund,dealRecall} from '../api'
+import courseList from "../components/courseList.vue";
+import {setWxConfig} from "../utils"
+export default {
+  name: "courseTransfer",
+  components: { courseList },
+  props: [],
+  data() {
+    return {
+      title: "课程交易",
+      transferInfo: {},
+      user_info:JSON.parse(localStorage.getItem('wx_user_info'))
+    };
+  },
+  computed: {
+    courseInfo() {
+      let list = [];
+      list.push(this.transferInfo);
+      return list;
+    }
+  },
+  activated(){
+    this.init();
+    if(this.$isWx){
+      setWxConfig(info);
+    }
+  },
+  created() {
+    // this.init()
+  },
+  methods: {
+    // 初始化
+    init(){
+      this.transferInfo = this.$route.query
+    },
+    // 返回
+    onClickLeft() {
+      if(window.history.length>1){
+        this.$router.go(-1);
+      }else{
+        this.$router.replace('/courseHome')
+      }
+    },
+    // 退回、撤回提示
+    returnLimit(){
+      if(this.transferInfo.toUserId == this.user_info.id){
+        this.$dialog.confirm({
+        title: "提示",
+        message: "确认退还当前转让的名额?"
+      })
+        .then(() => {
+          this.sendback();
+        })
+        .catch(() => {
+        });
+      }else{
+        this.$dialog.confirm({
+        title: "提示",
+        message: "确认撤回当前转让的名额?"
+      })
+        .then(() => {
+          this.sendRecall()
+        })
+        .catch(() => {
+        });
+      }
+    },
+    // 退还名额
+    sendback(){
+      let data = {
+        transferId:this.transferInfo.id,
+        subjectId:this.transferInfo.subjectId,
+        toUserId:this.transferInfo.toUserId,
+        fromUserId:this.transferInfo.fromUserId,
+      }
+      dealRefund(data).then(res=>{
+        this.$toast.success('退回成功')
+        setTimeout(()=>{
+          this.$router.go(-1)
+        })
+      })
+    },
+    // 撤回名额
+    sendRecall(){
+      let data = {
+        transferId:this.transferInfo.id,
+        subjectId:this.transferInfo.subjectId,
+        toUserId:this.transferInfo.toUserId,
+        fromUserId:this.transferInfo.fromUserId,
+      }
+      dealRecall(data).then(res=>{
+        this.$toast.success('退回成功')
+        setTimeout(()=>{
+          this.$router.go(-1)
+        })
+      })
+    },
+    // 接收名额
+    acceptAccount(){
+      let data = {
+        transferId:this.transferInfo.id,
+        subjectId:this.transferInfo.subjectId,
+        toUserId:this.transferInfo.toUserId,
+        fromUserId:this.transferInfo.fromUserId,
+      }
+      dealAccept(data).then(res=>{
+        this.$toast.success('接收成功')
+        setTimeout(()=>{
+          this.$router.go(-1)
+        })
+      })
+    },
+    // 接收名额提示
+    confirm() {
+      this.$dialog.confirm({
+        title: "提示",
+        message: "确认接收当前转让的名额?"
+      })
+        .then(() => {
+          this.acceptAccount()
+        })
+        .catch(() => {
+          // on cancel
+        });
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+@import url('../utils/navBar.scss');
+* {
+  margin: 0;
+  padding: 0;
+}
+img {
+  display: block;
+}
+.page {
+  background: #F3F2EE;
+  background: linear-gradient(90deg, #F3F2EE, #E7EFF9);
+  position: relative;
+  .transferTop {
+    padding: 0.4rem;
+    text-align: center;
+    p {
+      font-size: 0.6rem;
+      color: #000;
+    }
+    span {
+      font-size: 0.3rem;
+      line-height: 2;
+    }
+  }
+  .transferConetent {
+    margin: 0 .2rem;
+    .content{
+      margin: .2rem;
+      border-top: 1px solid #efefef;
+      padding-top: .1rem;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      flex-wrap: wrap;
+      p{
+        font-size: .24rem;
+        color: #666;
+        line-height: .35rem;
+        width: 30%;
+        &:nth-child(2){
+          flex: 1;
+          display: flex;
+          flex-wrap: wrap;
+          flex-direction: row-reverse;
+        }
+      }
+    }
+    .listOuer {
+      padding: 0 0 0.1rem;
+      background-color: #fff;
+    }
+    & > span {
+      margin-left: 0.2rem;
+      font-size: 0.26rem;
+      color: #666;
+      line-height: 1.4;
+    }
+    & > p {
+      font-size: 0.28rem;
+      color: #333;
+      line-height: 1.3;
+      padding: 0 0.2rem;
+    }
+  }
+  .transferBtm {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: center;
+    position: absolute;
+    bottom: 8%;
+    .transferTH {
+      margin-top: 0.4rem;
+      width: 100%;
+      display: flex;
+      justify-content: center;
+      p {
+        font-size: 0.26rem;
+        color: #000;
+      }
+      span {
+        color: #26a2ff;
+      }
+    }
+  }
+}
+</style>

+ 33 - 0
src/view/course/error.vue

@@ -0,0 +1,33 @@
+<template>
+<div>
+  <van-nav-bar
+      title="网络错误"
+      left-text="返回"
+      left-arrow
+      @click-left="onClickLeft"
+    ></van-nav-bar>
+    <van-empty style="position: relative;left: 0;top: 50%;transform: translateY(-50%);" image="network" description="请求失败了呢" />
+</div>
+</template>
+
+<script>
+export default {
+  name: 'error',
+  components: {},
+    props: [],
+  data () {
+    return {
+    }
+  },
+  created () { },
+  methods: { 
+    onClickLeft(){
+      this.$router.replace('/courseHome')
+    }
+   },
+  computed: {}
+}
+</script>
+<style scoped lang='scss'>
+
+</style>

+ 238 - 0
src/view/course/home.vue

@@ -0,0 +1,238 @@
+<template>
+  <div class="homePage">
+    <div class="homeContent">
+      <scroller 
+      :isInitRefresh="false" 
+      ref="recordScroller"
+      :list="courseList"
+      noDataText="没有更多..."
+      :on-refresh='resetList'
+      :on-infinite="getMoreList">
+        <div class="tit" style="margin-top: .3rem;">
+          <span>今日更新</span>
+        </div>
+        <div class="freeContent">
+          <template v-if="freeCourseList.length>0">
+            <div class="freeLi" v-for="(item,index) in freeCourseList" :key="index" @click="toUrl(item)">
+              <div class="liIcon">
+                <van-icon name="play-circle-o" />
+              </div>
+              <div class="freeR">
+                <p>{{ item.name }}</p>
+                <span>{{ getRandomNumber(10,30) }}人学习中</span>
+              </div>
+            </div>
+          </template>
+          <template v-else>
+            <p>暂无数据</p>
+          </template>
+        </div>
+        <div class="tit">
+          <span>课程推荐</span>
+        </div>
+        <courseList :dataList="courseList" :showNum="4"></courseList>
+      </scroller>
+      <van-tabbar v-model="active" @change="activeChange">
+        <van-tabbar-item icon="home-o">首页</van-tabbar-item>
+        <van-tabbar-item icon="friends-o">我的</van-tabbar-item>
+      </van-tabbar>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getUserAllCourseList ,getFreeCourseList} from "./api";
+import courseList from "./components/courseList.vue";
+import {setDocumentTitle} from '../../components/vueHashCalendar/utils/util'
+import {setWxConfig} from './utils'
+export default {
+  name: "courseHome",
+  components: {
+    courseList
+  },
+  data() {
+    return {
+      active:0,
+      canReq: true,
+      noDate: false,
+      logo:require('../../../static/images/logo.png'),
+      page: {
+        cur: 1,
+        size: 10,
+        total: 0
+      },
+      courseList: [],
+      freeCourseList:[]
+    };
+  },
+  activated(){
+    this.init();
+    if(this.$isWx){
+      setWxConfig();
+    }
+  },
+  deactivated(){
+    this.page.cur = 1;
+    this.courseList = []
+  },
+  methods: {
+    // 随机学习中
+    getRandomNumber(min, max) {
+      return Math.floor(Math.random() * (max - min + 1)) + min;
+    },
+    //跳转免费课程
+    toUrl(item){
+      this.$router.push({
+        path:`/freeCourse`,
+        query:item
+      })
+    },
+    // 触底加载
+    getMoreList(done) {
+      if (!this.noDate) {
+        setTimeout(() => {
+          this.getList(done);
+        }, 300);
+      } else {
+        this.$refs.recordScroller.finishInfinite(true);
+      }
+    },
+    //上拉刷新
+    resetList(done){
+      this.page.cur = 1;
+      this.getList(done,1)
+    },
+    //底部导航变化
+    activeChange(){
+      if(this.active != 0){
+        this.$router.push('/courseUser')
+        this.active = 0
+      }
+    },
+    // 初始化
+    init() {
+      this.getList();
+      this.getFreeList();
+    },
+    // 获取免费课程列表
+    getFreeList(){
+      getFreeCourseList().then(res=>{
+        this.freeCourseList = res.sections
+      })
+    },
+    // 获取所有课程列表
+    getList(done,type) {
+      let data = {
+        page: this.page.cur,
+        pageSize: this.page.size,
+        enable: 1
+      };
+      getUserAllCourseList(data).then(res => {
+        let list = []
+        res.list.forEach(item => {
+          let data = {
+              subjectName: item.name,
+              subjectId: item.id,
+              subjectPrice: item.price,
+              subjectThumb: item.thumb,
+              subjectEnable: item.enable,
+              sectionsNum: item.sectionsNum,
+              clickNum:Number(item.baseClick) + Number(item.clickNum)
+            };
+            list.push(data);
+        });
+        if(type == 1){
+          this.courseList = list;
+        }else{
+          this.courseList = this.courseList.concat(list);
+        }
+        this.page.total = res.total;
+        this.page.cur = res.current;
+        if (res.pages == res.current || res.pages == 0) {
+          if (done) done(true);
+          this.noDate = true;
+        } else {
+          if (done) done();
+          this.page.cur++; //下拉一次页数+1
+          this.noDate = false;
+        }
+      });
+    },
+  }
+};
+</script>
+<style scoped lang="scss">
+*{
+  margin: 0;
+  padding: 0;
+}
+.homePage {
+  background: #f3f2ee;
+  background: linear-gradient(90deg, #f3f2ee, #e7eff9);
+  .homeContent {
+    height: calc(100vh - 1rem);
+    margin: 0 .2rem;
+    box-sizing: border-box;
+    position: relative;
+    .tit{
+      display: flex;
+      span{
+        font-size: .32rem;
+        color: #000;
+        font-weight: 600;
+        line-height: .6rem;
+      }
+    }
+    .freeContent{
+      margin-bottom: .3rem;
+      &>p{
+        font-size: .26rem;
+        color: #888;
+        line-height: 1rem;
+        text-align: center;
+      }
+      .freeLi{
+        background-color: #FFF;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        border-radius: 0.1rem;
+        margin-bottom: 0.1rem;
+        padding: 0.15rem;
+        .liIcon{
+          background: #DBECFE;
+          width: .8rem;
+          height: .8rem;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          border-radius: .1rem;
+          i{
+            font-size: .62rem;
+            color:#609DFF;
+          }
+        }
+        .freeR{
+          flex: 1;
+          margin-left: .2rem;
+          width: calc(100% - 1.2rem);
+          p{
+            font-size: .3rem;
+            color: #333;
+            line-height: .35rem;
+            text-overflow: ellipsis;
+            overflow: hidden;
+            word-break: break-all;
+            white-space: nowrap;
+          }
+          span{
+            font-size: .22rem;
+            color: #999;
+            line-height: .3rem;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 546 - 0
src/view/course/user.vue

@@ -0,0 +1,546 @@
+<template>
+    <div class="curPage">
+      <div class="userInfo">
+        <van-row
+          type="flex"
+          class="imageName"
+          justify="space-between"
+          align="center"
+        >
+          <div class="userImage">
+            <userImage
+              class="about-me__avatar"
+              :img_url="user_info.imgUrl"
+              :user_name="user_info.name"
+              width="1.12rem"
+              height="1.12rem"
+              v-if="user_info.imgUrl"
+            ></userImage>
+            <div style="background: #26A2FF;border-radius: 50%;overflow: hidden;" v-else>
+              <userImage
+                class="about-me__avatar"
+                :img_url="defaultImgUrl"
+                user_name="用户"
+                width="1.12rem"
+                height="1.12rem"
+              ></userImage>
+            </div>
+            <div class="info">
+              <span
+                >{{ user_info.name ? user_info.name : "新用户"
+                }}<van-icon
+                  name="notes-o"
+                  color="#E1B98B"
+                  style="margin-left: .1rem;"
+              /></span>
+              <!-- <p>手机:{{ user_info.tel }}</p> -->
+              <!-- <p
+                class="userId"
+                :aria-label="user_info.id"
+                @click="copyLink('.userId')"
+              >
+                <i class="courseIcon icon-fuzhi"></i>复制身份ID
+              </p> -->
+            </div>
+          </div>
+          <div class="user_leave">
+            <van-icon name="gem-o" color="#a66666" />
+            {{ user_info.marketable ? "经销商" : "学员" }}
+          </div>
+        </van-row>
+      </div>
+      <div class="user_tabs" v-if="user_info.marketable">
+        <div class="tabs_content">
+          <div class="tabsLi" @click="toUrl('/courseTeam/1')">
+            <van-image
+              src="static/images/course_team.png"
+              style="width: .8rem;height: .8rem;"
+              type="contain"
+            />
+            <span>我的团队</span>
+          </div>
+          <div class="tabsLi" @click="qropen">
+            <van-image
+              src="static/images/course_ewm.png"
+              style="width: .8rem;height: .8rem;"
+              type="contain"
+            />
+            <span>邀请二维码</span>
+          </div>
+          <div class="tabsLi" @click="toUrl('/courseTeam/2')">
+            <van-image
+              src="static/images/course_dingdan.png"
+              style="width: .8rem;height: .8rem;"
+              type="contain"
+            />
+            <span>交易往来</span>
+          </div>
+        </div>
+      </div>
+      <div class="user_course_tabs" v-if='user_info.marketable'>
+        <van-tabs v-model="tbsIndex" style="width: 60%;">
+          <van-tab title="我的推广"></van-tab>
+          <van-tab title="我的学习"></van-tab>
+        </van-tabs>
+        <!-- <div class="tbsL" v-if='user_info.marketable'>
+          <div class="tbsi" :class="{active:tbsIndex==0}" @click="selectTbs(0)">我的推广</div>
+          <div class="tbsi" :class="{active:tbsIndex==1}" @click="selectTbs(1)">我的学习</div>
+        </div> -->
+        <div class="tbsR" v-if="user_info.marketable" @click="toMoreUrl">
+          <span>名额变动明细<van-icon name="arrow" /></span>
+        </div>
+      </div>
+      <!-- <van-search
+        v-model="wxId"
+        placeholder="请输入wxid替换当前账号"
+        show-action
+        style="margin: 0.1rem 0.2rem 0;border-radius: 0.1rem;"
+        @search="changeUSer"
+      /> -->
+      <div
+        class="courScroll"
+        :style="{
+          height: user_info.marketable
+            ? 'calc(100vh - 5.38rem) !important'
+            : 'calc(-3.05rem + 100vh) !important'
+        }"
+      >
+        <scroller ref="scroller" :isInitRefresh="false">
+          <van-loading
+            v-show="showLoad"
+            style="margin: 0px auto;position: relative;left: 50%;transform: translateX(-0.25rem);"
+          />
+          <div
+            class="myCourseList"
+            v-if="user_info.marketable && tbsIndex == 0 && !showLoad"
+          >
+            <courseList
+              :dataList="courseClass.proCourse.courseList"
+              :showNum="1"
+              :fixedTitle="courseClass.proCourse.title"
+            ></courseList>
+          </div>
+          <div class="myCourseList" v-if="tbsIndex == 1 && !showLoad">
+            <courseList
+              :dataList="courseClass.learnCourse.courseList"
+              :fixedTitle="courseClass.learnCourse.title"
+              isNoAd
+            ></courseList>
+          </div>
+        </scroller>
+        <van-tabbar v-model="active" @change="activeChange">
+            <van-tabbar-item icon="home-o">首页</van-tabbar-item>
+            <van-tabbar-item icon="friends-o">我的</van-tabbar-item>
+        </van-tabbar>
+      </div>
+      <van-overlay :show="qrVisible" @click="qrVisible = false">
+        <div class="wrapper">
+          <div class="qrContent">
+            <div class="tit">
+              邀请二维码
+            </div>
+            <div class="qrcode-wrap" ref="qrCodeUrl"></div>
+            <div class="btm">
+              <p>邀请朋友成为经销商,并加入你的团队</p>
+            </div>
+          </div>
+        </div>
+      </van-overlay>
+    </div>
+  </template>
+  
+  <script>
+  import Clipboard from "clipboard";
+  import QRCode from "qrcodejs2";
+  import courseList from "./components/courseList.vue";
+  import {setDocumentTitle} from '../../components/vueHashCalendar/utils/util'
+  import {setWxConfig} from './utils'
+  import {
+    getWxApiToken,
+    getUSerInfo,
+    getDealerCourseList,
+    getUserCourseList
+  } from "./api";
+  export default {
+    name: "courseUser",
+    components: {
+      courseList
+    },
+    data() {
+      return {
+        active:1,
+        defaultImgUrl:require('../../assets/images/headLogo.jpg'),
+        showLoad: false,
+        tbsIndex: 0,
+        clipboard: null,
+        qrVisible: false,
+        qrcode: null,
+        qrcodeStatus: false,
+        isAndroid: this.$getCache("isAndroid"),
+        user_info: {
+          imgUrl: "",
+          id: "0",
+          name: "用户名",
+          mobile: "0",
+          marketable: false
+        },
+        page: {
+          cur: 1,
+          size: 10,
+          total: 0
+        },
+        courseClass: {
+          proCourse: {
+            title: "我推广的课程",
+            total: 0,
+            courseList: []
+          },
+          learnCourse: {
+            title: "我学习的课程",
+            total: 0,
+            courseList: []
+          }
+        },
+        wxId: "11770"
+      };
+    },
+    activated(){
+      this.init();
+      if(this.$isWx){
+        setWxConfig();
+      }
+    },
+    methods: {
+        //底部导航变化
+        activeChange(){
+            if(this.active != 1){
+                this.$router.push('/courseHome');
+                this.active = 1;
+            }
+        },
+      // 推广/学习标签切换
+      selectTbs(i) {
+        if (this.user_info.marketable) {
+          if (i == 0 && this.tbsIndex != 0) {
+            this.tbsIndex = 0;
+            this.showLoad = true;
+            setTimeout(() => {
+              this.getDealerCourseList();
+            }, 1000);
+          } else if (i == 1 && this.tbsIndex != 1) {
+            this.tbsIndex = 1;
+            this.showLoad = true;
+            setTimeout(() => {
+              this.getUserCourseList();
+            }, 1000);
+          }
+        }
+      },
+      //查看名额变动明细
+      toMoreUrl() {
+        // this.$router.push(`/course/adlist`);
+        this.$router.push(`/course/limitChange`);
+      },
+      // 清楚本地存储/测试用
+      changeUSer() {
+        localStorage.clear();
+        this.getUerInfo(this.wxId);
+      },
+      // 获取指定用户信息/测试用
+      getUerInfo(wxid) {
+        getWxApiToken(wxid).then(token => {
+          getUSerInfo(token).then(res => {
+            this.user_info = JSON.parse(localStorage.getItem("wx_user_info"));
+            if (this.user_info.marketable) {
+              getDealerCourseList();
+            } else if (!this.user_info.marketable) {
+              this.tbsIndex = 1;
+            }
+            getUserCourseList();
+          });
+        });
+      },
+      //获取用户数据
+      init() {
+        this.user_info = JSON.parse(localStorage.getItem("wx_user_info"));
+        if (this.user_info.marketable) {
+          this.getDealerCourseList();
+        } else if (!this.user_info.marketable) {
+          this.tbsIndex = 1;
+        }
+        this.getUserCourseList();
+      },
+      //获取经销推广课程列表
+      getDealerCourseList(done) {
+        getDealerCourseList().then(res => {
+          this.courseClass.proCourse.total = res.total;
+          this.courseClass.proCourse.courseList = res.list;
+          this.showLoad = false;
+          if (done) done();
+        });
+      },
+      //获取用户消费的课程列表
+      getUserCourseList(done) {
+        getUserCourseList().then(res => {
+          this.courseClass.learnCourse.total = res.total;
+          let list = [];
+          res.list.forEach(item => {
+            let data = {
+              subjectName: item.name,
+              subjectId: item.id,
+              subjectPrice: item.price,
+              subjectThumb: item.thumb,
+              subjectEnable: item.enable,
+              sectionsNum: item.sectionsNum
+            };
+            list.push(data);
+          });
+          this.courseClass.learnCourse.courseList = list;
+          this.showLoad = false;
+          if (done) done();
+        });
+      },
+      // 打开二维码
+      qropen() {
+        this.qrVisible = true;
+        this.$nextTick(() => {
+          this.creatQrCode();
+        });
+      },
+      // 创建二维码
+      creatQrCode() {
+        if (!this.qrcodeStatus) {
+          this.qrcode = new QRCode(this.$refs.qrCodeUrl, {
+            text: `${window.location.href.split("#")[0]}#/courseLogin?pid=${
+              JSON.parse(localStorage.getItem("wx_user_info")).id
+            }`, // 需要转换为二维码的内容
+            width: 200,
+            height: 200,
+            colorDark: "#000000",
+            colorLight: "#ffffff",
+            correctLevel: QRCode.CorrectLevel.H
+          });
+          this.qrcodeStatus = true;
+        }
+      },
+      //复制剪切板
+      copyLink(event) {
+        let that = this;
+        //这里是复制目标的类名
+        that.clipboard = new Clipboard(event, {
+          text: function(trigger) {
+            return trigger.getAttribute("aria-label");
+          }
+        });
+        that.clipboard.on("success", function(e) {
+          e.clearSelection(); //清除选中的文字的选择状态
+          that.$toast.success("ID复制成功~");
+        });
+  
+        that.clipboard.on("error", function(e) {
+          console.error(e);
+        });
+      },
+      //跳转内页
+      toUrl(url, params) {
+        this.$router.push({
+          path: url
+        });
+      }
+    }
+  };
+  </script>
+  <style scoped lang="scss">
+  @import "../../assets/iconfont.css";
+  * {
+    margin: 0;
+    padding: 0;
+  }
+  img {
+    display: block;
+  }
+  .curPage {
+    height: 100%;
+    position: relative !important;
+    padding-top: 0.4rem;
+    background: #f3f2ee;
+    background: linear-gradient(90deg, #f3f2ee, #e7eff9);
+    .userInfo {
+      padding: 0.24rem 0.32rem 0.12rem;
+      .userImage {
+        display: flex;
+        align-items: center;
+        flex: 1;
+        .info {
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          margin-left: 0.2rem;
+          span {
+            font-size: 0.32rem;
+            font-weight: 600;
+            color: #000;
+            line-height: 2;
+            display: block;
+          }
+          p {
+            font-size: 0.22rem;
+            color: #222;
+            line-height: 1;
+            display: block;
+            i {
+              font-size: 0.22rem;
+              color: #222;
+              line-height: 1;
+            }
+          }
+        }
+      }
+      .user_leave {
+        padding: 0.05rem 0.3rem;
+        font-size: 0.26rem;
+        font-weight: 550;
+        color: #a66666;
+        border: 1px solid #c9c3c0;
+        border-radius: 0.1rem;
+        line-height: 1.5;
+      }
+    }
+    .user_tabs {
+      padding: 0 0.2rem;
+      margin-top: 0.15rem;
+      .tabs_content {
+        box-sizing: border-box;
+        height: 1.5rem;
+        padding: 0.1rem 0;
+        display: flex;
+        justify-content: space-around;
+        border-radius: 0.1rem;
+        background: #fff;
+        .tabsLi {
+          // flex: 1;
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          align-items: center;
+          span {
+            font-size: 0.24rem;
+            color: #333;
+            line-height: 0.3rem;
+          }
+        }
+      }
+    }
+    .user_course_tabs {
+      margin: 0.15rem 0.2rem 0;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      background-color: #fff;
+      border-radius: .1rem;
+      overflow: hidden;
+      .ctbsL {
+        width: 2rem;
+        display: flex;
+        align-items: center;
+      }
+      .tbsL {
+        width: 60%;
+        display: flex;
+        align-items: center;
+        .tbsi {
+          padding: 0 0.15rem;
+          border-radius: 0.25rem;
+          border: 0.02rem solid #999;
+          font-size: 0.24rem;
+          color: #444;
+          line-height: 0.4rem;
+          text-align: center;
+          margin-right: 0.2rem;
+          &.active {
+            border: 1px solid rgb(22, 132, 252);
+            background-color: rgba(38, 162, 255, 0.1);
+            color: rgb(22, 132, 252);
+          }
+        }
+      }
+      .tbsR {
+        display: flex;
+        align-items: center;
+        margin-right: .2rem;
+        span {
+          font-size: 0.24rem;
+          color: #333;
+          line-height: 0.4rem;
+        }
+      }
+    }
+    .courScroll {
+      height: calc(100vh - 2.75rem) !important;
+      position: relative;
+      .cScroll {
+        height: 100%;
+        position: relative !important;
+      }
+      .myCourseList {
+        &:nth-child(2) {
+          padding-bottom: 0.4rem;
+        }
+        padding: 0 0.2rem;
+        // margin-top: 0.2rem;
+      }
+    }
+    .wrapper {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      height: 100vh;
+      .qrContent {
+        width: 70%;
+        border-radius: 0.2rem;
+        overflow: hidden;
+        background-color: #FFF;
+        .btm{
+          font-size: .23rem;
+          color: #666;
+          line-height: .6rem;
+          text-align: center;
+          border: 0;
+        }
+        .tit {
+          position: relative;
+          width: 100%;
+          text-align: center;
+          font-size: 0.3rem;
+          color: #333;
+          line-height: 0.8rem;
+          &::after {
+            content: "X";
+            position: absolute;
+            right: 0.2rem;
+            top: 0.2rem;
+            font-size: 0.3rem;
+            line-height: 0.3rem;
+          }
+        }
+        .qrcode-wrap {
+          padding: 0.2rem .2rem 0;
+          background-color: #fff;
+          text-align: center;
+          display: flex;
+          justify-content: center;
+        }
+      }
+    }
+  }
+  /deep/ .van-search .van-cell {
+    padding: 0.1rem 0.16rem 0.1rem 0.16rem;
+  }
+  /deep/ .van-tabs--line .van-tabs__wrap{
+    height: .68rem;
+  }
+  /deep/ .van-tab--active{
+    font-weight: 600;
+  }
+  </style>
+  

+ 439 - 0
src/view/course/user/courseAdDeal.vue

@@ -0,0 +1,439 @@
+<template>
+  <div class="page">
+    <van-nav-bar
+      :title="title"
+      left-text="返回"
+      left-arrow
+      @click-left="onClickLeft"
+    ></van-nav-bar>
+    <div id="linkCode" style="display: none;" :data-clipboard-text="giveLink">
+      {{ giveLink }}
+    </div>
+    <div class="courseContent">
+      <scroller
+        ref="recordScroller"
+        :on-infinite="getMoreList"
+        :list="recordList"
+        noDataText="没有更多..."
+      >
+        <courseList :dataList="courseInfo" :showNum="2"></courseList>
+        <div class="record">
+          <p>名额变动明细</p>
+          <div class="recordList">
+            <div
+              class="recordLi"
+              v-for="(item, index) in recordList"
+              :key="index"
+            >
+              <div class="flex-name-num">
+                <p>{{ item.subjectName }}</p>
+                <span
+                  :style="{
+                    color: Number(item.amount) > 0 ? '#26A2FF' : 'red'
+                  }"
+                  >{{
+                    Number(item.amount) > 0 ? `+${item.amount}` : item.amount
+                  }}</span
+                >
+              </div>
+              <p>{{ item.content }}</p>
+              <span>{{ item.createTime }}</span>
+            </div>
+          </div>
+        </div>
+      </scroller>
+    </div>
+    <div class="courseShare" @click="comfirmCode">
+      <span>赠送课程给好友(当前剩余:{{ courseDetail.amount }}套)</span>
+    </div>
+    <van-share-sheet
+      v-model="showShare"
+      title="立即赠送给好友"
+      :options="options"
+      @select="onSelect"
+      class="linkCodeShare"
+    />
+    <van-overlay :show="showGive" @click="showGive = false">
+      <div class="wrapper" @click.stop>
+        <div class="tit">
+          赠送课程给好友
+          <div class="cancle" @click="showGive = false">
+            <van-icon name="cross" />
+          </div>
+        </div>
+        <div class="msg">
+          请提醒好友尽快点击链接领取课程名额。链接分享后,1小时内有效。
+        </div>
+        <div class="copy">
+          <p><van-icon name="info-o" /> 链接分享后,1小时内有效</p>
+          <!-- <van-button
+            style="padding: 0 1rem;border-radius: 0.4rem;"
+            color="#26A2FF"
+            class="copyCode"
+            @click="getCourseCode"
+            >复制链接</van-button> -->
+            <button ref="copys"  id="copyLink"   data-clipboard-action="copy" data-clipboard-target="#copy_text" @click.prevent.stop="copy($event)">复制链接</button>
+        </div>
+      </div>
+    </van-overlay>
+    
+    <input type="text" v-model="giveLink" readonly id="copy_text" style="opacity: 0">
+  </div>
+</template>
+<script>
+import { getCourseRecordList, createCourseCode ,getDealerCourseDetail} from "../api";
+import {setWxConfig} from '../utils'
+import Clipboard from "clipboard";
+import courseList from "../components/courseList.vue";
+import wx from "weixin-js-sdk";
+export default {
+  name: "courseAdDetail",
+  components: { courseList },
+  props: [],
+  data() {
+    return {
+      subjectId:0,
+      courseId:0,
+      showShare: false,
+      loading: false,
+      finished: false,
+      activeTab: 0,
+      title: "课程详情",
+      giveLink: "",
+      noDate: false,
+      showGive: false,
+      options: [
+        // { name: '微信', icon: 'wechat' },
+        { name: "复制链接", icon: "link" }
+        // { name: '二维码', icon: 'qrcode' },
+      ],
+      page: {
+        cur: 1,
+        total: 0,
+        size: 10
+      },
+      courseDetail: {
+        id: 0, //资产id
+        userId: 0, //用户id
+        subjectId: 0, //课程id
+        subjectName: "",
+        subjectThumb: "", //缩略图
+        subjectPrice: 0, //课程价格
+        sectionsNum: 0, //章节数
+        subjectEnable: 1, //是否上架
+        amount: 0, //剩余名额
+        statistics: {
+          saleAmount: 0, //已卖出
+          transferOutAmount: 0, //已转入
+          transferInAmount: 0 //已转出
+        }
+      },
+      recordList: [],
+      copyBtn:null,
+    };
+  },
+  computed: {
+    courseInfo() {
+      let list = [];
+      if (this.courseDetail && this.courseDetail.userId != 0) {
+        list.push(this.courseDetail);
+      }
+      return list;
+    }
+  },
+  created() {
+    // this.init();
+  },
+  activated(){
+    this.init();
+    if(this.$isWx){
+      setWxConfig();
+    }
+  },
+  deactivated(){
+    this.page.cur = 1;
+    this.recordList = [];
+  },
+  mounted(){
+    this.copyBtn = new Clipboard(this.$refs.copys);
+  },
+  methods: {
+    //分享链接
+    shareLink(){
+      if(this.$isWx){
+        wx.updateAppMessageShareData({ 
+          title: this.courseDetail.subjectName, // 分享标题
+          desc: '点击查看课程', // 分享描述
+          link: this.giveLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
+          imgUrl: this.courseDetail.subjectThumb, // 分享图标
+          success: function () {
+            // 设置成功
+            console.log("分享成功")
+            // this.$toast.success('')
+          }
+        })
+      }else{
+        this.$toast.fail('请在微信中打开分享')
+      }
+    },
+    //复制
+    copy (event) {
+      let _this = this
+      let clipboard = _this.copyBtn
+      clipboard.on('success', function () {
+        event.preventDefault()
+        _this.$toast.success('复制成功')
+      })
+      clipboard.on('error', function (e) {
+        console.error('复制失败',e)
+      })
+    },
+    // 分享课程方式选择
+    onSelect(option) {
+      if (option.name == "复制链接") {
+        this.showGive = true;
+        this.showShare = false;
+      }
+    },
+    //获取课程详情
+    getCourseDetail(){
+      getDealerCourseDetail(this.courseId).then(res=>{
+        this.courseDetail = res
+      })
+    },
+    // 获取课程码
+    getCourseCode() {
+      createCourseCode(this.courseDetail.subjectId).then(res => {
+        this.giveLink = `点我领取课程,1小时内可领取 ${window.location.href.split("#")[0]}#/courseDetail/${
+          this.subjectId
+        }?code=${res}`;
+        console.log(this.giveLink)
+        this.showGive = true;
+        // this.getCourseDetail();
+        // this.copyLink().then(()=>{
+        //   this.$toast.success('复制成功')
+        //   this.showGive = false;
+        // })
+      });
+    },
+    // 复制剪切板
+    copyLink() {
+      let oInput = document.createElement("input");
+      oInput.value = this.giveLink;
+      document.body.appendChild(oInput);
+      oInput.select(); // 选择对象
+      if (navigator.userAgent.match(/(iPhone|iPod|iPad);?/i)) {//兼容ios
+        if (!document.execCommand("Copy")) {
+          oInput.setSelectionRange(0, oInput.value.length);
+        }
+      }
+      document.execCommand("Copy"); // 执行浏览器复制命令
+      document.body.removeChild(oInput);
+      return new Promise((resolve,reject)=>{
+          if (document.execCommand("Copy")) {
+              resolve(this.giveLink);
+          }else{
+              reject(this.giveLink);
+          }
+      })
+    },
+    // 分享弹出
+    comfirmCode() {
+      // this.showGive = true;
+      this.getCourseCode()
+    },
+    // 触底加载
+    getMoreList(done) {
+      if (!this.noDate) {
+        setTimeout(() => {
+          this.getRecord(done);
+        }, 300);
+      } else {
+        this.$refs.recordScroller.finishInfinite(true);
+      }
+    },
+    // 获取课程变动记录
+    getRecord(done) {
+      let data = {
+        page: this.page.cur,
+        pageSize: this.page.size,
+        subjectId: this.subjectId
+      };
+      getCourseRecordList(data).then(res => {
+        this.recordList = this.recordList.concat(res.list);
+        this.page.cur = res.current;
+        this.page.total = res.total;
+        if (res.pages == res.current || res.pages == 0) {
+          if (done) done(true);
+          this.noDate = true;
+        } else {
+          if (done) done();
+          this.page.cur++; //下拉一次页数+1
+          this.noDate = false;
+        }
+      });
+    },
+    // 返回
+    onClickLeft() {
+      if(window.history.length>1){
+        this.$router.go(-1);
+      }else{
+        this.$router.replace('/courseHome')
+      }
+    },
+    // 初始化
+    init() {
+      let arr = this.$route.params.id.split('-')
+      this.courseId = arr[0];
+      this.subjectId = arr[1]
+      this.getCourseDetail();
+      this.getRecord();
+    },
+    destroyed() {
+      sessionStorage.removeItem("course_detail");
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+@import url('../utils/navBar.scss');
+* {
+  margin: 0;
+  padding: 0;
+}
+img {
+  display: block;
+}
+.page {
+  background-color: #fff;
+  box-sizing: border-box;
+  position: relative;
+  .courseContent {
+    height: calc(100vh - 1.9rem);
+    position: relative;
+    .record {
+      border-top: 1px solid #efefef;
+      border-bottom: 1px solid #efefef;
+      & > p {
+        font-size: 0.28rem;
+        line-height: 0.8rem;
+        color: #000;
+        font-weight: 550;
+        padding: 0 0.2rem;
+      }
+      .recordList {
+        border-top: 0.02rem solid #efefef;
+        // border-bottom: 1px solid #999;
+        .recordLi {
+          background: #fff;
+          padding: 0 0.2rem;
+          overflow: hidden;
+          &:not(:nth-last-child(1)) {
+            border-bottom: 1px solid #efefef;
+          }
+          .flex-name-num {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding-top: 0.1rem;
+            & > p {
+              font-size: 0.32rem;
+              color: #000;
+              line-height: 1.5;
+            }
+            & > span {
+              font-size: 0.32rem;
+              color: #000;
+              line-height: 2;
+              margin-left: 0.1rem;
+            }
+          }
+          & > p {
+            font-size: 0.28rem;
+            color: #666;
+            line-height: 1;
+          }
+          & > span {
+            font-size: 0.28rem;
+            color: #666;
+            line-height: 1;
+            display: block;
+            margin-top: 0.2rem;
+            margin-bottom: 0.1rem;
+          }
+        }
+      }
+    }
+  }
+  .courseShare {
+    width: calc(100% - 0.6rem);
+    height: 0.8rem;
+    position: absolute;
+    left: 0.3rem;
+    bottom: 0.1rem;
+    background-color: #26a2ff;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border-radius: 0.15rem;
+    span {
+      font-size: 0.26rem;
+      color: #fff;
+    }
+  }
+  .wrapper {
+    background: #fff;
+    width: 75%;
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    border-radius: 0.2rem;
+    padding: 0.3rem 0.2rem;
+    .tit {
+      font-size: 0.32rem;
+      color: #333;
+      line-height: 0.8rem;
+      text-align: center;
+      position: relative;
+      font-weight: 600;
+      position: relative;
+      .cancle {
+        position: absolute;
+        top: 0;
+        right: 0;
+        font-size: 0.3rem;
+        line-height: 0.3rem;
+      }
+    }
+    .msg {
+      font-size: 0.27rem;
+      text-align: center;
+      padding: 0 0.1rem;
+    }
+    .copy {
+      text-align: center;
+      margin-top: 0.5rem;
+      #copyLink{
+        padding: 0px 1rem;
+        border-radius: 0.4rem;
+        color: white;
+        background: rgb(38, 162, 255);
+        border-color: rgb(38, 162, 255);
+        line-height: .75rem;
+        border: 0;
+        outline: none;
+      }
+      p {
+        font-size: 0.22rem;
+        color: #888;
+        line-height: 0.3rem;
+        margin-bottom: 0.15rem;
+      }
+    }
+  }
+}
+/deep/ .van-tab--active{
+  font-weight: 600;
+}
+</style>

+ 423 - 0
src/view/course/user/courseDeal.vue

@@ -0,0 +1,423 @@
+<template>
+  <div class="page">
+    <van-nav-bar :title="title" @click-left="onClickLeft">
+      <template #left>
+        <template v-if="$route.query && $route.query.code">
+          <van-icon name="wap-home-o" />
+          <span style="font-size: .32rem;color: #FFF;">首页</span>
+        </template>
+        <template v-else>
+          <van-icon name="arrow-left" />
+          <span style="font-size: .32rem;color: #FFF;">返回</span>
+        </template>
+      </template>
+    </van-nav-bar>
+    <div class="courseContent">
+      <div class="tabs">
+        <div v-show="showBack" class="toTop" @click="BackTop">
+          <span><van-icon name="back-top"/></span>
+        </div>
+        <scroller ref="scroller" :on-scrolling="scrollChange">
+          <div class="previewImg">
+            <img :src="courseDetail.thumb" />
+          </div>
+          <div class="title">
+            <span>{{ courseDetail.price }}</span>
+            <p>{{ courseDetail.name }}</p>
+            <i style="margin-right: .1rem;"
+              >已更新{{ courseDetail.sections.length }}节课</i
+            >
+            <i
+              >{{
+                Number(courseDetail.baseClick) + Number(courseDetail.clickNum)
+              }}次浏览</i
+            >
+          </div>
+          <van-tabs v-model="activeTab" swipeable sticky>
+            <van-tab title="课程介绍">
+              <div class="images">
+                <div
+                  class="descImage"
+                  v-for="(item, index) in courseDetail.images"
+                  :key="index"
+                >
+                  <img :src="item" />
+                </div>
+              </div>
+            </van-tab>
+            <van-tab title="课程目录">
+              <div class="catelog">
+                <div class="logConetent">
+                  <div
+                    class="logLi"
+                    v-for="(item, index) in courseDetail.sections"
+                    :key="index"
+                    @click="toSectionVidio(item, index)"
+                  >
+                    <p>{{ index + 1 }}、{{ item.name }}</p>
+                  </div>
+                </div>
+              </div>
+            </van-tab>
+          </van-tabs>
+          <div
+            id="xxhh"
+            style="height: 1.2rem;"
+            v-if="!courseDetail.buy && canGive && canGive2"
+          ></div>
+        </scroller>
+      </div>
+      <div
+        class="getCourse"
+        v-if="!courseDetail.buy && canGive && canGive2"
+        @click="useCode"
+      >
+        <van-button icon="fire-o" square class="getBtn"
+          >点击领取课程名额</van-button
+        >
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { setWxConfig } from "../utils";
+import wx from 'weixin-js-sdk'
+import {
+  learnerCourseDetail,
+  getCourseCodeDetail,
+  getCourseCode,
+  getVideoSrc
+} from "../api";
+export default {
+  name: "courseDetail",
+  components: {},
+  props: [],
+  data() {
+    return {
+      showBack:false,
+      activeTab: 0,
+      title: "课程详情",
+      courseDetail: {
+        thumb: "",
+        name: "",
+        images: [],
+        sections: [],
+        buy: false
+      },
+      canGive: true,
+      canGive2: true,
+      giveCode: false,
+      codeDetail: {
+        enable: true
+      }
+    };
+  },
+  created() {
+    // this.init();
+  },
+  activated(){
+    this.init();
+  },
+  methods: {
+    scrollChange(e){
+      //需要滚动的界面实际长度大于整个页面长度
+      if(e>40&&document.getElementsByClassName('page')[0].offsetHeight<document.getElementsByClassName('_v-content')[0].offsetHeight){
+        this.showBack = true;
+      }else{
+        this.showBack = false;
+      }
+    },
+    //回到顶部
+    BackTop() {
+      this.$refs.scroller.scrollTo(0, 0, 500);
+    },
+    // 领取课程提示
+    useCode() {
+      if (this.codeDetail && this.codeDetail.enable) {
+        this.$dialog
+          .confirm({
+            title: "提示",
+            message: "确定领取当前课程吗"
+          })
+          .then(() => {
+            let data = {
+              salesCode: this.codeDetail.salesCode,
+              userId: this.codeDetail.userId,
+              subjectId: this.codeDetail.subjectId
+            };
+            getCourseCode(data).then(res => {
+              this.$toast.success("领取成功!");
+              this.giveCode = true;
+              this.getDetail();
+            });
+          });
+      } else {
+        this.$dialog.confirm({
+          title: "提示",
+          message: "该课程码已失效"
+        });
+        // this.$toast.fail("该课程码已失效");
+      }
+    },
+    // 领取课程码课程
+    getCodeDetail() {
+      getCourseCodeDetail(this.$route.query.code).then(res => {
+        this.codeDetail = res;
+        if (!res && !this.courseDetail.buy) {
+          this.$dialog.confirm({
+            title: "提示",
+            message: "该课程码已失效"
+          });
+          // this.$toast.fail("该课程码已失效");
+        }
+      });
+    },
+    // 章节点击观看视频
+    toSectionVidio(item, index) {
+      if (this.courseDetail.buy && this.courseDetail.enable) {
+        let data = {
+          index: index,
+          link: item.link
+        };
+        sessionStorage.setItem("vd_info", JSON.stringify(data));
+        this.$router.push({
+          path: `/course/video/${this.$route.params.id}`
+        });
+      } else if (!this.courseDetail.buy) {
+        this.$toast.fail("请先领取课程后再观看");
+      } else {
+        this.$toast.fail("课程已下架");
+      }
+    },
+    // 返回首页
+    onClickLeft() {
+      if (this.$route.query && (this.$route.query.code)) {
+        this.$router.push("/courseHome");
+      } else {
+        this.$router.go(-1);
+      }
+    },
+    // 初始化
+    init() {
+      this.courseId = this.$route.params.id;
+      if (this.$route.query && this.$route.query.code && this.$route.query.code != 2) {
+        this.getDetail();
+      } else {
+        this.getDetail();
+        this.canGive = false;
+      }
+    },
+    //删除URL的指定参数
+    urlDelP(url,name){
+      var urlArr = url.split('?');
+      if(urlArr.length>1 && urlArr[1].indexOf(name)>-1){
+          var query = urlArr[1];
+          var obj = {}
+          var arr = query.split("&");
+          for (var i = 0; i < arr.length; i++) {
+              arr[i] = arr[i].split("=");
+              obj[arr[i][0]] = arr[i][1];
+          };
+          delete obj[name];
+          var urlte = urlArr[0] +'?'+ JSON.stringify(obj).replace(/[\"\{\}]/g,"").replace(/\:/g,"=").replace(/\,/g,"&");
+          return urlte;
+      }else{
+          return url;
+      };
+    },
+    // 获取用户此课程的详情
+    getDetail() {
+      learnerCourseDetail(this.courseId).then(res => {
+        this.courseDetail = res;
+        if(this.$isWx){
+          let info = {
+            title:this.courseDetail.name,// 分享标题
+            desc:'听完觉得确实不错,忍不住要推荐~',// 分享描述
+            link: `${window.location.href}`, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
+            imgUrl: this.courseDetail.thumb, // 分享图标
+          }
+          if(this.$route.query&&this.$route.query.code){
+            let newUrl = this.urlDelP(window.location.href,'code')
+            info.link = newUrl.includes('?')?`${newUrl}&code=2`:`${newUrl}?code=2`
+          }else{
+            info.link = window.location.href.includes('?')?`${window.location.href}&code=2`:`${window.location.href}?code=2`
+          }
+          setWxConfig(info);
+        }
+        if (
+          this.courseDetail.buy &&
+          this.$route.query &&
+          this.$route.query.code &&
+          this.$route.query.code != 2 &&
+          !this.giveCode
+        ) {
+          this.$toast.fail("您已经购买课程,无需再次购买");
+          return;
+        }
+        if (!this.courseDetail.enable) {
+          this.canGive2 = false;
+          this.$toast.fail("课程已下架");
+          return;
+        }
+        if (
+          !this.courseDetail.buy &&
+          this.$route.query &&
+          this.$route.query.code &&
+          this.$route.query.code != 2 &&
+          this.courseDetail.enable &&
+          !this.giveCode
+        ) {
+          this.getCodeDetail();
+        }
+      });
+    }
+  },
+  computed: {}
+};
+</script>
+<style scoped lang="scss">
+@import url("../utils/navBar.scss");
+* {
+  margin: 0;
+  padding: 0;
+}
+img {
+  display: block;
+}
+.page {
+  // background-color: #fff;
+  box-sizing: border-box;
+  .courseContent {
+    // padding: 0 0.2rem;
+    // margin-top: 0.3rem;
+    position: relative;
+    .previewImg {
+      // border-radius: 0.1rem;
+      overflow: hidden;
+      img {
+        width: 100%;
+        // height: 4rem;
+        overflow: hidden;
+        display: block;
+      }
+    }
+    .title {
+      padding: 0 0.2rem 0.2rem;
+      background-color: #fff;
+      margin-bottom: 0.2rem;
+      span {
+        font-size: 0.35rem;
+        font-weight: 600;
+        color: red;
+        line-height: 0.8rem;
+      }
+      p {
+        font-size: 0.32rem;
+        font-weight: 600;
+        color: #000;
+        line-height: 0.4rem;
+        margin-bottom: 0.2rem;
+        /* white-space: pre-wrap; */
+        /* overflow: hidden; */
+        /* text-overflow: ellipsis; */
+        /* white-space: nowrap; */
+        /* word-break: break-all; */
+        width: 100%;
+        word-wrap: break-word;
+      }
+      i {
+        font-size: 0.22rem;
+        color: #888;
+        line-height: 0.3rem;
+        font-style: normal;
+      }
+    }
+    .tabs {
+      height: calc(100vh - 0.92rem);
+      position: relative;
+      .toTop {
+        width: 1rem;
+        height: 1rem;
+        background-color: #ccc;
+        border-radius: 50%;
+        overflow: hidden;
+        text-align: center;
+        position: absolute;
+        right: 0.4rem;
+        bottom: 0.4rem;
+        z-index: 999;
+        span {
+          font-size: 0.48rem;
+          color: #fff;
+          line-height: 1rem;
+        }
+      }
+      .images {
+        // margin-top: 0.1rem;
+        img {
+          width: 100%;
+        }
+      }
+      .catelog {
+        background: #fff;
+        padding: 0.2rem;
+        margin-top: 1px;
+        border-top: 1px solid #efefef;
+        position: relative;
+        .sup {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          span {
+            font-size: 0.24rem;
+            color: #666;
+            line-height: 3;
+            margin-left: 0.1rem;
+          }
+        }
+        .logConetent {
+          .logLi {
+            border: 1px solid #efefef;
+            border-radius: 0.1rem;
+            padding: 0 0.2rem;
+            margin-bottom: 0.15rem;
+            p {
+              padding: 0.2rem 0;
+              font-size: 0.3rem;
+              color: #000;
+              line-height: 1.3;
+              // line-height: 3;
+              // overflow: hidden;
+              // text-overflow: ellipsis;
+              // white-space: nowrap;
+              // word-break: break-all;
+            }
+          }
+        }
+      }
+    }
+  }
+  .getCourse {
+    position: absolute;
+    bottom: 0.1rem;
+    left: 0.1rem;
+    width: calc(100% - 0.2rem);
+    .getBtn {
+      width: 100%;
+      background-color: #26a2ff;
+      color: #fff;
+      // animation: getFire 3s infinite linear;
+      border-radius: 0.1rem;
+    }
+  }
+}
+@keyframes getFire {
+  0% {
+    transform: scale(0.95);
+  }
+  100% {
+    transform: scale(1.05);
+  }
+}
+</style>

+ 403 - 0
src/view/course/user/deal.vue

@@ -0,0 +1,403 @@
+<template>
+  <div class="deal-x">
+    <van-nav-bar
+      :title="title"
+      left-text="返回"
+      left-arrow
+      @click-left="onClickLeft"
+    ></van-nav-bar>
+    <div class="userInfo">
+      <van-row
+        type="flex"
+        class="imageName"
+        justify="space-between"
+        align="center"
+      >
+        <div class="userImage">
+          <userImage
+            class="about-me__avatar"
+            :img_url="user_info.imgUrl"
+            :user_name="user_info.name"
+            width="1.12rem"
+            height="1.12rem"
+            v-if="user_info.imgUrl"
+          ></userImage>
+          <div style="width: 1.12rem;height: 1.12rem;background: #26A2FF;border-radius: 50%;overflow: hidden;display: flex;justify-content: center;align-items: center;" v-else>
+            <img :src="defaultImgUrl" style="width: 80%;height: 80%;">
+            <!-- <userImage
+              class="about-me__avatar"
+              :img_url="defaultImgUrl"
+              user_name="用户"
+              width="1.12rem"
+              height="1.12rem"
+            ></userImage> -->
+          </div>
+          <div class="info">
+            <span
+              >{{ user_info.name
+              }}<van-icon
+                name="notes-o"
+                color="#E1B98B"
+                style="margin-left: .1rem;"
+            /></span>
+            <p v-if="user_info.mobile != ''">手机:{{ user_info.mobile }}</p>
+          </div>
+        </div>
+        <div class="user_leave" @click="dealCourseNum">
+          <span>交易课程名额</span>
+        </div>
+      </van-row>
+    </div>
+    <div class="user_tabs">
+      <van-tabs
+        v-model="active"
+        @click="activeChange"
+        animated
+        title-active-color="#26A2FF"
+      >
+        <van-tab
+          v-for="(item, index) in activeList"
+          :key="index"
+          :title="item"
+        ></van-tab>
+      </van-tabs>
+    </div>
+    <div class="dealScroll">
+      <scroller
+        ref="courseScroller"
+        :on-infinite="getMoreList"
+        :list="courseList"
+        noDataText="没有更多..."
+        v-show="active == 0"
+      >
+        <div class="dealList">
+          <courseList :dataList="courseList" :listType="2"></courseList>
+        </div>
+      </scroller>
+      <scroller
+        ref="recordScroller"
+        :on-infinite="getMoreList"
+        noDataText="没有更多..."
+        :list="recordList"
+        v-show="active == 1"
+      >
+        <div class="dealRecordList" v-show="active == 1">
+          <div
+            class="recordLi"
+            v-for="(item, index) in recordList"
+            :key="index"
+          >
+            <div class="flex-name-num">
+              <p>{{ item.subjectName }}</p>
+              <span :style="{color:item.toUserId == target_user_info.id ?'#26A2FF':'#eb6f6f'}"
+                >{{ item.toUserId == target_user_info.id ? "收到" : "转出"
+                }}{{ item.amount }}套</span
+              >
+            </div>
+            <p>{{ item.content }}</p>
+            <span>{{ item.createTime }}</span>
+          </div>
+        </div>
+        <van-divider
+          v-if="recordList.length != 0 && recordList.length == page1.total"
+          style="line-height: .6rem;"
+          >没有更多了...</van-divider
+        >
+        <noData :list="recordList" />
+      </scroller>
+    </div>
+  </div>
+</template>
+
+<script>
+import Vue from "vue";
+import { Tab, Tabs } from "vant";
+import courseList from "../components/courseList";
+import { getDealerRecord } from "../api";
+import {setWxConfig} from '../utils'
+
+Vue.use(Tab);
+Vue.use(Tabs);
+export default {
+  name: "deal",
+  components: { courseList },
+  data() {
+    return {
+      defaultImgUrl:require('../../../assets/images/courseUser.png'),
+      title: "交易",
+      activeList: ["待确认接收的名额", "已确认接收的名额"],
+      active: 0,
+      noDate: false,
+      noDate1: false,
+      page: {
+        cur: 1,
+        size: 10,
+        total: 0
+      },
+      page1: {
+        cur: 1,
+        size: 15,
+        total: 0
+      },
+      user_info: {
+        imgUrl: "",
+        id: "",
+        name: "",
+        mobile: ""
+      },
+      target_user_info: JSON.parse(localStorage.getItem("wx_user_info")),
+      courseList: [],
+      recordList: []
+    };
+  },
+  activated(){
+    this.init();
+    if(this.$isWx){
+      setWxConfig();
+    }
+  },
+  deactivated(){
+    this.resetList();
+  },
+  created() {
+    // this.init();
+  },
+  methods: {
+    // 初始化
+    init() {
+      this.user_info = this.$route.query;
+      this.getList();
+      this.getRecordList();
+    },
+    // 初始化数据
+    resetList() {
+      this.active = 0;
+      this.page.cur = 1;
+      this.page.total = 0;
+      this.page1.cur = 1;
+      this.page1.total = 0;
+      this.noDate = false;
+      this.noDate1 = false;
+      this.courseList = [];
+      this.recordList = [];
+    },
+    // 触底加载
+    getMoreList(done) {
+      if (this.active == 0) {
+        if (!this.noDate) {
+          setTimeout(() => {
+            this.getList(done);
+          }, 300);
+        } else {
+          this.$refs.courseScroller.finishInfinite(true);
+        }
+      } else {
+        if (!this.noDate1) {
+          setTimeout(() => {
+            this.getRecordList(done);
+          }, 300);
+        } else {
+          this.$refs.recordScroller.finishInfinite(true);
+        }
+      }
+    },
+    // 获取待确认的交易列表
+    getList(done) {
+      let data = {
+        page: this.page.cur,
+        pageSize: this.page.size,
+        status: 1
+      };
+      getDealerRecord(this.$route.params.id, data).then(res => {
+        res.list.forEach(item => {
+          item.dealAmount = item.amount;
+          item.subjectThumb = item.thumb;
+          item.subjectPrice = item.price;
+          delete item.amount;
+          delete item.thumb;
+          delete item.price;
+        });
+        this.courseList = this.courseList.concat(res.list);
+        this.page.cur = res.current;
+        this.page.total = res.total;
+        if (res.pages == this.page.cur || res.pages == 0) {
+          if (done) done(true);
+          this.noDate = true;
+        } else {
+          if (done) done();
+          this.page.cur++; //下拉一次页数+1
+          this.noDate = false;
+        }
+      });
+    },
+    // 获取已交易的列表
+    getRecordList(done) {
+      let data = {
+        page: this.page1.cur,
+        pageSize: this.page1.size,
+        status: 2
+      };
+      getDealerRecord(this.$route.params.id, data).then(res => {
+        this.page1.cur = res.current;
+        this.page1.total = res.total;
+        this.recordList = this.recordList.concat(res.list);
+        if (res.pages == this.page1.cur || res.pages == 0) {
+          console.log("没有更多");
+          if (done) done(true);
+          this.noDate1 = true;
+        } else {
+          if (done) done();
+          this.page1.cur++; //下拉一次页数+1
+          this.noDate1 = false;
+        }
+      });
+    },
+    // 确认交易
+    dealCourseNum() {
+      this.$router.push(`/course/dealOrder/${this.$route.params.id}`);
+    },
+    // 标签切换
+    activeChange(e) {
+      this.active = e;
+    },
+    //导航左侧返回
+    onClickLeft() {
+      if(window.history.length>1){
+        this.$router.go(-1);
+      }else{
+        this.$router.replace('/courseHome')
+      }
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+@import url('../utils/navBar.scss');
+* {
+  margin: 0;
+  padding: 0;
+}
+.deal-x {
+  background-color: #efefef;
+  .userInfo {
+    padding: 0.24rem 0.32rem;
+    .userImage {
+      display: flex;
+      align-items: center;
+      flex: 1;
+      .info {
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        margin-left: 0.2rem;
+        span {
+          font-size: 0.32rem;
+          font-weight: 600;
+          color: #000;
+          line-height: 2;
+          display: block;
+        }
+        p {
+          font-size: 0.22rem;
+          color: #222;
+          line-height: 1;
+          display: block;
+        }
+      }
+    }
+    .user_leave {
+      padding: 0.15rem 0.3rem;
+      font-size: 0.26rem;
+      font-weight: 550;
+      color: #26A2FF;
+      border: 1px solid #26A2FF;
+      border-radius: 0.1rem;
+      line-height: 1.5;
+      margin-left: .2rem;
+    }
+  }
+  .user_tabs {
+    margin: 0 0.2rem;
+    border-radius: 0.1rem;
+    position: relative;
+    overflow: hidden;
+    &::after {
+      content: "";
+      width: 1px;
+      height: 60%;
+      position: absolute;
+      left: 50%;
+      top: 20%;
+      background-color: #898989;
+    }
+  }
+  .dealScroll {
+    height: calc(100vh - 3.5rem) !important;
+    padding: 0 0.2rem;
+    position: relative;
+    &::after {
+      content: "";
+      width: calc(100% - 0.2rem);
+      height: 1px;
+      position: absolute;
+      top: 0;
+      left: 0.1rem;
+      background-color: #efefef;
+    }
+    .dealList {
+      padding: 0.15rem 0.2rem 0;
+      border-radius: 0.1rem;
+    }
+    .dealRecordList {
+      padding: 0 0.2rem;
+      border-radius: 0.1rem;
+      margin-top: 0.1rem;
+      .recordLi {
+        background: #fff;
+        padding: 0 0.2rem;
+        overflow: hidden;
+        &:not(:nth-last-child(1)) {
+          border-bottom: 1px solid #efefef;
+        }
+        &:first-child {
+          border-radius: 0.1rem 0.1rem 0 0;
+        }
+        &:last-child {
+          border-radius: 0 0 0.1rem 0.1rem;
+        }
+        .flex-name-num {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          padding-top: 0.1rem;
+          & > p {
+            font-size: 0.32rem;
+            color: #000;
+            line-height: 1.5;
+            flex: 1;
+          }
+          & > span {
+            font-size: 0.28rem;
+            color: #000;
+            line-height: 2;
+            margin-left: 0.1rem;
+          }
+        }
+        & > p {
+          font-size: 0.28rem;
+          color: #666;
+          line-height: 1.3;
+        }
+        & > span {
+          font-size: 0.28rem;
+          color: #666;
+          line-height: 1;
+          display: block;
+          margin-top: 0.2rem;
+          margin-bottom: 0.1rem;
+        }
+      }
+    }
+  }
+}
+</style>

+ 208 - 0
src/view/course/user/login.vue

@@ -0,0 +1,208 @@
+<template>
+  <div class="page">
+    <van-nav-bar title="经销商手机号绑定"></van-nav-bar>
+    <div class="buibOuter">
+      <div class="bindContent">
+        <div class="tit">
+          <p>请完善用户信息</p>
+        </div>
+        <van-form>
+          <van-cell-group>
+            <van-field
+              v-model="form.name"
+              :rules="[{ required: true}]"
+              placeholder="请输入用户名"
+            />
+          </van-cell-group>
+          <van-cell-group>
+            <van-field
+              v-model="form.mobile"
+              name="pattern"
+              :rules="[{ pattern}]"
+              placeholder="请输入手机号"
+            />
+          </van-cell-group>
+          <van-cell-group>
+            <van-field
+              v-model="form.code"
+              center
+              clearable
+              :rules="[{ required: true}]"
+              placeholder="请输入短信验证码"
+            >
+              <template #button>
+                <van-button
+                  size="small"
+                  :loading="sendMsgLoading"
+                  style="width: 2rem;"
+                  :disabled="sended"
+                  @click="getYzm()"
+                  >{{ sendMsgText }}</van-button
+                >
+              </template>
+            </van-field>
+          </van-cell-group>
+          <div style="margin: 16px;">
+            <van-button block type="info" @click="onSubmit">提交</van-button>
+          </div>
+        </van-form>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { returnJSEncrypt1 } from "@/utils/auth";
+import { getMobileYzm,getUSerInfo } from "../api";
+import { addDealer } from "../api";
+import { setWxConfig } from "../utils";
+export default {
+  name: "courseLogin",
+  components: {},
+  props: [],
+  data() {
+    return {
+      pid: null,
+      sendMsgText: "获取验证码",
+      sended: false,
+      countdown: 60,
+      form: {
+        name: "",
+        mobile: "",
+        code: ""
+      },
+      sendMsgLoading: false,
+      pattern: /^(?:(?:\+|00)86)?1[3-9]\d{9}$/,
+      partternY: /\d{6}/
+    };
+  },
+  activated(){
+    this.init();
+    if(this.$isWx){
+      setWxConfig();
+    }
+  },
+  created() {
+    // this.init();
+  },
+  methods: {
+    // 初始化
+    init() {
+      if (this.$route.query && this.$route.query.pid) {
+        this.pid = this.$route.query.pid;
+      }
+      if(JSON.parse(localStorage.getItem("wx_user_info")).marketable){
+        this.$router.push('/courseHome')
+      }
+    },
+    // 手机号校验
+    checkMobile(sMobile) {
+      if (!/^1\d{10}$/.test(sMobile)) {
+        return false;
+      } else {
+        return true;
+      }
+    },
+    // 获取验证码
+    getYzm() {
+      if (!this.checkMobile(this.form.mobile)) {
+        this.$toast.fail("请输入正确的手机号");
+        return false;
+      }
+      let data = { mobile: this.form.mobile.toString(), type: 1 };
+      this.sendMsgLoading = true;
+      getMobileYzm({ data: returnJSEncrypt1(data) })
+        .then(res => {
+          this.sended = true;
+          this.countDownInit();
+          this.$toast.success("已经发送,请注意查收!");
+        })
+        .finally(() => {
+          this.sendMsgLoading = false;
+        });
+    },
+    // 验证码发送倒计时
+    countDownInit() {
+      let self = this;
+      self.sendMsgText = "已发送(" + self.countdown + ")";
+      if (self.countdown == 0) {
+        self.countdown = 60;
+        self.sendMsgText = "重新发送";
+        self.sended = false;
+        return false;
+      } else {
+        setTimeout(function() {
+          self.countdown--;
+          self.countDownInit();
+        }, 1000);
+      }
+    },
+    // 注册经销商提交
+    onSubmit() {
+      if (this.form.name && this.checkMobile(this.form.mobile) && this.form.code) {
+        let data = {
+          name: this.form.name,
+          mobile: this.form.mobile,
+          code: this.form.code
+        };
+        if (this.pid != null&&this.pid!=0) {
+          data.pid = this.pid;
+        }
+        addDealer(data).then(res => {
+          this.$toast.success("注册经销商成功");
+          localStorage.removeItem('wx_user_info')
+          setTimeout(() => {
+            this.$router.replace("/courseHome");
+          }, 1000);
+        });
+      } else {
+        this.$toast.fail("请先将信息填写完整在提交");
+      }
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+@import url('../utils/navBar.scss');
+* {
+  margin: 0;
+  padding: 0;
+}
+img {
+  display: block;
+}
+.page {
+  background: url(~@/assets/images/courseLogin.png) no-repeat;
+  background-size: 100% 100%;
+  .buibOuter {
+    width: 100%;
+    height: calc(100vh - 0.92rem);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    .bindContent {
+      width: 92%;
+      overflow: hidden;
+      border-radius: 0.15rem;
+      background: #fff;
+      margin: 0 auto;
+      padding: 0.5rem 0.3rem;
+      box-sizing: border-box;
+      .tit {
+        display: flex;
+        justify-content: center;
+        p {
+          font-size: 0.32rem;
+          font-weight: 600;
+          line-height: 0.32rem;
+          margin-bottom: 0.5rem;
+        }
+      }
+    }
+  }
+}
+/deep/ .van-field__control {
+  font-size: 0.28rem;
+  line-height: 0.9rem;
+}
+</style>

+ 160 - 0
src/view/course/user/team.vue

@@ -0,0 +1,160 @@
+<template>
+  <div class="team-x">
+    <van-nav-bar
+      class="left-text-bold"
+      :title="title"
+      left-text="返回"
+      left-arrow
+      @click-left="onClickLeft"
+    ></van-nav-bar>
+    <div class="teamContent">
+      <scroller 
+      :isInitRefresh="false" 
+      ref="recordScroller"
+      :list="teamList"
+      noDataText="没有更多..."
+      :on-infinite="getMoreList">
+        <Team
+          :teamType="type"
+          :teamList="teamList"
+          :count="page.total"
+          @search="search"
+        ></Team>
+      </scroller>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getDealerTeam, getDealerPerson } from "../api";
+import Team from "../components/CourseTeam";
+import {setWxConfig} from '../utils'
+import {setDocumentTitle} from '../../../components/vueHashCalendar/utils/util'
+export default {
+  name: "courseTeam",
+  components: { Team },
+  data() {
+    return {
+      canReq: true,
+      noDate: false,
+      type: this.$route.params.id,//1 or 2
+      page: {
+        cur: 1,
+        size: 10,
+        total: 0
+      },
+      teamList: [],
+      keyword: ""
+    };
+  },
+  computed: {
+    title() {
+      return this.type == 1 ? "我的团队" : "近30天交易";
+    }
+  },
+  created() {
+    
+  },
+  activated(){
+    this.init();
+    if(this.$isWx){
+      setWxConfig();
+    }
+  },
+  methods: {
+    debouce(callback,time){
+      let timer;
+      return ()=>{
+        clearTimeout(timer)
+        timer = setTimeout(()=>{
+          callback()
+        },time)
+      }
+    },
+    // 触底加载
+    getMoreList(done) {
+      console.log("到底了");
+      if (!this.noDate) {
+        setTimeout(() => {
+          this.getList(done);
+        }, 300);
+      } else {
+        this.$refs.recordScroller.finishInfinite(true);
+      }
+    },
+    // 初始化
+    init() {
+      this.type = this.$route.params.id;
+      if(this.type == 1){
+        setDocumentTitle('我的团队')
+      }else if(this.type == 2){
+        setDocumentTitle('近30天交易')
+      }
+      this.getList();
+    },
+    //导航左侧返回
+    onClickLeft() {
+      if(window.history.length>1){
+        this.$router.go(-1);
+      }else{
+        this.$router.replace('/courseHome')
+      }
+    },
+    // 获取团队列表
+    getList(done) {
+      let data = {
+        page: this.page.cur,
+        pageSize: this.page.size,
+        keyword: this.keyword
+      };
+      if (this.type==1) {
+        getDealerTeam(data).then(res => {
+          this.teamList = this.teamList.concat(res.list);
+          this.page.total = res.total;
+          this.page.cur = res.current;
+          if (res.pages == res.current || res.pages == 0) {
+            console.log("已无更多");
+            if (done) done(true);
+            this.noDate = true;
+          } else {
+            console.log("更多...");
+            if (done) done();
+            this.page.cur++; //下拉一次页数+1
+            this.noDate = false;
+          }
+        });
+      } else if(this.type==2) {
+        getDealerPerson(data).then(res => {
+          this.teamList = res.list;
+          this.page.total = res.total;
+          this.page.cur = res.current;
+          if (res.pages == res.current || res.pages == 0) {
+            if (done) done(true);
+            this.noDate = true;
+          } else {
+            if (done) done();
+            this.page.cur++; //下拉一次页数+1
+            this.noDate = false;
+          }
+        });
+      }
+    },
+    // 搜索
+    search(val) {
+      this.keyword = val;
+      this.page.cur = 1;
+      this.teamList = []
+      this.getList();
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+@import url('../utils/navBar.scss');
+.team-x {
+  .teamContent {
+    height: calc(100vh - 0.92rem);
+    position: relative;
+  }
+}
+</style>

+ 155 - 0
src/view/course/user/wxAuth.vue

@@ -0,0 +1,155 @@
+<template>
+  <div class="page">
+    <template v-if="isWx">
+      <div class="wxTop">
+      <van-image class="logo" :src="logo" type="contain" />
+    </div>
+    <div class="center">
+      <p>申请获取以下权限</p>
+      <span>获取您的公开信息(昵称、头像等)</span>
+      <button class="btn" @click="init"
+        >微信授权</button>
+    </div>
+    </template>
+    <template v-else>
+      <div class="center"  style="width: 80%;position: absolute;top: 10%;left: 50%;transform: translateX(-50%);">
+        <van-loading size="24px" style="margin-bottom: 0.3rem;display: flex;flex-direction: column;justify-content: center;align-items: center;">请在手机微信打开...</van-loading>
+      </div>
+    </template>
+  </div>
+</template>
+
+<script>
+import { getWxApiToken, getUSerInfo, getCourseCodeDetail } from "../api";
+import { isWxEnv } from "../utils";
+import { mapState, mapGetters } from "vuex";
+export default {
+  name: "wxAuth",
+  components: {},
+  props: [],
+  data() {
+    return {
+      isWx:false,
+      pid: null,
+      code: null,
+      logo: require("../../../../static/images/course_logo.png")
+    };
+  },
+  activated(){
+    this.init();
+  },
+  created() {
+    // this.init();
+  },
+  computed: {
+    ...mapGetters(["wxid"])
+  },
+  methods: {
+    // 根据wxid获取微信个人数据
+    getUerInfo(wxid) {
+      console.log('测试用,正式删除')
+      getWxApiToken(wxid).then(token => {
+        getUSerInfo(token).then(res => {
+          this.user_info = JSON.parse(localStorage.getItem("wx_user_info"));
+          if (
+            this.$route.query &&
+            this.$route.query.pid &&
+            !this.user_info.marketable
+          ) {
+            localStorage.setItem("pid", this.$route.query.pid);
+            this.$router.replace(`/courseLogin?pid=${this.$route.query.pid}`);
+          } else if (this.$route.query && this.$route.query.code) {
+            let codeArr = this.$route.query.code.split("-");
+            this.$router.replace(
+              `/course/courseDeail/${codeArr[1]}?code=${codeArr[0]}`
+            );
+          } else {
+            this.$router.replace(`/courseHome`);
+          }
+        });
+      });
+    },
+    // 微信环境判断
+    wxAuth(type, data) {
+      isWxEnv(type, data)
+        .then(() => {
+          this.isWx = true;
+          this.$router.replace(`/courseHome`);
+        })
+        .catch((e) => {
+          if(e == 1){
+            this.isWx = true;
+          }else{
+            this.isWx = false;
+            // this.getUerInfo(this.wxid);
+          }
+        });
+    },
+    //初始化判断
+    init() {
+      if (this.$route.query && this.$route.query.pid) {
+        this.wxAuth("pid", this.$route.query.pid);
+      } else if (this.$route.query && this.$route.query.code) {
+        this.wxAuth("code", this.$route.query.code);
+      } else {
+        this.wxAuth();
+      }
+      // this.$dialog
+      //   .confirm({
+      //     title: "提示",
+      //     message: "本程序需要提供您的用户信息"
+      //   })
+      //   .then(() => {
+          
+      //   })
+      //   .catch(() => {});
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+*{
+  margin: 0;
+  padding: 0;
+}
+.page {
+  box-sizing: border-box;
+  padding: 0 0.4rem;
+  .wxTop {
+    padding: 1rem 0;
+    border-bottom: 1px solid #ddd;
+    .logo {
+      border-radius: 0.2rem;
+      overflow: hidden;
+      display: block;
+      width: 50%;
+      margin: 0 auto;
+    }
+  }
+  .center {
+    padding-top: .5rem;
+    p{
+      font-size: .28rem;
+      margin-bottom: .3rem
+    }
+    span{
+      font-size: .26rem;
+      color: #888;
+      display: block;
+      margin-bottom: 0.5rem;
+    }
+    .btn{
+      margin: 0 auto;
+      width: 90%;
+      display: block;
+      border-radius: 0.4rem;
+      background-color: #26A2FF;
+      color: #fff;
+      font-size: .32rem;
+      line-height: .8rem;
+      border: 0;
+      outline: none;
+    }
+  }
+}
+</style>

+ 591 - 0
src/view/course/user_qr2img_next.vue

@@ -0,0 +1,591 @@
+<template>
+    <div class="curPage">
+      <div class="userInfo">
+        <van-row
+          type="flex"
+          class="imageName"
+          justify="space-between"
+          align="center"
+        >
+          <div class="userImage">
+            <userImage
+              class="about-me__avatar"
+              :img_url="user_info.imgUrl"
+              :user_name="user_info.name"
+              width="1.12rem"
+              height="1.12rem"
+              v-if="user_info.imgUrl"
+            ></userImage>
+            <div style="background: #26A2FF;border-radius: 50%;overflow: hidden;" v-else>
+              <userImage
+                class="about-me__avatar"
+                :img_url="defaultImgUrl"
+                user_name="用户"
+                width="1.12rem"
+                height="1.12rem"
+              ></userImage>
+            </div>
+            <div class="info">
+              <span
+                >{{ user_info.name ? user_info.name : "新用户"
+                }}<van-icon
+                  name="notes-o"
+                  color="#E1B98B"
+                  style="margin-left: .1rem;"
+              /></span>
+              <!-- <p>手机:{{ user_info.tel }}</p> -->
+              <!-- <p
+                class="userId"
+                :aria-label="user_info.id"
+                @click="copyLink('.userId')"
+              >
+                <i class="courseIcon icon-fuzhi"></i>复制身份ID
+              </p> -->
+            </div>
+          </div>
+          <div class="user_leave">
+            <van-icon name="gem-o" color="#a66666" />
+            {{ user_info.marketable ? "经销商" : "学员" }}
+          </div>
+        </van-row>
+      </div>
+      <div class="user_tabs" v-if="user_info.marketable">
+        <div class="tabs_content">
+          <div class="tabsLi" @click="toUrl('/courseTeam/1')">
+            <van-image
+              src="static/images/course_team.png"
+              style="width: .8rem;height: .8rem;"
+              type="contain"
+            />
+            <span>我的团队</span>
+          </div>
+          <div class="tabsLi" @click="qropen">
+            <van-image
+              src="static/images/course_ewm.png"
+              style="width: .8rem;height: .8rem;"
+              type="contain"
+            />
+            <span>邀请二维码</span>
+          </div>
+          <div class="tabsLi" @click="toUrl('/courseTeam/2')">
+            <van-image
+              src="static/images/course_dingdan.png"
+              style="width: .8rem;height: .8rem;"
+              type="contain"
+            />
+            <span>交易往来</span>
+          </div>
+        </div>
+      </div>
+      <div class="user_course_tabs" v-if='user_info.marketable'>
+        <van-tabs v-model="tbsIndex" style="width: 60%;">
+          <van-tab title="我的推广"></van-tab>
+          <van-tab title="我的学习"></van-tab>
+        </van-tabs>
+        <!-- <div class="tbsL" v-if='user_info.marketable'>
+          <div class="tbsi" :class="{active:tbsIndex==0}" @click="selectTbs(0)">我的推广</div>
+          <div class="tbsi" :class="{active:tbsIndex==1}" @click="selectTbs(1)">我的学习</div>
+        </div> -->
+        <div class="tbsR" v-if="user_info.marketable" @click="toMoreUrl">
+          <span>名额变动明细<van-icon name="arrow" /></span>
+        </div>
+      </div>
+      <!-- <van-search
+        v-model="wxId"
+        placeholder="请输入wxid替换当前账号"
+        show-action
+        style="margin: 0.1rem 0.2rem 0;border-radius: 0.1rem;"
+        @search="changeUSer"
+      /> -->
+      <div
+        class="courScroll"
+        :style="{
+          height: user_info.marketable
+            ? 'calc(100vh - 4.38rem) !important'
+            : 'calc(-2.05rem + 100vh) !important'
+        }"
+      >
+        <scroller ref="scroller" :isInitRefresh="false">
+          <van-loading
+            v-show="showLoad"
+            style="margin: 0px auto;position: relative;left: 50%;transform: translateX(-0.25rem);"
+          />
+          <div
+            class="myCourseList"
+            v-if="user_info.marketable && tbsIndex == 0 && !showLoad"
+          >
+            <courseList
+              :dataList="courseClass.proCourse.courseList"
+              :showNum="1"
+              :fixedTitle="courseClass.proCourse.title"
+            ></courseList>
+          </div>
+          <div class="myCourseList" v-if="tbsIndex == 1 && !showLoad">
+            <courseList
+              :dataList="courseClass.learnCourse.courseList"
+              :fixedTitle="courseClass.learnCourse.title"
+              isNoAd
+            ></courseList>
+          </div>
+        </scroller>
+      </div>
+      <van-overlay :show="qrVisible" @click="qrVisible = false">
+        <div class="wrapper">
+          <div class="qrContent">
+            <div class="tit">
+              邀请二维码
+            </div>
+            <div class="canvasImg" ref="canvasImg" v-if="imgEwmUrl == ''">
+              <div class="qrcode-wrap" ref="qrCodeUrl"></div>
+              <div class="btm">
+                <p>邀请朋友成为经销商,并加入你的团队</p>
+              </div>
+            </div>
+            <img :src="imgEwmUrl" v-else>
+          </div>
+        </div>
+      </van-overlay>
+    </div>
+  </template>
+  
+  <script>
+  import Clipboard from "clipboard";
+  import QRCode from "qrcodejs2";
+  import html2canvas from "html2canvas";
+  import Canvas2Image from "./utils/convas2Images";
+  import courseList from "./components/courseList.vue";
+  import {setDocumentTitle} from '../../components/vueHashCalendar/utils/util'
+  import {isWeChatMobile,isWeChatPC,isWeChat} from './utils'
+  import {
+    getWxApiToken,
+    getUSerInfo,
+    getDealerCourseList,
+    getUserCourseList
+  } from "./api";
+  export default {
+    name: "courseHome",
+    components: {
+      courseList
+    },
+    data() {
+      return {
+        defaultImgUrl:require('../../assets/images/courseUser.png'),
+        showLoad: false,
+        tbsIndex: 0,
+        clipboard: null,
+        qrVisible: false,
+        qrcode: null,
+        qrcodeStatus: false,
+        imgEwmUrl:'',
+        isAndroid: this.$getCache("isAndroid"),
+        user_info: {
+          imgUrl: "",
+          id: "0",
+          name: "用户名",
+          mobile: "0",
+          marketable: false
+        },
+        page: {
+          cur: 1,
+          size: 10,
+          total: 0
+        },
+        courseClass: {
+          proCourse: {
+            title: "我推广的课程",
+            total: 0,
+            courseList: []
+          },
+          learnCourse: {
+            title: "我学习的课程",
+            total: 0,
+            courseList: []
+          }
+        },
+        wxId: "11770"
+      };
+    },
+    created() {
+      this.init();
+      console.log(isWeChat()?isWeChatMobile()?'手机微信':isWeChatPC()?'电脑微信':'无法判断':'不是微信')
+    },
+    watch: {
+      $route(to) {
+        if (to.path == "/courseHome") {
+          this.init();
+        }
+      }
+    },
+    methods: {
+      // 推广/学习标签切换
+      selectTbs(i) {
+        if (this.user_info.marketable) {
+          if (i == 0 && this.tbsIndex != 0) {
+            this.tbsIndex = 0;
+            this.showLoad = true;
+            setTimeout(() => {
+              this.getDealerCourseList();
+            }, 1000);
+          } else if (i == 1 && this.tbsIndex != 1) {
+            this.tbsIndex = 1;
+            this.showLoad = true;
+            setTimeout(() => {
+              this.getUserCourseList();
+            }, 1000);
+          }
+        }
+      },
+      //查看名额变动明细
+      toMoreUrl() {
+        // this.$router.push(`/course/adlist`);
+        this.$router.push(`/course/limitChange`);
+      },
+      // 清楚本地存储/测试用
+      changeUSer() {
+        localStorage.clear();
+        this.getUerInfo(this.wxId);
+      },
+      // 获取指定用户信息/测试用
+      getUerInfo(wxid) {
+        getWxApiToken(wxid).then(token => {
+          getUSerInfo(token).then(res => {
+            this.user_info = JSON.parse(localStorage.getItem("wx_user_info"));
+            if (this.user_info.marketable) {
+              getDealerCourseList();
+            } else if (!this.user_info.marketable) {
+              this.tbsIndex = 1;
+            }
+            getUserCourseList();
+          });
+        });
+      },
+      //获取用户数据
+      init() {
+        setDocumentTitle('首页')
+        this.user_info = JSON.parse(localStorage.getItem("wx_user_info"));
+        if (this.user_info.marketable) {
+          this.getDealerCourseList();
+        } else if (!this.user_info.marketable) {
+          this.tbsIndex = 1;
+        }
+        this.getUserCourseList();
+      },
+      //获取经销推广课程列表
+      getDealerCourseList(done) {
+        getDealerCourseList().then(res => {
+          this.courseClass.proCourse.total = res.total;
+          this.courseClass.proCourse.courseList = res.list;
+          this.showLoad = false;
+          if (done) done();
+        });
+      },
+      //获取用户消费的课程列表
+      getUserCourseList(done) {
+        getUserCourseList().then(res => {
+          this.courseClass.learnCourse.total = res.total;
+          let list = [];
+          res.list.forEach(item => {
+            let data = {
+              subjectName: item.name,
+              subjectId: item.id,
+              subjectPrice: item.price,
+              subjectThumb: item.thumb,
+              subjectEnable: item.enable,
+              sectionsNum: item.sectionsNum
+            };
+            list.push(data);
+          });
+          this.courseClass.learnCourse.courseList = list;
+          this.showLoad = false;
+          if (done) done();
+        });
+      },
+      // 打开二维码
+      qropen() {
+        this.qrVisible = true;
+        this.$nextTick(() => {
+          this.creatQrCode();
+        });
+      },
+      // 创建二维码
+      creatQrCode() {
+        if (!this.qrcodeStatus) {
+          console.log(
+            `${window.location.href.split("#")[0]}#/courseLogin?pid=${
+              JSON.parse(localStorage.getItem("wx_user_info")).id
+            }`
+          );
+          this.qrcode = new QRCode(this.$refs.qrCodeUrl, {
+            text: `${window.location.href.split("#")[0]}#/courseLogin?pid=${
+              JSON.parse(localStorage.getItem("wx_user_info")).id
+            }`, // 需要转换为二维码的内容
+            width: 200,
+            height: 200,
+            colorDark: "#000000",
+            colorLight: "#ffffff",
+            correctLevel: QRCode.CorrectLevel.H
+          });
+          this.qrcodeStatus = true;
+          this.createImg();
+        }
+      },
+      createHDCanvas (w=300,h=150) {
+        let ratio = window.devicePixelRatio || 1;
+        let canvas = document.createElement('canvas');
+        canvas.width = w * ratio; // 实际渲染像素
+        canvas.height = h * ratio; // 实际渲染像素
+        canvas.style.width = `${w}px`; // 控制显示大小
+        canvas.style.height = `${h}px`; // 控制显示大小
+        canvas.getContext('2d').setTransform(ratio, 0, 0, ratio, 0, 0);
+        return canvas;
+      },
+      createImg() {
+        let that = this
+        let opts = {
+          useCORS: true, //支持图片跨域
+          allowTaint: false, //这个属性和useCORS不能同时为true哦
+          logging: false,
+          letterRendering: true,
+        };
+        html2canvas(this.$refs.canvasImg, opts) //传入你想生成图片的dom
+          .then(function (canvas) {
+            // let canvas2 = that.createHDCanvas()
+            let img = Canvas2Image.convertToImage(
+              canvas,
+              canvas.width,
+              canvas.height
+            );
+            img.style.width = "200px";
+            img.style.height = "250px";
+            let url = canvas.toDataURL("image/png"); //得到图片的base64编码数据
+            that.imgEwmUrl = url
+          });
+      },
+      //复制剪切板
+      copyLink(event) {
+        let that = this;
+        //这里是复制目标的类名
+        that.clipboard = new Clipboard(event, {
+          text: function(trigger) {
+            return trigger.getAttribute("aria-label");
+          }
+        });
+        console.log(that.clipboard)
+        that.clipboard.on("success", function(e) {
+          e.clearSelection(); //清除选中的文字的选择状态
+          that.$toast.success("ID复制成功~");
+        });
+  
+        that.clipboard.on("error", function(e) {
+          console.error(e);
+        });
+      },
+      //跳转内页
+      toUrl(url, params) {
+        this.$router.push({
+          path: url
+        });
+      }
+    }
+  };
+  </script>
+  <style scoped lang="scss">
+  @import "../../assets/iconfont.css";
+  * {
+    margin: 0;
+    padding: 0;
+  }
+  img {
+    display: block;
+  }
+  .curPage {
+    height: 100%;
+    position: relative !important;
+    padding-top: 0.4rem;
+    background: #f3f2ee;
+    background: linear-gradient(90deg, #f3f2ee, #e7eff9);
+    .userInfo {
+      padding: 0.24rem 0.32rem 0.12rem;
+      .userImage {
+        display: flex;
+        align-items: center;
+        flex: 1;
+        .info {
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          margin-left: 0.2rem;
+          span {
+            font-size: 0.32rem;
+            font-weight: 600;
+            color: #000;
+            line-height: 2;
+            display: block;
+          }
+          p {
+            font-size: 0.22rem;
+            color: #222;
+            line-height: 1;
+            display: block;
+            i {
+              font-size: 0.22rem;
+              color: #222;
+              line-height: 1;
+            }
+          }
+        }
+      }
+      .user_leave {
+        padding: 0.05rem 0.3rem;
+        font-size: 0.26rem;
+        font-weight: 550;
+        color: #a66666;
+        border: 1px solid #c9c3c0;
+        border-radius: 0.1rem;
+        line-height: 1.5;
+      }
+    }
+    .user_tabs {
+      padding: 0 0.2rem;
+      margin-top: 0.15rem;
+      .tabs_content {
+        box-sizing: border-box;
+        height: 1.5rem;
+        padding: 0.1rem 0;
+        display: flex;
+        justify-content: space-around;
+        border-radius: 0.1rem;
+        background: #fff;
+        .tabsLi {
+          // flex: 1;
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          align-items: center;
+          span {
+            font-size: 0.24rem;
+            color: #333;
+            line-height: 0.3rem;
+          }
+        }
+      }
+    }
+    .user_course_tabs {
+      margin: 0.15rem 0.2rem 0;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      background-color: #fff;
+      border-radius: .1rem;
+      overflow: hidden;
+      .ctbsL {
+        width: 2rem;
+        display: flex;
+        align-items: center;
+      }
+      .tbsL {
+        width: 60%;
+        display: flex;
+        align-items: center;
+        .tbsi {
+          padding: 0 0.15rem;
+          border-radius: 0.25rem;
+          border: 0.02rem solid #999;
+          font-size: 0.24rem;
+          color: #444;
+          line-height: 0.4rem;
+          text-align: center;
+          margin-right: 0.2rem;
+          &.active {
+            border: 1px solid rgb(22, 132, 252);
+            background-color: rgba(38, 162, 255, 0.1);
+            color: rgb(22, 132, 252);
+          }
+        }
+      }
+      .tbsR {
+        display: flex;
+        align-items: center;
+        margin-right: .2rem;
+        span {
+          font-size: 0.24rem;
+          color: #333;
+          line-height: 0.4rem;
+        }
+      }
+    }
+    .courScroll {
+      height: calc(100vh - 2.75rem) !important;
+      position: relative;
+      .cScroll {
+        height: 100%;
+        position: relative !important;
+      }
+      .myCourseList {
+        &:nth-child(2) {
+          padding-bottom: 0.4rem;
+        }
+        padding: 0 0.2rem;
+        // margin-top: 0.2rem;
+      }
+    }
+    .wrapper {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      height: 100vh;
+      .qrContent {
+        width: 70%;
+        border-radius: 0.2rem;
+        overflow: hidden;
+        background-color: #FFF;
+        img{
+          width: 100%;
+        }
+        .canvasImg{
+          width: 100%;
+        }
+        .btm{
+          font-size: .23rem;
+          color: #666;
+          line-height: .6rem;
+          text-align: center;
+          border: 0;
+        }
+        .tit {
+          position: relative;
+          width: 100%;
+          text-align: center;
+          font-size: 0.3rem;
+          color: #333;
+          line-height: 0.8rem;
+          &::after {
+            content: "X";
+            position: absolute;
+            right: 0.2rem;
+            top: 0.2rem;
+            font-size: 0.3rem;
+            line-height: 0.3rem;
+          }
+        }
+        .qrcode-wrap {
+          padding: 0.2rem .2rem 0;
+          background-color: #fff;
+          text-align: center;
+          display: flex;
+          justify-content: center;
+        }
+      }
+    }
+  }
+  /deep/ .van-search .van-cell {
+    padding: 0.1rem 0.16rem 0.1rem 0.16rem;
+  }
+  /deep/ .van-tabs--line .van-tabs__wrap{
+    height: .68rem;
+  }
+  /deep/ .van-tab--active{
+    font-weight: 600;
+  }
+  </style>
+  

+ 266 - 0
src/view/course/utils/convas2Images.js

@@ -0,0 +1,266 @@
+/**
+ * covert canvas to image
+ * and save the image file
+ */
+ 
+var Canvas2Image = function () {
+ 
+	// check if support sth.
+	var $support = function () {
+		var canvas = document.createElement('canvas'),
+			ctx = canvas.getContext('2d');
+ 
+		return {
+			canvas: !!ctx,
+			imageData: !!ctx.getImageData,
+			dataURL: !!canvas.toDataURL,
+			btoa: !!window.btoa
+		};
+	}();
+ 
+	var downloadMime = 'image/octet-stream';
+ 
+	function scaleCanvas (canvas, width, height) {
+		var w = canvas.width,
+			h = canvas.height;
+		if (width == undefined) {
+			width = w;
+		}
+		if (height == undefined) {
+			height = h;
+		}
+ 
+		var retCanvas = document.createElement('canvas');
+		var retCtx = retCanvas.getContext('2d');
+		retCanvas.width = width;
+		retCanvas.height = height;
+		retCtx.drawImage(canvas, 0, 0, w, h, 0, 0, width, height);
+		return retCanvas;
+	}
+ 
+	function getDataURL (canvas, type, width, height) {
+		canvas = scaleCanvas(canvas, width, height);
+		return canvas.toDataURL(type);
+	}
+ 
+	function saveFile (strData) {
+		document.location.href = strData;
+	}
+ 
+	function genImage(strData) {
+		var img = document.createElement('img');
+		img.src = strData;
+		return img;
+	}
+	function fixType (type) {
+		type = type.toLowerCase().replace(/jpg/i, 'jpeg');
+		var r = type.match(/png|jpeg|bmp|gif/)[0];
+		return 'image/' + r;
+	}
+	function encodeData (data) {
+		if (!window.btoa) { throw 'btoa undefined' }
+		var str = '';
+		if (typeof data == 'string') {
+			str = data;
+		} else {
+			for (var i = 0; i < data.length; i ++) {
+				str += String.fromCharCode(data[i]);
+			}
+		}
+ 
+		return btoa(str);
+	}
+	function getImageData (canvas) {
+		var w = canvas.width,
+			h = canvas.height;
+		return canvas.getContext('2d').getImageData(0, 0, w, h);
+	}
+	function makeURI (strData, type) {
+		return 'data:' + type + ';base64,' + strData;
+	}
+ 
+ 
+	/**
+	 * create bitmap image
+	 * 按照规则生成图片响应头和响应体
+	 */
+	var genBitmapImage = function (oData) {
+ 
+		//
+		// BITMAPFILEHEADER: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx
+		// BITMAPINFOHEADER: http://msdn.microsoft.com/en-us/library/dd183376.aspx
+		//
+ 
+		var biWidth  = oData.width;
+		var biHeight	= oData.height;
+		var biSizeImage = biWidth * biHeight * 3;
+		var bfSize  = biSizeImage + 54; // total header size = 54 bytes
+ 
+		//
+		//  typedef struct tagBITMAPFILEHEADER {
+		//  	WORD bfType;
+		//  	DWORD bfSize;
+		//  	WORD bfReserved1;
+		//  	WORD bfReserved2;
+		//  	DWORD bfOffBits;
+		//  } BITMAPFILEHEADER;
+		//
+		var BITMAPFILEHEADER = [
+			// WORD bfType -- The file type signature; must be "BM"
+			0x42, 0x4D,
+			// DWORD bfSize -- The size, in bytes, of the bitmap file
+			bfSize & 0xff, bfSize >> 8 & 0xff, bfSize >> 16 & 0xff, bfSize >> 24 & 0xff,
+			// WORD bfReserved1 -- Reserved; must be zero
+			0, 0,
+			// WORD bfReserved2 -- Reserved; must be zero
+			0, 0,
+			// DWORD bfOffBits -- The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits.
+			54, 0, 0, 0
+		];
+ 
+		//
+		//  typedef struct tagBITMAPINFOHEADER {
+		//  	DWORD biSize;
+		//  	LONG  biWidth;
+		//  	LONG  biHeight;
+		//  	WORD  biPlanes;
+		//  	WORD  biBitCount;
+		//  	DWORD biCompression;
+		//  	DWORD biSizeImage;
+		//  	LONG  biXPelsPerMeter;
+		//  	LONG  biYPelsPerMeter;
+		//  	DWORD biClrUsed;
+		//  	DWORD biClrImportant;
+		//  } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
+		//
+		var BITMAPINFOHEADER = [
+			// DWORD biSize -- The number of bytes required by the structure
+			40, 0, 0, 0,
+			// LONG biWidth -- The width of the bitmap, in pixels
+			biWidth & 0xff, biWidth >> 8 & 0xff, biWidth >> 16 & 0xff, biWidth >> 24 & 0xff,
+			// LONG biHeight -- The height of the bitmap, in pixels
+			biHeight & 0xff, biHeight >> 8  & 0xff, biHeight >> 16 & 0xff, biHeight >> 24 & 0xff,
+			// WORD biPlanes -- The number of planes for the target device. This value must be set to 1
+			1, 0,
+			// WORD biBitCount -- The number of bits-per-pixel, 24 bits-per-pixel -- the bitmap
+			// has a maximum of 2^24 colors (16777216, Truecolor)
+			24, 0,
+			// DWORD biCompression -- The type of compression, BI_RGB (code 0) -- uncompressed
+			0, 0, 0, 0,
+			// DWORD biSizeImage -- The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps
+			biSizeImage & 0xff, biSizeImage >> 8 & 0xff, biSizeImage >> 16 & 0xff, biSizeImage >> 24 & 0xff,
+			// LONG biXPelsPerMeter, unused
+			0,0,0,0,
+			// LONG biYPelsPerMeter, unused
+			0,0,0,0,
+			// DWORD biClrUsed, the number of color indexes of palette, unused
+			0,0,0,0,
+			// DWORD biClrImportant, unused
+			0,0,0,0
+		];
+ 
+		var iPadding = (4 - ((biWidth * 3) % 4)) % 4;
+ 
+		var aImgData = oData.data;
+ 
+		var strPixelData = '';
+		var biWidth4 = biWidth<<2;
+		var y = biHeight;
+		var fromCharCode = String.fromCharCode;
+ 
+		do {
+			var iOffsetY = biWidth4*(y-1);
+			var strPixelRow = '';
+			for (var x = 0; x < biWidth; x++) {
+				var iOffsetX = x<<2;
+				strPixelRow += fromCharCode(aImgData[iOffsetY+iOffsetX+2]) +
+							   fromCharCode(aImgData[iOffsetY+iOffsetX+1]) +
+							   fromCharCode(aImgData[iOffsetY+iOffsetX]);
+			}
+ 
+			for (var c = 0; c < iPadding; c++) {
+				strPixelRow += String.fromCharCode(0);
+			}
+ 
+			strPixelData += strPixelRow;
+		} while (--y);
+ 
+		var strEncoded = encodeData(BITMAPFILEHEADER.concat(BITMAPINFOHEADER)) + encodeData(strPixelData);
+ 
+		return strEncoded;
+	};
+ 
+	/**
+	 * saveAsImage
+	 * @param canvasElement
+	 * @param {String} image type
+	 * @param {Number} [optional] png width
+	 * @param {Number} [optional] png height
+	 */
+	var saveAsImage = function (canvas, width, height, type) {
+		if ($support.canvas && $support.dataURL) {
+			if (typeof canvas == "string") { canvas = document.getElementById(canvas); }
+			if (type == undefined) { type = 'png'; }
+			type = fixType(type);
+			if (/bmp/.test(type)) {
+				var data = getImageData(scaleCanvas(canvas, width, height));
+				var strData = genBitmapImage(data);
+				saveFile(makeURI(strData, downloadMime));
+			} else {
+				var strData = getDataURL(canvas, type, width, height);
+				saveFile(strData.replace(type, downloadMime));
+			}
+		}
+	};
+ 
+	var convertToImage = function (canvas, width, height, type) {
+		if ($support.canvas && $support.dataURL) {
+			if (typeof canvas == "string") { canvas = document.getElementById(canvas); }
+			if (type == undefined) { type = 'png'; }
+			type = fixType(type);
+ 
+			if (/bmp/.test(type)) {
+				var data = getImageData(scaleCanvas(canvas, width, height));
+				var strData = genBitmapImage(data);
+				return genImage(makeURI(strData, 'image/bmp'));
+			} else {
+				var strData = getDataURL(canvas, type, width, height);
+				return genImage(strData);
+			}
+		}
+	};
+ 
+ 
+ 
+	return {
+		saveAsImage: saveAsImage,
+		saveAsPNG: function (canvas, width, height) {
+			return saveAsImage(canvas, width, height, 'png');
+		},
+		saveAsJPEG: function (canvas, width, height) {
+			return saveAsImage(canvas, width, height, 'jpeg');
+		},
+		saveAsGIF: function (canvas, width, height) {
+			return saveAsImage(canvas, width, height, 'gif');
+		},
+		saveAsBMP: function (canvas, width, height) {
+			return saveAsImage(canvas, width, height, 'bmp');
+		},
+ 
+		convertToImage: convertToImage,
+		convertToPNG: function (canvas, width, height) {
+			return convertToImage(canvas, width, height, 'png');
+		},
+		convertToJPEG: function (canvas, width, height) {
+			return convertToImage(canvas, width, height, 'jpeg');
+		},
+		convertToGIF: function (canvas, width, height) {
+			return convertToImage(canvas, width, height, 'gif');
+		},
+		convertToBMP: function (canvas, width, height) {
+			return convertToImage(canvas, width, height, 'bmp');
+		}
+	};
+ 
+}();
+export default Canvas2Image;

+ 152 - 0
src/view/course/utils/index.js

@@ -0,0 +1,152 @@
+import { Toast, Notify } from 'vant'
+import Clipboard from "clipboard";
+import { getWxToken, openError } from "@/utils/auth";
+import { getCache } from '@/utils/auth'
+import { getWxConfigInfo } from '../api'
+import router from '@/router'
+import wx from "weixin-js-sdk";
+//判断环境/登录状态
+export function isWxEnv(type, data) {
+    return new Promise((resolve, reject) => {
+        if (isWeChatMobile()) {
+            if (getWxToken() && localStorage.getItem('wx_user_info')) {
+                Toast("微信环境已授权");
+                resolve()
+            } else {
+                Toast.fail("微信环境未授权");
+                reject(1)
+                doWeixinLogin(type, data);
+            }
+        } else {
+            Toast.fail("请在手机微信中打开浏览");
+            reject(2)
+            // if (getWxToken() && localStorage.getItem('wx_user_info')) {
+            //     resolve()
+            // } else {
+            //     Toast.fail("请在手机微信中打开浏览");
+            //     reject(2)
+            // }
+        }
+    })
+}
+export function isWeChat() {
+    var ua = navigator.userAgent.toLowerCase();
+    return /micromessenger/.test(ua);
+}
+
+export function isWeChatPC() {
+    var ua = navigator.userAgent.toLowerCase();
+    // 你可以根据PC版微信浏览器的特性来添加更多的判断条件  
+    // 例如,某些PC版微信浏览器可能包含特定的关键字或版本信息  
+    return /micromessenger/.test(ua) && /windows/.test(ua) && !/mobile/.test(ua);
+}
+
+export function isWeChatMobile() {
+    var ua = navigator.userAgent.toLowerCase();
+    return /micromessenger/.test(ua) && /mobile/.test(ua);
+}
+
+// if (isWeChat()) {  
+//     if (isWeChatPC()) {  
+//         console.log('这是PC版微信');  
+//     } else if (isWeChatMobile()) {  
+//         console.log('这是手机版微信');  
+//     } else {  
+//         console.log('无法确定是PC版还是手机版微信');  
+//     }  
+// } else {  
+//     console.log('这不是微信浏览器');  
+// }
+//请求微信授权
+export function doWeixinLogin(type, data) {
+    // let defaultUrl = 'https://3g954g5149.picp.vip/wx/mp/auth/wx65f4dde5ec7c31e7?marketing=1'
+    // let dealerUrl = 'https://3g954g5149.picp.vip/wx/mp/auth/wx65f4dde5ec7c31e7?marketing=2&pid='
+    // let timinalUrl = 'https://3g954g5149.picp.vip/wx/mp/auth/wx65f4dde5ec7c31e7?marketing=3&expendCode='
+    let defaultUrl = `${process.env.BASE_API}/wx/mp/auth/wx65f4dde5ec7c31e7?marketing=1`
+    let dealerUrl = `${process.env.BASE_API}/wx/mp/auth/wx65f4dde5ec7c31e7?marketing=2&pid=`
+    let timinalUrl = `${process.env.BASE_API}/wx/mp/auth/wx65f4dde5ec7c31e7?marketing=3&expendCode=`
+    if (getCache("isAndroid")) {
+        if (type == 'pid' && data) {
+            window.open(`${dealerUrl}${data}`)
+        } else if (type == 'code' && data) {
+            window.open(`${timinalUrl}${data}`)
+        } else {
+            window.open(`${defaultUrl}`)
+        }
+    } else {
+        if (type == 'pid' && data) {
+            window.location.href = `${dealerUrl}${data}`;
+        } else if (type == 'code' && data) {
+            window.location.href = `${timinalUrl}${data}`;
+        } else {
+            window.location.href = `${defaultUrl}`;
+        }
+    }
+}
+//复制(event必须为点击元素)
+export function copyLink(event) {
+    let that = this;
+    //这里是复制目标的类名
+    let clipboard = new Clipboard(event, {
+        text: function (trigger) {
+            return trigger.getAttribute("aria-label");
+        }
+    });
+    clipboard.on("success", function (e) {
+        e.clearSelection(); //清除选中的文字的选择状态
+        that.$toast.success("复制成功~");
+    });
+
+    clipboard.on("error", function (e) {
+        console.error(e);
+    });
+}
+export function setWxConfig(shareInfo) {
+    let info
+    if(shareInfo){
+        info = shareInfo
+    }else{
+        info = {
+            title:'功道云知识平台',// 分享标题
+            desc:'听完觉得确实不错,忍不住要推荐~',// 分享描述
+            link: window.location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
+            imgUrl: 'https://oa.g107.com/m/static/images/logo.png', // 分享图标
+        }
+    }
+    console.log(info)
+    let data = {
+        url:window.location.href
+    }
+    getWxConfigInfo(data).then(config => {
+        wx.config({
+            appId: config.appId,
+            timestamp: config.timestamp,
+            nonceStr: config.nonceStr,
+            signature: config.signature,
+            jsApiList: ['updateAppMessageShareData','updateTimelineShareData']
+        })
+        wx.ready(() => {
+            wx.updateAppMessageShareData({
+                title: info.title, // 分享标题
+                desc: info.desc, // 分享描述
+                link: info.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
+                imgUrl: info.imgUrl, // 分享图标
+                success: function () {
+                // 设置成功
+                console.log("分享成功");
+                },
+            });
+            wx.updateTimelineShareData({
+                title: info.title, // 分享标题
+                link: info.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
+                imgUrl: info.imgUrl, // 分享图标
+                success: function () {
+                // 设置成功
+                console.log("分享成功");
+                },
+            });
+        });
+    }).catch(err=>{
+        console.log(err)
+    })
+}

+ 16 - 0
src/view/course/utils/navBar.scss

@@ -0,0 +1,16 @@
+/deep/ .van-nav-bar{
+    background-color:#FFF;
+    border-bottom: 1px solid #efefef;
+}
+/deep/ .van-nav-bar .van-icon{
+    color:#333;
+}
+/deep/ .van-nav-bar__text{
+    color: #333;
+}
+/deep/ .van-nav-bar__title{
+    color: #333;
+}
+/deep/ .van-nav-bar__left span{
+    color: #333!important;
+}

+ 338 - 0
src/view/course/video/courseVideo.vue

@@ -0,0 +1,338 @@
+<template>
+  <div class="page">
+    <van-nav-bar
+      :title="title"
+      left-text="返回"
+      left-arrow
+      @click-left="onClickLeft"
+    ></van-nav-bar>
+    <div class="courseContent">
+      <div class="previewImg">
+        <video
+          ref="vueMiniPlayer"
+          :src="videoSrc"
+          controls
+          autoplay
+          v-if="showVideo"
+          controlsList="nodownload"
+        ></video>
+      </div>
+      <div class="videoTitle">
+        <!-- <span>{{ courseDetail.price }}</span> -->
+        <p>{{ curTitle }}</p>
+        <!-- <i style="margin-right: .1rem;">已更新{{ courseDetail.sections.length }}节课</i>
+        <i>{{ Number(courseDetail.baseClick) + Number(courseDetail.clickNum) }}次浏览</i> -->
+      </div>
+      <div class="tabs">
+        <div v-show="showBack" class="toTop" @click="BackTop">
+          <span><van-icon name="back-top"/></span>
+        </div>
+        <scroller ref="scroller" :on-scrolling="scrollChange">
+          <van-tabs v-model="activeTab" swipeable>
+            <van-tab title="课程介绍">
+              <div class="images">
+                <div
+                  class="descImage"
+                  v-for="(item, index) in courseDetail.images"
+                  :key="index"
+                >
+                  <img :src="item" />
+                </div>
+              </div>
+            </van-tab>
+            <van-tab title="课程目录">
+              <div class="catelog">
+                <div class="logConetent">
+                  <div
+                    class="logLi"
+                    v-for="(item, index) in courseDetail.sections"
+                    :key="index"
+                    @click="toSectionVidio(item, index)"
+                    :class="{ active: item.active }"
+                  >
+                    <p>{{ index + 1 }}、{{ item.name }}</p>
+                  </div>
+                </div>
+              </div>
+            </van-tab>
+          </van-tabs>
+        </scroller>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { learnerCourseDetail, getVideoSrc } from "../api";
+import {setWxConfig} from '../utils'
+export default {
+  name: "video",
+  data() {
+    return {
+      showBack: false,
+      showVideo: true,
+      loading: false,
+      finished: false,
+      activeTab: 1,
+      title: "课程详情",
+      curTitle: "",
+      videoSrc: "",
+      courseDetail: {
+        thumb: "",
+        name: "",
+        images: [],
+        sections: []
+      }
+    };
+  },
+  watch: {
+    videoSrc() {
+      this.showVideo = false;
+      this.$nextTick(() => {
+        this.showVideo = true;
+        this.$nextTick(() => {
+          this.$refs.vueMiniPlayer.play(); //播放
+        });
+      });
+    }
+  },
+  activated(){
+    this.init();
+    if(this.$isWx){
+      setWxConfig();
+    }
+  },
+  created() {
+    // this.init();
+    
+  },
+  methods: {
+    //滚动监控
+    scrollChange(e) {
+      //需要滚动的界面实际长度大于整个页面长度
+      let allH = document.getElementsByClassName("_v-content")[0].offsetHeight + document.getElementsByClassName("van-nav-bar")[0].offsetHeight+document.getElementsByClassName("previewImg")[0].offsetHeight+document.getElementsByClassName("videoTitle")[0].offsetHeight
+      let canShow = allH > document.getElementsByClassName("page")[0].offsetHeight
+      if ( e > 40 && canShow ) {
+        this.showBack = true;
+      } else {
+        this.showBack = false;
+      }
+    },
+    //回到顶部
+    BackTop() {
+      this.$refs.scroller.scrollTo(0, 0, 500);
+    },
+    // 章节切换获取视频地址
+    toSectionVidio(item, i) {
+      this.courseDetail.sections.forEach((item, index) => {
+        item.active = false;
+        if (index == i) {
+          item.active = true;
+        }
+      });
+      let data = {
+        index: i,
+        link: item.link
+      };
+      this.curTitle = this.courseDetail.sections[i].name;
+      sessionStorage.setItem("vd_info", JSON.stringify(data));
+      this.getVideoLink(item.link);
+      // this.videoSrc = this.courseDetail.sections[index].link
+    },
+    // 获取视频地址
+    getVideoLink(link) {
+      let data = {
+        subjectId: this.$route.params.id,
+        link: link
+      };
+      getVideoSrc(data)
+        .then(res => {
+          this.videoSrc = res;
+        })
+        .catch(err => {
+          this.$router.push("/courseError");
+        });
+    },
+    // 返回
+    onClickLeft() {
+      if(window.history.length>1){
+        this.$router.go(-1);
+      }else{
+        this.$router.replace('/courseHome')
+      }
+    },
+    // 初始化
+    init() {
+      this.courseId = this.$route.params.id;
+      this.getVideoLink(JSON.parse(sessionStorage.getItem("vd_info")).link);
+      this.getDetail();
+    },
+    // 获取课程详情
+    getDetail() {
+      learnerCourseDetail(this.courseId).then(res => {
+        this.title = res.name;
+        document.title = res.name;
+        res.sections.forEach((item, index) => {
+          item.active = false;
+        });
+        if (JSON.parse(sessionStorage.getItem("vd_info"))) {
+          res.sections[
+            JSON.parse(sessionStorage.getItem("vd_info")).index
+          ].active = true;
+          this.curTitle =
+            res.sections[
+              JSON.parse(sessionStorage.getItem("vd_info")).index
+            ].name;
+        }
+        this.courseDetail = res;
+      });
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+@import url("../utils/navBar.scss");
+* {
+  margin: 0;
+  padding: 0;
+}
+img {
+  display: block;
+}
+.page {
+  // background-color: #fff;
+  box-sizing: border-box;
+  .courseContent {
+    // padding: 0 0.2rem;
+    // margin-top: 0.3rem;
+    .previewImg {
+      // border-radius: 0.1rem;
+      overflow: hidden;
+      video {
+        width: 100%;
+      }
+    }
+    .videoTitle {
+      padding: 0.2rem;
+      background-color: #fff;
+      margin-bottom: 0.2rem;
+      span {
+        font-size: 0.35rem;
+        font-weight: 600;
+        color: red;
+        line-height: 0.8rem;
+      }
+      p {
+        font-size: 0.32rem;
+        font-weight: 600;
+        color: #000;
+        line-height: 0.4rem;
+        // margin-bottom: .2rem;
+        /* white-space: pre-wrap; */
+        /* overflow: hidden; */
+        /* text-overflow: ellipsis; */
+        /* white-space: nowrap; */
+        /* word-break: break-all; */
+        width: 100%;
+        word-wrap: break-word;
+      }
+      i {
+        font-size: 0.22rem;
+        color: #888;
+        line-height: 0.3rem;
+        font-style: normal;
+      }
+    }
+    .tabs {
+      height: calc(100vh - 6rem);
+      position: relative;
+      .toTop {
+        width: 1rem;
+        height: 1rem;
+        background-color: #ccc;
+        border-radius: 50%;
+        overflow: hidden;
+        text-align: center;
+        position: absolute;
+        right: 0.4rem;
+        bottom: 0.4rem;
+        z-index: 999;
+        span {
+          font-size: 0.48rem;
+          color: #fff;
+          line-height: 1rem;
+        }
+      }
+      .images {
+        // margin-top: 0.1rem;
+        img {
+          width: 100%;
+        }
+      }
+      .catelog {
+        background: #fff;
+        padding: 0.2rem;
+        margin-top: 1px;
+        border-top: 1px solid #efefef;
+        .sup {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          span {
+            font-size: 0.24rem;
+            color: #666;
+            line-height: 3;
+            margin-left: 0.1rem;
+          }
+        }
+        .logConetent {
+          .logLi {
+            border: 1px solid #efefef;
+            border-radius: 0.1rem;
+            padding: 0 0.2rem;
+            margin-bottom: 0.15rem;
+            &.active {
+              box-shadow: 0.02rem 0.08rem #ddd;
+              p {
+                color: #26a2ff;
+              }
+            }
+            p {
+              padding: 0.2rem 0;
+              font-size: 0.3rem;
+              color: #000;
+              line-height: 1.3;
+              // line-height: 3;
+              // overflow: hidden;
+              // text-overflow: ellipsis;
+              // white-space: nowrap;
+              // word-break: break-all;
+            }
+          }
+        }
+      }
+    }
+  }
+  .getCourse {
+    position: absolute;
+    bottom: 0.1rem;
+    left: 0.1rem;
+    width: calc(100% - 0.2rem);
+    .getBtn {
+      width: 100%;
+      background-color: #26a2ff;
+      color: #fff;
+      // animation: getFire 3s infinite linear;
+      border-radius: 0.1rem;
+    }
+  }
+}
+@keyframes getFire {
+  0% {
+    transform: scale(0.95);
+  }
+  100% {
+    transform: scale(1.05);
+  }
+}
+</style>

+ 310 - 0
src/view/course/video/freeVideo.vue

@@ -0,0 +1,310 @@
+<template>
+  <div class="page">
+    <van-nav-bar :title="title" @click-left="onClickLeft">
+      <template #left>
+        <template v-if="$route.query && $route.query.code && $route.query.code == 2">
+          <van-icon name="wap-home-o" />
+          <span style="font-size: .32rem;color: #FFF;">首页</span>
+        </template>
+        <template v-else>
+          <van-icon name="arrow-left" />
+          <span style="font-size: .32rem;color: #FFF;">返回</span>
+        </template>
+      </template>
+    </van-nav-bar>
+    <div class="courseContent">
+      <div class="previewImg">
+        <video
+          ref="vueMiniPlayer"
+          :src="videoSrc"
+          controls
+          autoplay
+          v-if="showVideo"
+          controlsList="nodownload"
+        ></video>
+      </div>
+      <div class="title">
+        <p>{{ video_info.name }}</p>
+      </div>
+    </div>
+    <div class="otherCourse">
+      <scroller :isInitRefresh="false" ref="recordScroller">
+        <div class="otherContent">
+          <div class="tit">
+            <span>推荐课程</span>
+          </div>
+          <courseList :dataList="courseList" :showNum="4"></courseList>
+        </div>
+      </scroller>
+    </div>
+  </div>
+</template>
+
+<script>
+import { learnerCourseDetail, getFreeVideoSrc,getUserAllCourseList } from "../api";
+import courseList from "../components/courseList.vue";
+import { setWxConfig } from "../utils";
+export default {
+  name: "video",
+  data() {
+    return {
+      video_info: {
+        name: "今日更新"
+      },
+      showVideo: true,
+      title: "今日更新",
+      videoSrc: "",
+      courseDetail: {
+        thumb: "",
+        name: "",
+        images: [],
+        sections: []
+      },
+      courseList: [],
+      page:{
+        cur:1,
+        size:5,
+        total:0
+      }
+    };
+  },
+  components: { courseList },
+  watch: {
+    videoSrc() {
+      this.showVideo = false;
+      this.$nextTick(() => {
+        this.showVideo = true;
+        this.$nextTick(() => {
+          this.$refs.vueMiniPlayer.play(); //播放
+        });
+      });
+    }
+  },
+  activated() {
+    this.init();
+    if (this.$isWx) {
+      let info = {
+        title:this.$route.query.name,// 分享标题
+        desc:'听完觉得确实不错,忍不住要推荐~',// 分享描述
+        link: window.location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
+        imgUrl: 'https://oa.g107.com/m/static/images/logo.png', // 分享图标
+      }
+      if(this.$route.query&&this.$route.query.code){
+        let newUrl = this.urlDelP(window.location.href,'code')
+        info.link = newUrl.includes('?')?`${newUrl}&code=2`:`${newUrl}?code=2`
+      }else{
+        info.link = window.location.href.includes('?')?`${window.location.href}&code=2`:`${window.location.href}?code=2`
+      }
+      setWxConfig(info);
+    }
+  },
+  created() {
+    // this.init();
+  },
+  methods: {
+    //删除URL的指定参数
+    urlDelP(url,name){
+      var urlArr = url.split('?');
+      if(urlArr.length>1 && urlArr[1].indexOf(name)>-1){
+          var query = urlArr[1];
+          var obj = {}
+          var arr = query.split("&");
+          for (var i = 0; i < arr.length; i++) {
+              arr[i] = arr[i].split("=");
+              obj[arr[i][0]] = arr[i][1];
+          };
+          delete obj[name];
+          var urlte = urlArr[0] +'?'+ JSON.stringify(obj).replace(/[\"\{\}]/g,"").replace(/\:/g,"=").replace(/\,/g,"&");
+          return urlte;
+      }else{
+          return url;
+      };
+    },
+    // 获取所有课程列表
+    getList() {
+      let data = {
+        page: this.page.cur,
+        pageSize: this.page.size,
+        enable: 1
+      };
+      getUserAllCourseList(data).then(res => {
+        let list = [];
+        res.list.forEach(item => {
+          let data = {
+            subjectName: item.name,
+            subjectId: item.id,
+            subjectPrice: item.price,
+            subjectThumb: item.thumb,
+            subjectEnable: item.enable,
+            sectionsNum: item.sectionsNum,
+            clickNum: Number(item.baseClick) + Number(item.clickNum)
+          };
+          list.push(data);
+        });
+        this.courseList = list;
+        this.page.total = res.total;
+        this.page.cur = res.current;
+      });
+    },
+    // 章节切换获取视频地址
+    toSectionVidio(item, i) {
+      this.courseDetail.sections.forEach((item, index) => {
+        item.active = false;
+        if (index == i) {
+          item.active = true;
+        }
+      });
+      let data = {
+        index: i,
+        link: item.link
+      };
+      sessionStorage.setItem("vd_info", JSON.stringify(data));
+      this.getVideoLink(item.link);
+      // this.videoSrc = this.courseDetail.sections[index].link
+    },
+    // 获取视频地址
+    getVideoLink(link) {
+      let data = {
+        subjectId: this.$route.params.id,
+        link: link
+      };
+      getFreeVideoSrc(data)
+        .then(res => {
+          this.videoSrc = res;
+        })
+        .catch(err => {
+          this.$router.push("/courseError");
+        });
+    },
+    // 返回
+    onClickLeft() {
+      // this.$router.go(-1);
+      if (this.$route.query && this.$route.query.code && this.$route.query.code == 2) {
+        this.$router.push("/courseHome");
+      } else {
+        this.$router.go(-1);
+      }
+    },
+    // 初始化
+    init() {
+      if (this.$route.query) {
+        this.video_info = this.$route.query;
+        this.getVideoLink(this.video_info.link);
+        this.getList();
+      } else {
+        this.$toast.fail("视频似乎有点问题");
+        setTimeout(() => {
+          this.$router.go(-1);
+        }, 2000);
+      }
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+@import url("../utils/navBar.scss");
+* {
+  margin: 0;
+  padding: 0;
+}
+img {
+  display: block;
+}
+.page {
+  box-sizing: border-box;
+  .courseContent {
+    padding: 0.3rem 0.2rem 0;
+    background-color: #fff;
+    .previewImg {
+      border-radius: 0.1rem;
+      overflow: hidden;
+      width: 100%;
+      // height: 4rem;
+      video {
+        width: 100%;
+        // height: 4rem;
+      }
+    }
+    .title {
+      padding: 0.2rem 0;
+      p {
+        font-size: 0.32rem;
+        font-weight: 600;
+        color: #000;
+        line-height: 0.5rem;
+        // overflow: hidden;
+        // text-overflow: ellipsis;
+        // white-space: nowrap;
+        // word-break: break-all;
+      }
+    }
+    .tabs {
+      height: calc(100vh - 6.25rem);
+      position: relative;
+      .images {
+        margin-top: 0.1rem;
+        img {
+          width: 100%;
+        }
+      }
+      .catelog {
+        margin-top: 1px;
+        border-top: 1px solid #efefef;
+        .sup {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          span {
+            font-size: 0.24rem;
+            color: #666;
+            line-height: 3;
+          }
+        }
+        .logConetent {
+          .logLi {
+            border: 1px solid #efefef;
+            border-radius: 0.1rem;
+            padding: 0 0.2rem;
+            margin-bottom: 0.15rem;
+            p {
+              padding: 0.2rem 0;
+              font-size: 0.3rem;
+              color: #000;
+              line-height: 1.3;
+              // overflow: hidden;
+              // text-overflow: ellipsis;
+              // white-space: nowrap;
+              // word-break: break-all;
+            }
+            &.active {
+              box-shadow: 1px 4px #ddd;
+              p {
+                color: #26a2ff;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  .otherCourse {
+    height: calc(100vh - 6.3rem);
+    box-sizing: border-box;
+    position: relative;
+    background-color: #fff;
+    margin-top: 0.2rem;
+    .tit {
+      display: flex;
+      span {
+        font-size: 0.32rem;
+        color: #000;
+        font-weight: 600;
+        line-height: 0.6rem;
+      }
+    }
+    .otherContent {
+      padding: 0 0.2rem;
+    }
+  }
+}
+</style>

+ 2 - 0
src/view/user/account.vue

@@ -237,8 +237,10 @@ export default {
           if (window.plus) {
             plus.storage.removeItem('Admin-Token');
             plus.storage.removeItem('a-token-temp');
+            plus.storage.removeItem('a-token-tel');
           } else {
             localStorage.removeItem('a-token-temp');
+            localStorage.removeItem('a-token-tel');
             localStorage.removeItem('Admin-Token');
           }
           this.$store.dispatch('clear_cache');

+ 56 - 64
src/view/user/accountSet.vue

@@ -1,91 +1,83 @@
 <template>
   <div class="per-info__container">
-    <van-nav-bar class="headerbar no-down-icon" title="账号管理" left-text="返回" @click-left="$route_back" left-arrow>
+    <van-nav-bar
+      class="headerbar no-down-icon"
+      title="账号密码"
+      left-text="返回"
+      @click-left="$route_back"
+      left-arrow
+    >
       <template slot="right" class="department_right_nav">
-        <van-dropdown-menu  duration="0.3" text="text"  class="head_dropdown_menu">
-          <van-dropdown-item title="更多"  @change="plus_menu" :options="option" />
+        <van-dropdown-menu
+          duration="0.3"
+          text="text"
+          class="head_dropdown_menu"
+        >
+          <van-dropdown-item
+            title="更多"
+            @change="plus_menu"
+            :options="option"
+          />
         </van-dropdown-menu>
       </template>
     </van-nav-bar>
     <van-cell-group>
       <van-cell title="修改密码" to="change_pwd" is-link />
     </van-cell-group>
-    <van-dialog v-model="show" show-cancel-button @confirm="verify">
-       <div class="text">
-         <div>操作前需要验证你的登录密码</div>
-         <div>如果忘了原密码,请退出登录,点击"忘记密码",使用短信验证码重新登录后设置新密码。</div>
-       </div>
-       <van-cell-group>
-         <van-field v-model="password" label="原密码" placeholder="请输入原密码" type="password"  />
-       </van-cell-group>
-    </van-dialog>
   </div>
 </template>
 
 <script>
-import Vue from 'vue'
-import { Cell, CellGroup, DropdownMenu, DropdownItem} from 'vant'
+import Vue from "vue";
+import { Cell, CellGroup, DropdownMenu, DropdownItem } from "vant";
 
-import {returnJSEncrypt} from '@/utils/auth'
-Vue.use(Cell).use(CellGroup).use(DropdownMenu).use(DropdownItem)
+Vue.use(Cell)
+  .use(CellGroup)
+  .use(DropdownMenu)
+  .use(DropdownItem);
 
 export default {
-  name: 'accountSet',
-  data () {
+  name: "accountSet",
+  data() {
     return {
-      account_info: this.$store.getters.account_info,
-      option: [{ text: '账号注销', value: 1 }],
-      show: false,
-      password: ''
-    }
+      option: [{ text: "账号注销", value: 1 }]
+    };
   },
   methods: {
-    plus_menu (val) {
+    plus_menu(val) {
       if (val) {
-        this.password = ''
-        this.show = true
-      }
-    },
-    verify () {
-      if (!this.password) {
-        this.$toast('请输入密码')
-        return false
-      }
-      this.$toast.loading({
-        mask: true,
-        message: '正在验证...'
-      })
-      let data = {
-        tel: this.account_info.tel,
-        password: this.password,
-        custom_prompt: '密码错误'
+        this.$router.push({
+          path: "/verify",
+          query: {
+            type: 2
+          }
+        });
       }
-      this.$axiosUser('post', '/api/pro/login',{data:returnJSEncrypt(data)},'v2').then(res => {
-        if (res.data.code == 1) {
-          this.$router.push({name: 'verify'})
-        }
-      }).finally(e => {
-        this.$toast.clear()
-      })
     }
   }
-}
+};
 </script>
 
 <style scoped lang="less">
-  .text{
-    text-align: center;
-    color: #969799;
-    font-size: 0.28rem;
-    padding: 0.2rem 0;
-  }
-  .headerbar /deep/.van-dropdown-menu__title {
-      padding: 0;
-      padding-right: 0rem;
-      font-size: 0.3rem;
-      color: #fff;
-  }
-  /deep/ .van-dropdown-menu__bar {
-    background-color: transparent;
-  }
+.text {
+  text-align: center;
+  color: #969799;
+  font-size: 0.28rem;
+  padding: 0.2rem 0;
+}
+.headerbar /deep/.van-dropdown-menu__title {
+  padding: 0;
+  padding-right: 0rem;
+  font-size: 0.3rem;
+  color: #fff;
+}
+/deep/ .van-dropdown-menu__bar {
+  background-color: transparent;
+}
+/deep/ .van-nav-bar__right{
+  overflow: hidden;
+}
+/deep/ .van-dropdown-menu__title--active {
+  color: #fff !important;
+}
 </style>

+ 9 - 3
src/view/user/accountVf.vue

@@ -6,7 +6,7 @@
         <div class="login-form-box" style="background-color: #fff;">
           <div class="setp1">
             <van-cell-group>
-              <van-cell title="手机号" v-show="account_info.tel != ''">{{ account_info.tel | mobile }}</van-cell>
+              <van-cell title="手机号" v-show="account_tel != ''">{{ account_tel | mobile }}</van-cell>
               <van-field v-model="formData.origin_verify" center clearable label="验证码" placeholder="请输入短信验证码">
                 <van-button style="border:none;font-size:0.28rem;" :loading="sendMsgLoading" slot="button" size="small" plain type="info" @click="sendMsg" :disabled="sended">
                   {{ sendMsgText }}
@@ -48,6 +48,7 @@ export default {
       next_btn_enable: false,
       userinfo: this.$userInfo(),
       account_info: this.$store.getters.account_info,
+      account_tel:localStorage.getItem('a-token-tel'),
       setp: 1,
       countdown: 90,
       sended: false,
@@ -86,10 +87,13 @@ export default {
       deep: true
     }
   },
+  activated(){
+    // console.log(account_tel)
+  },
   methods: {
     nextReg() {
       this.next_loading = true;
-      let data = { tel: this.account_info.tel, verify: this.formData.origin_verify };
+      let data = { tel: this.account_tel, verify: this.formData.origin_verify };
       this.$axios('post', '/api/pro/destruction', { data: returnJSEncrypt(data) }, 'v2').then(res => {
           if (res.data.code == 1) {
             this.$toast('注销成功');
@@ -107,8 +111,10 @@ export default {
       if (window.plus) {
         plus.storage.removeItem('Admin-Token');
         plus.storage.removeItem('a-token-temp');
+        plus.storage.removeItem('a-token-tel');
       } else {
         localStorage.removeItem('a-token-temp');
+        localStorage.removeItem('a-token-tel');
         localStorage.removeItem('Admin-Token');
       }
       this.$store.dispatch('clear_cache');
@@ -138,7 +144,7 @@ export default {
 
     sendMsg() {
       this.sendMsgLoading = true;
-      let data = { mobile: this.account_info.tel, type: 7 };
+      let data = { mobile: this.account_tel, type: 7 };
       if (!this.verifyPhoneNo(data.mobile)) {
         this.$notify({
           message: '请输入正确手机号码',

+ 44 - 3
src/view/user/create_company.vue

@@ -1,6 +1,12 @@
 <template>
   <div>
-    <van-nav-bar title="创建企业" left-text="返回" @click-left="$route_back" left-arrow></van-nav-bar>
+    <van-nav-bar title="创建企业" left-text="返回" @click-left="$route_back" left-arrow>
+      <template slot="right" class="department_right_nav">
+        <van-dropdown-menu  duration="0.3" text="text"  class="head_dropdown_menu">
+          <van-dropdown-item title="•••"  @change="plus_menu" :options="option" />
+        </van-dropdown-menu>
+      </template>
+    </van-nav-bar>
     <div class="body_com has_header">
       <div class="body_com_bg"></div>
       <van-cell-group>
@@ -37,13 +43,16 @@
 <script>
 import Vue from 'vue';
 import { setToken } from '@/utils/auth';
-import { Picker } from 'vant';
+import {returnJSEncrypt} from '@/utils/auth'
+import { Picker,DropdownMenu,DropdownItem } from 'vant';
+
+Vue.use(Picker).use(DropdownMenu).use(DropdownItem);
 
-Vue.use(Picker);
 export default {
   name: 'create_company',
   data() {
     return {
+      option: [{ text: '账号注销', value: 1 }],
       submit_loading: false,
       formdata: {
         tel: '',
@@ -81,6 +90,11 @@ export default {
     );
   },
   methods: {
+    plus_menu (val) {
+      if (val) {
+        this.$router.push('/verify')
+      }
+    },
     get_company_info(id) {
       let self = this;
       this.$axios('get', '/addons/ems/index/get_company_info', { id: id }).then(res => {
@@ -144,6 +158,12 @@ export default {
 </script>
 
 <style scoped>
+.text{
+  text-align: center;
+  color: #969799;
+  font-size: 0.28rem;
+  padding: 0.2rem 0;
+}
 .van-nav-bar__title {
   font-weight: bold;
 }
@@ -248,4 +268,25 @@ export default {
   border: 0.02rem solid #238dfa;
   border-radius: 0.04rem;
 }
+.text{
+  text-align: center;
+  color: #969799;
+  font-size: 0.28rem;
+  padding: 0.2rem 0;
+}
+/deep/ .van-dropdown-menu__bar {
+  background-color: transparent;
+}
+/deep/ .van-dropdown-menu__title{
+  color: #FFF;
+}
+/deep/ .van-dropdown-menu__title::after{
+  display: none;
+}
+/deep/ .van-nav-bar__right{
+  overflow: hidden;
+}
+/deep/ .van-dropdown-menu__title--active{
+  color: #FFF!important;
+}
 </style>

+ 222 - 0
src/view/user/iosIntercept.vue

@@ -0,0 +1,222 @@
+<template>
+  <div class="page">
+    <van-nav-bar class="left-text-bold" left-text="返回" title="欢迎使用功道云" @click-left="$route_back" left-arrow>
+      <template slot="right" class="department_right_nav">
+        <van-dropdown-menu
+          duration="0.3"
+          text="text"
+          class="head_dropdown_menu"
+        >
+          <van-dropdown-item
+            title="•••"
+            @change="plus_menu"
+            :options="option"
+          />
+        </van-dropdown-menu>
+      </template>
+    </van-nav-bar>
+    <van-tabs v-model="active" swipeable animated>
+      <van-tab v-for="(item, index) in options" :key="index" :title="item"></van-tab>
+    </van-tabs>
+    <div class="pageContent">
+      <scroller>
+        <div class="showDemo">
+          <template v-for="(item, index) in imgUrls">
+            <img v-if="index == active" :src="item" @click="buyPopupPage = true" >
+          </template>
+        </div>
+      </scroller>
+    </div>
+    <div class="pageBtm">
+      <van-button
+        class="b_btn"
+        @click="buyPopupPage = true"
+        >预约演示</van-button
+      >
+      <a href="tel:400-6877-880" class='a_btn'>电话咨询</a>
+    </div>
+    <van-popup
+      v-model="buyPopupPage"
+      style="border-radius: 0.15rem; background: #fff0;overflow: visible;"
+      @closed="getItemBuyPopupPage"
+    >
+      <div class="buyPopupBody">
+        <div class="buyPopupContent">
+          <div class="buyPopupTitle">预约演示</div>
+          <p class="buyPopupTxt">
+            欢迎使用功道云,我们有专属顾问免费给您一对一同屏讲解系统软件,如需演示请点击【立即预约】,或拨打电话
+          </p>
+          <a class="buyPopupTel" href="tel:400-6877-880">400-6877-880</a>
+          <van-row gutter="20" style="margin-top: 0.32rem;">
+            <van-col span="12"
+              ><van-button block type="info" @click="applyButton"
+                >立即预约</van-button
+              ></van-col
+            >
+            <van-col span="12"
+              ><van-button block type="default" @click="getItemBuyPopupPage"
+                >我知道了</van-button
+              ></van-col
+            >
+          </van-row>
+        </div>
+      </div>
+    </van-popup>
+  </div>
+</template>
+
+<script>
+import Vue from "vue";
+import { DropdownMenu, DropdownItem } from "vant";
+Vue.use(DropdownMenu).use(DropdownItem);
+export default {
+  name: "iosIntercept",
+  components: {},
+  data() {
+    return {
+      active: 0,
+      options: ["积分", "目标", "绩效", "巡检"],
+      option: [{ text: "账号注销", value: 1 }],
+      buyPopupPage: false,
+      imgUrls:[
+        "static/images/s-jifen.jpg",
+        "static/images/s-mubiao.jpg",
+        "static/images/s-jixiao.jpg",
+        "static/images/s-xunjian.jpg"
+      ]
+    };
+  },
+  created() {},
+  methods: {
+    plus_menu(val) {
+      if (val) {
+        this.$router.push({
+          path: "/verify"
+        });
+      }
+    },
+    getItemBuyPopupPage() {
+      this.buyPopupPage = false;
+    },
+    applyButton() {
+      let self = this;
+      let data = {
+        account_id: this.$getCache('account').id,
+        source_type: 1,
+        apply_type: 2
+      };
+      this.$axiosUser("post", "/api/pro/intentions/addbuy", data)
+        .then(res => {
+          this.$toast({
+            message: "预约成功,专属顾问“孙小姐”将在24小时内与您联系",
+            duration: 5000
+          });
+        })
+        .finally(() => {
+          this.buyPopupPage = false;
+        });
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+* {
+  padding: 0;
+  margin: 0;
+}
+img {
+  width: 100%;
+}
+.page {
+  background-color: #fff;
+  .pageContent {
+    height: calc(100vh - 3.9rem);
+    position: relative;
+  }
+  .pageBtm {
+    width: 100%;
+    height: 1.8rem;
+    display: flex;
+    justify-content: space-around;
+    align-items: center;
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    .b_btn{
+      color: #26A2FF;
+      background: rgb(255, 255, 255);
+      border-color: rgb(255, 255, 255);
+      border: 1px solid #26A2FF;
+      box-sizing: border-box;
+      width: 40%;
+      border-radius: .1rem;
+      font-weight: 600;
+    }
+    .a_btn{
+      font-size: .28rem;
+      font-weight: 600;
+      color: #fff;
+      width: 40%;
+      background-color: #26A2FF;
+      display: block;
+      line-height: .88rem;
+      border-radius: 0.04rem;
+      box-sizing: border-box;
+      text-align: center;
+      border-radius: .1rem;
+    }
+  }
+  .buyPopupBody {
+    width: 85vw;
+    .buyPopupContent {
+      position: relative;
+      background: white;
+      padding: 0 5vw 5vw 5vw;
+      border-radius: 0.15rem;
+      .buyPopupTitle {
+        background: #1a89fa;
+        position: absolute;
+        left: 0.6rem;
+        right: 0.6rem;
+        top: -0.3rem;
+        text-align: center;
+        border-radius: 0.1rem;
+        line-height: 2;
+        font-weight: normal;
+        font-size: 0.36rem;
+        color: #fff;
+      }
+      .buyPopupTxt {
+        font-size: 0.32rem;
+        line-height: 1.8;
+        padding-top: 0.8rem;
+      }
+      .buyPopupTel {
+        color: #1a89fa;
+        font-weight: bold;
+      }
+    }
+  }
+}
+/deep/ .van-tabs__wrap {
+  width: 60%;
+}
+/deep/ .van-dropdown-menu__bar {
+  background-color: transparent;
+}
+/deep/ .van-dropdown-menu__title {
+  color: #fff;
+}
+/deep/ .van-dropdown-menu__title::after {
+  display: none;
+}
+/deep/ .van-tabs__line {
+  z-index: 0;
+}
+/deep/ .van-nav-bar__right{
+  overflow: hidden;
+}
+/deep/ .van-dropdown-menu__title--active{
+  color: #FFF!important;
+}
+</style>

+ 699 - 576
src/view/user/login.vue

@@ -13,26 +13,53 @@
           </div>
           <div class="setp1">
             <van-cell-group style="margin-top:0.3rem;">
-              <van-field class="tel" left-icon="logo" label-class="hidden" label="" type="Number"
-                v-model="formData.username" placeholder="手机号" clearable style="color:#515151;caret-color:#26A2FF;"
-                name="手机号码" v-validate="'required|phone'">
+              <van-field
+                class="tel"
+                left-icon="logo"
+                label-class="hidden"
+                label=""
+                type="Number"
+                v-model="formData.username"
+                placeholder="手机号"
+                clearable
+                style="color:#515151;caret-color:#26A2FF;"
+                name="手机号码"
+                v-validate="'required|phone'"
+              >
                 <template slot="left-icon">
                   <icon name="tel" class="login_tel"></icon>
                 </template>
               </van-field>
 
-              <van-field class="psw" label-class="hidden" left-icon="logo" clearable type="password" v-model="formData.password" placeholder="密码" name="密码" v-validate="'required|alpha_dash|min:6'"  style="color:#515151;caret-color:#26A2FF;">
+              <van-field
+                class="psw"
+                label-class="hidden"
+                left-icon="logo"
+                clearable
+                type="password"
+                v-model="formData.password"
+                placeholder="密码"
+                name="密码"
+                v-validate="'required|alpha_dash|min:6'"
+                style="color:#515151;caret-color:#26A2FF;"
+              >
                 <template slot="left-icon">
                   <icon name="pwd" class="login_pwd"></icon>
                 </template>
               </van-field>
-
             </van-cell-group>
           </div>
 
           <div style="padding:0 0.32rem">
-            <van-button class="login_button" color="#228bf8" size="large" :disabled="!next_btn_enable"
-              @click="sendLogin" type="info">登录</van-button>
+            <van-button
+              class="login_button"
+              color="#228bf8"
+              size="large"
+              :disabled="!next_btn_enable"
+              @click="sendLogin"
+              type="info"
+              >登录</van-button
+            >
           </div>
           <div style="padding:0.2rem 0.32rem 0.2rem;" class="reg_link_box">
             <van-row>
@@ -40,12 +67,14 @@
                 <div class="blue" @click="openUrl(1)">找回密码</div>
               </van-col>
               <van-col span="12" style="text-align: right;">
-                <div @click="openUrl(2)">注册免费试用</div>
+                <div @click="openUrl(2)">注册账号</div>
               </van-col>
             </van-row>
           </div>
-          <div style="text-align: center; padding:0 0.32rem;letter-spacing: 0.01rem"
-            v-if="(auths.length > 0&&isAndroid)||$isWx">
+          <div
+            style="text-align: center; padding:0 0.32rem;letter-spacing: 0.01rem"
+            v-if="(auths.length > 0 && isAndroid) || $isWx"
+          >
             <van-divider>快捷登录</van-divider>
             <div style="display: inline-block;" @click="doWeixinLogin">
               <icon name="weixindenglu" style="width:1.2rem;"></icon>
@@ -53,25 +82,45 @@
           </div>
         </div>
         <div class="footer flex-box-ce flex-center-center" v-if="!$isWx">
-          <van-checkbox icon-size="14px" v-model="isYsShow">登录即同意功道云</van-checkbox>
-          <span style="color:#28a2f1" @click="$router.push({ name: 'user_agreement' })">《服务协议》</span>
+          <van-checkbox icon-size="14px" v-model="isYsShow"
+            >登录即同意功道云</van-checkbox
+          >
+          <span
+            style="color:#28a2f1"
+            @click="$router.push({ name: 'user_agreement' })"
+            >《服务协议》</span
+          >
           <span>&</span>
-          <span style="color:#28a2f1" @click="$router.push({ name: 'privacy_agreement' })">《隐私政策》</span>
+          <span
+            style="color:#28a2f1"
+            @click="$router.push({ name: 'privacy_agreement' })"
+            >《隐私政策》</span
+          >
         </div>
       </div>
     </div>
 
-
-
     <!-- 隐私条例 -->
-    <van-popup v-model="showYs" :close-on-click-overlay="false" class="popup-all">
+    <van-popup
+      v-model="showYs"
+      :close-on-click-overlay="false"
+      class="popup-all"
+    >
       <div style="position: relative;">
         <div class="title">提示</div>
         <div class="content">
           使用本软件前请认真阅读我们的
-          <span style="color:#28a2f1" @click="$router.push({ name: 'user_agreement' })">《用户服务协议》</span>
+          <span
+            style="color:#28a2f1"
+            @click="$router.push({ name: 'user_agreement' })"
+            >《用户服务协议》</span
+          >
-          <span style="color:#28a2f1" @click="$router.push({ name: 'privacy_agreement' })">《隐私协议》</span>
+          <span
+            style="color:#28a2f1"
+            @click="$router.push({ name: 'privacy_agreement' })"
+            >《隐私协议》</span
+          >
           相关条款,您也可以稍后在应用设置里浏览查看。点击“同意使用”即表示您接受我们的服务协议和隐私政策,继续使用我们的软件。
         </div>
         <div class="footer2 flex-box-ce">
@@ -84,29 +133,63 @@
     <!-- 微信登录 -->
     <van-popup v-model="isShowSelect" class="popup-all">
       <div style="position: relative;">
-        <div style="position: absolute;top:16px;right:16px" @click="isShowSelect=false"><van-icon name="cross" /></div>
+        <div
+          style="position: absolute;top:16px;right:16px"
+          @click="isShowSelect = false"
+        >
+          <van-icon name="cross" />
+        </div>
         <div class="contentBox">
           <div class="">欢迎使用功道云!</div>
           <p>请选择以下进入方式,如已有登录账号<br />请先绑定账号再进入</p>
         </div>
         <div class="btns" style="padding-bottom: 16px;">
-          <div class="bdBtn" @click="$router.push({ name: 'bindingPhone', query: { secret: wo_token } })">绑定已有账号</div>
-          <div style="font-size: 0.28rem;color: #666" @click="wxLogin">创建新账号</div>
+          <div
+            class="bdBtn"
+            @click="
+              $router.push({
+                name: 'bindingPhone',
+                query: { secret: wo_token }
+              })
+            "
+          >
+            绑定已有账号
+          </div>
+          <div style="font-size: 0.28rem;color: #666" @click="wxLogin">
+            注册账号
+          </div>
         </div>
       </div>
     </van-popup>
 
-    <van-dialog v-model="isShowDialog" confirmButtonText="同意并继续" confirmButtonColor="#238cf9" @confirm="confirmDialog">
+    <van-dialog
+      v-model="isShowDialog"
+      confirmButtonText="同意并继续"
+      confirmButtonColor="#238cf9"
+      @confirm="confirmDialog"
+    >
       <div style="padding: 0.3rem;">
         <div class="flex-box-ce" style="margin-bottom: 0.24rem;">
-          <div style="font-size: 0.4rem;font-weight: 700;" class="flex-1 black">服务协议和隐私政策</div>
-          <van-icon name="cross" @click="isShowDialog=false" class="fontColorC"
-            style="font-size: 0.3rem;position: relative;top: -0.1rem;right: -0.1rem;" />
+          <div style="font-size: 0.4rem;font-weight: 700;" class="flex-1 black">
+            服务协议和隐私政策
+          </div>
+          <van-icon
+            name="cross"
+            @click="isShowDialog = false"
+            class="fontColorC"
+            style="font-size: 0.3rem;position: relative;top: -0.1rem;right: -0.1rem;"
+          />
         </div>
         <div class="fontColorC">
-          为了更好地保障你的合法权益,使用前请阅读并同意功道云<span style="color:#28a2f1"
-            @click="$router.push({ name: 'user_agreement' })">《服务协议》</span>&<span style="color:#28a2f1"
-            @click="$router.push({ name: 'privacy_agreement' })">《隐私政策》</span>
+          为了更好地保障你的合法权益,使用前请阅读并同意功道云<span
+            style="color:#28a2f1"
+            @click="$router.push({ name: 'user_agreement' })"
+            >《服务协议》</span
+          >&<span
+            style="color:#28a2f1"
+            @click="$router.push({ name: 'privacy_agreement' })"
+            >《隐私政策》</span
+          >
         </div>
       </div>
     </van-dialog>
@@ -114,602 +197,642 @@
 </template>
 
 <script>
-  import {
-    setToken,
-    returnJSEncrypt
-  } from '@/utils/auth';
-  import axios from 'axios';
-  import qs from 'qs';
-  import Vue from 'vue';
-  import {
-    Divider
-  } from 'vant';
-  Vue.use(Divider);
-  export default {
-    name: 'login',
-    data() {
-      return {
-        input_focus: false,
-        next_btn_enable: false,
-        isAndroid: this.$getCache('isAndroid'),
-        formData: {
-          username: '',
-          password: ''
-        },
-        aweixin: null,
-        auths: [],
-
-        index: 0,
-        // 微信登录
-        isShowSelect: false,
-        // 隐私相关
-        isYsShow: false,
-        showYs: false,
-        wo_token: '',
-        isShowDialog: false,
-        // wo_token:'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOm51bGwsImlhdCI6MTY0MjI0MDQ3NywiZXhwIjoxNjQ0ODMyNDc3LCJuYmYiOjE2NDIyNDA0NzcsImp0aSI6ImtlZmVxZ09yMVZYWEVNZmwiLCJzdWIiOjgsInBydiI6IjAzMDBhNTQ5YWI4ZjcwMmNkYTgzMjMxYTQxMzMyZWNjYmRlOWRmOGYiLCJyb2xlIjoid2VjaGF0X29wZW5fdXNlciJ9.SRt2d8-J3FXQ0UFU27csIiGOJvOSxzQSoDMV-LpE3ZM' //微信登录token
-      };
-    },
-    created() {
-      let that = this;
-      document.body.addEventListener('blur', function(e) {
+import { setToken, returnJSEncrypt } from "@/utils/auth";
+import axios from "axios";
+import qs from "qs";
+import Vue from "vue";
+import { Divider } from "vant";
+Vue.use(Divider);
+export default {
+  name: "login",
+  data() {
+    return {
+      input_focus: false,
+      next_btn_enable: false,
+      isAndroid: this.$getCache("isAndroid"),
+      formData: {
+        username: "",
+        password: ""
+      },
+      aweixin: null,
+      auths: [],
+
+      index: 0,
+      // 微信登录
+      isShowSelect: false,
+      // 隐私相关
+      isYsShow: false,
+      showYs: false,
+      wo_token: "",
+      isShowDialog: false
+      // wo_token:'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOm51bGwsImlhdCI6MTY0MjI0MDQ3NywiZXhwIjoxNjQ0ODMyNDc3LCJuYmYiOjE2NDIyNDA0NzcsImp0aSI6ImtlZmVxZ09yMVZYWEVNZmwiLCJzdWIiOjgsInBydiI6IjAzMDBhNTQ5YWI4ZjcwMmNkYTgzMjMxYTQxMzMyZWNjYmRlOWRmOGYiLCJyb2xlIjoid2VjaGF0X29wZW5fdXNlciJ9.SRt2d8-J3FXQ0UFU27csIiGOJvOSxzQSoDMV-LpE3ZM' //微信登录token
+    };
+  },
+  created() {
+    let that = this;
+    document.body.addEventListener(
+      "blur",
+      function(e) {
         setTimeout(() => {
-          e.target.parentNode.parentNode.parentNode.classList.remove('field-focus');
+          e.target.parentNode.parentNode.parentNode.classList.remove(
+            "field-focus"
+          );
           that.input_focus = false;
         }, 100);
-      }, true);
-      document.body.addEventListener('focus', function(e) {
-        e.target.parentNode.parentNode.parentNode.classList.add('field-focus');
+      },
+      true
+    );
+    document.body.addEventListener(
+      "focus",
+      function(e) {
+        e.target.parentNode.parentNode.parentNode.classList.add("field-focus");
         setTimeout(() => {
           that.input_focus = true;
         }, 100);
-      }, true);
-      this.$store.commit('SET_USERINFO', {}); // 清空人员信息
-      this.$store.commit('SET_USERID', 0);
-      // alert(`$isWx${this.$isWx}`)
-      if (this.$isWx) {
-        this.doWeixinLogin();
-        return false
-      }
+      },
+      true
+    );
+    this.$store.commit("SET_USERINFO", {}); // 清空人员信息
+    this.$store.commit("SET_USERID", 0);
+    // alert(`$isWx${this.$isWx}`)
+    if (this.$isWx) {
+      this.doWeixinLogin();
+      return false;
+    }
+    if (window.plus) {
+      this.hei = plus.navigator.getStatusbarHeight();
+      this.getServiceOauth();
+    }
+  },
+  mounted() {
+    this.$removeCache("account");
+  },
+  watch: {
+    formData: {
+      handler(val, oldVal) {
+        if (val.username != "" && val.password != "") {
+          this.next_btn_enable = true;
+        } else {
+          this.next_btn_enable = false;
+        }
+      },
+      deep: true
+    }
+  },
+  methods: {
+    confirmDialog() {
+      this.isShowDialog = true;
+      this.isYsShow = true;
+    },
+    wxLogin() {
+      let pl = "a";
       if (window.plus) {
-        this.hei = plus.navigator.getStatusbarHeight();
-        this.getServiceOauth();
+        if (navigator.userAgent.indexOf("Android") > 0) {
+          pl = "a";
+        } else {
+          pl = "i";
+        }
       }
+      axios({
+        method: "post",
+        url: process.env.BASE_API + "/api/pro/wo/create",
+        headers: {
+          "Content-Type": "application/x-www-form-urlencoded",
+          pl: pl,
+          "A-TOKEN": this.wo_token
+        }
+      }).then(res => {
+        if (res.data.code == 1) {
+          this.$setCache("account", res.data.data.account);
+          localStorage.setItem("a-token-temp", res.data.data.token); // 保存平台账号登录的token
+          localStorage.setItem("a-token-tel", res.data.data.account.tel); // 保存平台账号登录的token
+          this.registrationExperience(); //进入体验账号
+        } else {
+          this.$toast(res.data.msg);
+        }
+      });
     },
-    mounted() {
-      this.$removeCache('account')
-    },
-    watch: {
-      formData: {
-        handler(val, oldVal) {
-          if (val.username != '' && val.password != '') {
-            this.next_btn_enable = true;
-          } else {
-            this.next_btn_enable = false;
-          }
-        },
-        deep: true
+    openUrl(index) {
+      if (!this.isLogin()) {
+        return false;
+      }
+      if (index == 1) {
+        this.$router.push({
+          name: "forget_pwd"
+        });
+      } else {
+        this.$router.push({
+          name: "reg"
+        });
       }
     },
-    methods: {
-      confirmDialog() {
+    openHome() {
+      setTimeout(() => {
+        window.location.href = window.location.href.split("#")[0];
+      }, 100);
+    },
+    isLogin() {
+      if (!this.isYsShow && process.env.NODE_ENV == "production") {
         this.isShowDialog = true;
-        this.isYsShow = true
-      },
-      wxLogin() {
-        let pl = 'a';
-        if (window.plus) {
-          if (navigator.userAgent.indexOf('Android') > 0) {
-            pl = 'a';
-          } else {
-            pl = 'i';
-          }
-        }
-        axios({
-          method: 'post',
-          url: process.env.BASE_API + '/api/pro/wo/create',
-          headers: {
-            'Content-Type': 'application/x-www-form-urlencoded',
-            pl: pl,
-            'A-TOKEN': this.wo_token
-          }
-        }).then(res => {
-          if (res.data.code == 1) {
-            this.$setCache('account', res.data.data.account);
-            localStorage.setItem('a-token-temp', res.data.data.token); // 保存平台账号登录的token
-            this.registrationExperience(); //进入体验账号
-          } else {
-            this.$toast(res.data.msg);
+        return false;
+      } else {
+        return true;
+      }
+    },
+    // 判断是否获取微信登录认证
+    getServiceOauth() {
+      var that = this;
+      if (window.plus) {
+        plus.oauth.getServices(function(services) {
+          that.auths = services;
+          for (let i in services) {
+            if (services[i].id == "weixin") {
+              that.aweixin = services[i];
+            }
           }
         });
-      },
-      openUrl(index) {
-        if (!this.isLogin()) {
-          return false
-        }
-        if (index == 1) {
-          this.$router.push({
-            name: 'forget_pwd'
-          });
+      }
+    },
+    doWeixinLogin() {
+      if (this.$isWx) {
+        if (this.isAndroid) {
+          window.open(process.env.VUE_APP_WXURL, "_blank");
         } else {
-          this.$router.push({
-            name: 'reg'
-          });
+          window.location.href = process.env.VUE_APP_WXURL;
         }
-      },
-      openHome() {
-        setTimeout(() => {
-          window.location.href = window.location.href.split('#')[0];
-        }, 100);
-      },
-      isLogin() {
-        if (!this.isYsShow && process.env.NODE_ENV == 'production') {
-          this.isShowDialog = true;
-          return false;
-        } else {
-          return true;
+        return false;
+      }
+      let that = this;
+      if (window.plus && this.isLogin()) {
+        if (this.aweixin == null) {
+          plus.nativeUI.alert("当前环境不支持微信登录");
+          return;
         }
-      },
-      // 判断是否获取微信登录认证
-      getServiceOauth() {
-        var that = this;
-        if (window.plus) {
-          plus.oauth.getServices(function(services) {
-            that.auths = services;
-            for (let i in services) {
-              if (services[i].id == 'weixin') {
-                that.aweixin = services[i];
-              }
+        this.aweixin.authorize(
+          function(e) {
+            that.WeixinLogin(e.code);
+          },
+          function(e) {
+            if (e.code == "-1002") {
+              plus.nativeUI.alert("请先安装微信客户端");
             }
-          });
-        }
-      },
-      doWeixinLogin() {
-        if (this.$isWx) {
-          if (this.isAndroid) {
-            window.open(process.env.VUE_APP_WXURL, '_blank');
-          } else {
-            window.location.href = process.env.VUE_APP_WXURL
+          },
+          {
+            scope: "snsapi_userinfo",
+            state: "authorize test",
+            appid: "wx84f9a9b3ce29f450"
           }
-          return false
-        }
-        let that = this;
-        if (window.plus && this.isLogin()) {
-          if (this.aweixin == null) {
-            plus.nativeUI.alert('当前环境不支持微信登录');
-            return;
-          }
-          this.aweixin.authorize(
-            function(e) {
-              that.WeixinLogin(e.code);
-            },
-            function(e) {
-              if (e.code == '-1002') {
-                plus.nativeUI.alert('请先安装微信客户端');
+        );
+      }
+    },
+    sendLogin() {
+      if (!this.isLogin()) {
+        return false;
+      }
+      this.$validator.validate().then(result => {
+        if (!result) {
+          this.$notify({
+            type: "danger",
+            message: this.$validator.errors.items[0].msg
+          });
+        } else {
+          this.$toast.loading({
+            mask: true,
+            message: "正在登录..."
+          });
+          this.$store
+            .dispatch("login", {
+              tel: this.formData.username,
+              password: this.formData.password
+            })
+            .then(res => {
+              if (res.code == 1) {
+                this.$setCache("account", res.data.account);
+                localStorage.setItem('a-token-tel',this.formData.username)
+                localStorage.setItem("a-token-temp", res.data.token); // 保存平台账号登录的token
+                // if (window.plus) {
+                //   let deviceInfo = window.plus.os.name;
+                //   if (
+                //     deviceInfo === "IOS" &&
+                //     res.data.account_site.length > 0
+                //   ) {
+                //     console.log("苹果软件用户有创建公司");
+                //   }
+                //   if (
+                //     deviceInfo === "IOS" &&
+                //     res.data.account_site.length == 0
+                //   ) {
+                //     console.log("苹果软件用户没有创建公司");
+                //   }
+                // }
+                console.log(res.data.account_site);
+                this.openUrl2(
+                  res.data.account_site,
+                  res.data.invitation_wait_count
+                );
+              } else {
+                this.$toast.fail({
+                  message: res.msg,
+                  duration: 1000
+                });
               }
-            }, {
-              scope: 'snsapi_userinfo',
-              state: 'authorize test',
-              appid: 'wx84f9a9b3ce29f450'
-            }
-          );
-        }
-      },
-      sendLogin() {
-        if (!this.isLogin()) {
-          return false
-        }
-        this.$validator.validate().then(result => {
-          if (!result) {
-            this.$notify({
-              type: 'danger',
-              message: this.$validator.errors.items[0].msg
+            })
+            .finally(() => {
+              this.$toast.clear();
             });
-          } else {
-            this.$toast.loading({
-              mask: true,
-              message: '正在登录...'
-            });
-            this.$store.dispatch('login', {
-                tel: this.formData.username,
-                password: this.formData.password
-              }).then(res => {
-                if (res.code == 1) {
-                  localStorage.setItem('a-token-temp', res.data.token); // 保存平台账号登录的token
-                  this.openUrl2(res.data.account_site, res.data.invitation_wait_count);
-                } else {
-                  this.$toast.fail({
-                    message: res.msg,
-                    duration: 1000
-                  });
-                }
-              })
-              .finally(() => {
-                this.$toast.clear();
-              });
-          }
-        });
-      },
-      // 直接进入,跳过选择行业与公司,体验账户专用
-      registrationExperience() {
+        }
+      });
+    },
+    // 直接进入,跳过选择行业与公司,体验账户专用
+    registrationExperience() {
+      if (window.plus&&(navigator.userAgent.indexOf('iPhone') > 0)) {
+        this.$router.replace({
+          name: 'iosIntercept'
+        })
+      } else {
         this.$router.replace({
           name: 'create_company'
         })
-      },
-      WeixinLogin(code) {
-        this.$toast.loading({
-          mask: true,
-          message: '正在登录...'
-        });
-        let pl = 'a';
-        if (window.plus) {
-          if (navigator.userAgent.indexOf('Android') > 0) {
-            pl = 'a';
-          } else {
-            pl = 'i';
-          }
+      }
+    },
+    WeixinLogin(code) {
+      this.$toast.loading({
+        mask: true,
+        message: "正在登录..."
+      });
+      let pl = "a";
+      if (window.plus) {
+        if (navigator.userAgent.indexOf("Android") > 0) {
+          pl = "a";
+        } else {
+          pl = "i";
         }
-        let data = {
-          code: code,
-        };
-        axios({
-          method: 'post',
-          url: process.env.BASE_API + '/api/pro/wo/code',
-          data: qs.stringify({
-            data: returnJSEncrypt(data)
-          }),
-          headers: {
-            'Content-Type': 'application/x-www-form-urlencoded',
-            pl: pl
-          }
-        }).then(res => {
-          if (res.data.code == 1) {
-            this.wo_token = res.data.data.wo_token;
-            this.wxSelect();
-          } else {
-            this.$toast(res.data.msg);
-          }
-        });
-      },
-      wxSelect() {
-        let pl = 'a';
-        if (window.plus) {
-          if (navigator.userAgent.indexOf('Android') > 0) {
-            pl = 'a';
-          } else {
-            pl = 'i';
-          }
+      }
+      let data = {
+        code: code
+      };
+      axios({
+        method: "post",
+        url: process.env.BASE_API + "/api/pro/wo/code",
+        data: qs.stringify({
+          data: returnJSEncrypt(data)
+        }),
+        headers: {
+          "Content-Type": "application/x-www-form-urlencoded",
+          pl: pl
         }
-        axios({
-          method: 'get',
-          url: process.env.BASE_API + '/api/pro/wo/oui',
-          headers: {
-            'Content-Type': 'application/x-www-form-urlencoded',
-            pl: pl,
-            'A-TOKEN': this.wo_token
-          }
-        }).then(res => {
-          if (res.data.code == 1) {
-            this.$setCache('account', res.data.data.account);
-            if (res.data.data.account_id !== 0) {
-              localStorage.setItem('a-token-temp', res.data.data.token); // 保存平台账号登录的token
-              // 已绑定平台账号
-              this.openUrl2(res.data.data.account_site, res.data.data.invitation_wait_count);
-            } else {
-              this.$router.replace({
-                name: 'regWx',
-                query: {
-                  wo_token: this.wo_token
-                }
-              });
-              // this.isShowSelect = true;
-            }
+      }).then(res => {
+        if (res.data.code == 1) {
+          this.wo_token = res.data.data.wo_token;
+          this.wxSelect();
+        } else {
+          this.$toast(res.data.msg);
+        }
+      });
+    },
+    wxSelect() {
+      let pl = "a";
+      if (window.plus) {
+        if (navigator.userAgent.indexOf("Android") > 0) {
+          pl = "a";
+        } else {
+          pl = "i";
+        }
+      }
+      axios({
+        method: "get",
+        url: process.env.BASE_API + "/api/pro/wo/oui",
+        headers: {
+          "Content-Type": "application/x-www-form-urlencoded",
+          pl: pl,
+          "A-TOKEN": this.wo_token
+        }
+      }).then(res => {
+        if (res.data.code == 1) {
+          this.$setCache("account", res.data.data.account);
+          if (res.data.data.account_id !== 0) {
+            localStorage.setItem("a-token-temp", res.data.data.token); // 保存平台账号登录的token
+            localStorage.setItem("a-token-tel", res.data.data.account.tel); // 保存平台账号登录的token
+            // 已绑定平台账号
+            this.openUrl2(
+              res.data.data.account_site,
+              res.data.data.invitation_wait_count
+            );
           } else {
-            this.$toast(res.data.msg);
-          }
-        });
-      },
-      openUrl2(account_site, invitation_wait_count) {
-        if (account_site.length > 0) {
-          // 公司数量
-          if (invitation_wait_count > 0) {
-            this.$router.push({
-              name: 'registration_experience',
+            this.$router.replace({
+              name: "regWx",
               query: {
-                invite: 1,
-                iscompany: 1
+                wo_token: this.wo_token
               }
-            }); // 选择行业
-          } else {
-            this.$router.push({
-              name: 'login_company_list'
-            }); // 选择企业
+            });
+            // this.isShowSelect = true;
           }
         } else {
-          if (invitation_wait_count > 0) {
-            // 待邀请数量
-            this.$router.push({
-              name: 'registration_experience',
-              query: {
-                invite: 1
-              }
-            }); // 选择行业
-          } else {
-            this.registrationExperience(); //进入体验账号
-          }
+          this.$toast(res.data.msg);
         }
-      },
-      // 关闭APP
-      closeYs2() {
-        this.isYsShow = false;
-        this.showYs = false;
-        if (window.plus) {
-          plus.runtime.quit();
+      });
+    },
+    openUrl2(account_site, invitation_wait_count) {
+      if (account_site.length > 0) {
+        // 公司数量
+        if (invitation_wait_count > 0) {
+          this.$router.push({
+            name: "registration_experience",
+            query: {
+              invite: 1,
+              iscompany: 1
+            }
+          }); // 选择行业
+        } else {
+          this.$router.push({
+            name: "login_company_list"
+          }); // 选择企业
         }
-      },
-      // 关闭隐私
-      closeYs() {
-        localStorage.setItem('isYsShow', true);
-        this.isYsShow = true;
-        this.showYs = false;
-      },
+      } else {
+        if (invitation_wait_count > 0) {
+          // 待邀请数量
+          this.$router.push({
+            name: "registration_experience",
+            query: {
+              invite: 1
+            }
+          }); // 选择行业
+        } else {
+          this.registrationExperience(); //进入体验账号
+        }
+      }
+    },
+    // 关闭APP
+    closeYs2() {
+      this.isYsShow = false;
+      this.showYs = false;
+      if (window.plus) {
+        plus.runtime.quit();
+      }
+    },
+    // 关闭隐私
+    closeYs() {
+      localStorage.setItem("isYsShow", true);
+      this.isYsShow = true;
+      this.showYs = false;
     }
-  };
+  }
+};
 </script>
 
 <style rel="stylesheet/scss" lang="scss" scoped>
-  .contentBox {
-    text-align: center;
-    padding: 50px 0;
-
-    div {
-      font-size: 0.38rem;
-      color: #222;
-    }
-
-    p {
-      font-size: 0.28rem;
-      color: #666;
-    }
-  }
-
-  .bdBtn {
-    width: 80%;
-    padding: 10px;
-    border-radius: 25px;
-    background-image: linear-gradient(117deg, #04b3fb, #31d4ff);
-    color: #fff;
-    margin: 0 auto;
-    margin-bottom: 16px;
-  }
-
-  .popup-all {
-    border-radius: 0.15rem;
-    background: #fff;
-    width: 80%;
-    text-align: center;
-    font-size: 0.32rem;
-
-    .title {
-      padding: 0.2rem 0;
-    }
-
-    .content {
-      font-size: 0.28rem;
-      padding: 0 0.2rem;
-      padding-bottom: 0.2rem;
-      height: 3rem;
-      // overflow-y: scroll;
-    }
-
-    .footer2 div:nth-child(1) {
-      background-color: #ccc;
-      color: #333333;
-      padding: 0.24rem 0;
-      font-size: 0.28rem;
-    }
-
-    .footer2 div:nth-child(2) {
-      background-color: #1989fa;
-      color: #fff;
-      padding: 0.24rem 0;
-      font-size: 0.28rem;
-    }
-  }
-
-  .body_com {
-    background-color: #fff;
-    position: fixed;
-    top: 1rem;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    overflow: auto;
-    z-index: 2;
-  }
-
-  .login_button {
-    height: 1rem;
-    line-height: 0.8rem;
-    border-radius: 0.15rem;
-  }
-
-  .imgLsit img {
-    height: 100%;
-    width: 100%;
-    vertical-align: bottom;
-  }
-
-  .input_focus.login-box {
-    height: calc(100% - 0rem);
-  }
-
-  .login-box {
-    height: calc(100%);
-    position: relative;
-  }
-
-  .login-box-parent .van-field__icon .van-icon {
-    color: #4b0;
-  }
-
-  .login-form-box-bg {
-    position: absolute;
-    top: -0.4rem;
-    left: 0;
-    width: 100%;
-    height: 3.4rem;
-    color: #26a2ff;
-  }
-
-  .login_logo {
-    position: relative;
-    display: block;
-    margin: -1.45rem auto;
-    width: 3.6rem;
-    color: #fff;
-    margin-bottom: 0rem;
-    z-index: 1;
-  }
-
-  .setp1,
-  .setp2 {
-    padding-bottom: 0.5rem;
-  }
-
-  .login-box-parent .mint-cell.cell-last:before {
-    bottom: 0;
-  }
+.contentBox {
+  text-align: center;
+  padding: 50px 0;
 
-  .login-box .van-cell[data-v-1a0d0fb5]:not(:last-child)::after {
-    border: none;
-    border-bottom: 0.02rem #efefef solid;
-    transform: scaleY(0.5);
-    left: 0.32rem;
-    right: 0.32rem;
+  div {
+    font-size: 0.38rem;
+    color: #222;
   }
 
-  .login-box .login-form-box .tel {
-    font-size: 0.32rem;
-    margin-bottom: 0.16rem;
-    padding: 0.2rem 0.32rem;
-    line-height: 0.5rem;
-  }
-
-  .login-box .login-form-box .tel .login_tel {
-    width: 0.37rem;
-    height: 0.37rem;
-    color: #b8b8b8;
-    margin-top: -0.06rem;
-    margin-left: -0.06rem;
-    padding-right: 0rem;
-    border-right: none;
-  }
-
-  .login-box .login-form-box .psw {
-    font-size: 0.32rem;
-    margin-bottom: 0.16rem;
-    padding: 0.2rem 0.32rem;
-    line-height: 0.5rem;
-  }
-
-  .login-box .login-form-box .psw .login_pwd {
-    width: 0.37rem;
-    height: 0.37rem;
-    color: #b8b8b8;
-    margin-top: -0.05rem;
-    margin-left: -0.06rem;
-    padding-right: 0rem;
-    border-right: none;
-  }
-
-  /deep/ .login-box input {
-    font-size: 0.4rem !important;
-    color: #1c1c1c;
-    letter-spacing: 0.005rem;
-  }
-
-  .login-box ::-webkit-input-placeholder {
-    font-size: 0.32rem;
-    color: #b8b8b8 !important;
-    letter-spacing: 0.005rem;
-  }
-
-  .login-box input:-ms-input-placeholder {
-    font-size: 0.32rem;
-    color: #b8b8b8 !important;
-    letter-spacing: 0.005rem;
-  }
-
-  .login-box ::-moz-input-placeholder {
-    font-size: 0.32rem;
-    color: #b8b8b8 !important;
-    letter-spacing: 0.005rem;
-  }
-
-  // .login-box .field-focus ::-webkit-input-placeholder{
-  //   color:#238cf9 !important;
-  // }
-  // .login-box input:-ms-input-placeholder {
-  //    color:#238cf9 !important;
-  //  }
-  // .login-box .field-focus ::-moz-input-placeholder {
-  //   color:#238cf9 !important;
-  // }
-  // .login-box .field-focus .login_tel{
-  //   color:#238cf9 !important;
-  // }
-  // .login-box .field-focus .login_pwd {
-  //   color:#238cf9 !important;
-  // }
-  .login-box .van-hairline--top-bottom:after {
-    border: none;
-    border-bottom: 0.02rem #efefef solid;
-    transform: scaleY(0.5);
-    left: 0.32rem;
-    right: 0.32rem;
-  }
-
-  .login-box .van-hairline-unset--top-bottom:after {
-    border: none;
-    border-bottom: 0.02rem #efefef solid;
-    transform: scaleY(0.5);
-    left: 0.32rem;
-    right: 0.32rem;
-  }
-
-  // /deep/ .login-box .field-focus:after {
-  //   border-bottom: 0.02rem #238cf9 solid !important;
-  // }
-  .login-box .van-row {
-    margin-top: 0.08rem;
+  p {
     font-size: 0.28rem;
+    color: #666;
   }
-
-  .login-box .van-row .van-col:not(:last-child) {
-    color: #9e9da3;
-  }
-
-  .login-box .van-row .van-col {
-    color: #28a2f1;
-    letter-spacing: 0.005rem;
+}
+
+.bdBtn {
+  width: 80%;
+  padding: 10px;
+  border-radius: 25px;
+  background-image: linear-gradient(117deg, #04b3fb, #31d4ff);
+  color: #fff;
+  margin: 0 auto;
+  margin-bottom: 16px;
+}
+
+.popup-all {
+  border-radius: 0.15rem;
+  background: #fff;
+  width: 80%;
+  text-align: center;
+  font-size: 0.32rem;
+
+  .title {
+    padding: 0.2rem 0;
   }
 
-  .login-box .login_button {
-    height: 1rem;
-    line-height: 0.8rem;
-    border-radius: 0.04rem;
+  .content {
+    font-size: 0.28rem;
+    padding: 0 0.2rem;
+    padding-bottom: 0.2rem;
+    height: 3rem;
+    // overflow-y: scroll;
   }
 
-  .footer {
+  .footer2 div:nth-child(1) {
+    background-color: #ccc;
+    color: #333333;
+    padding: 0.24rem 0;
     font-size: 0.28rem;
-    line-height: 1rem;
-    text-align: center;
-    letter-spacing: 0.005rem;
-    margin-bottom: 0.5rem;
   }
 
-  .footer a {
-    color: #1989fa;
+  .footer2 div:nth-child(2) {
+    background-color: #1989fa;
+    color: #fff;
+    padding: 0.24rem 0;
+    font-size: 0.28rem;
   }
+}
+
+.body_com {
+  background-color: #fff;
+  position: fixed;
+  top: 1rem;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  overflow: auto;
+  z-index: 2;
+}
+
+.login_button {
+  height: 1rem;
+  line-height: 0.8rem;
+  border-radius: 0.15rem;
+}
+
+.imgLsit img {
+  height: 100%;
+  width: 100%;
+  vertical-align: bottom;
+}
+
+.input_focus.login-box {
+  height: calc(100% - 0rem);
+}
+
+.login-box {
+  height: calc(100%);
+  position: relative;
+}
+
+.login-box-parent .van-field__icon .van-icon {
+  color: #4b0;
+}
+
+.login-form-box-bg {
+  position: absolute;
+  top: -0.4rem;
+  left: 0;
+  width: 100%;
+  height: 3.4rem;
+  color: #26a2ff;
+}
+
+.login_logo {
+  position: relative;
+  display: block;
+  margin: -1.45rem auto;
+  width: 3.6rem;
+  color: #fff;
+  margin-bottom: 0rem;
+  z-index: 1;
+}
+
+.setp1,
+.setp2 {
+  padding-bottom: 0.5rem;
+}
+
+.login-box-parent .mint-cell.cell-last:before {
+  bottom: 0;
+}
+
+.login-box .van-cell[data-v-1a0d0fb5]:not(:last-child)::after {
+  border: none;
+  border-bottom: 0.02rem #efefef solid;
+  transform: scaleY(0.5);
+  left: 0.32rem;
+  right: 0.32rem;
+}
+
+.login-box .login-form-box .tel {
+  font-size: 0.32rem;
+  margin-bottom: 0.16rem;
+  padding: 0.2rem 0.32rem;
+  line-height: 0.5rem;
+}
+
+.login-box .login-form-box .tel .login_tel {
+  width: 0.37rem;
+  height: 0.37rem;
+  color: #b8b8b8;
+  margin-top: -0.06rem;
+  margin-left: -0.06rem;
+  padding-right: 0rem;
+  border-right: none;
+}
+
+.login-box .login-form-box .psw {
+  font-size: 0.32rem;
+  margin-bottom: 0.16rem;
+  padding: 0.2rem 0.32rem;
+  line-height: 0.5rem;
+}
+
+.login-box .login-form-box .psw .login_pwd {
+  width: 0.37rem;
+  height: 0.37rem;
+  color: #b8b8b8;
+  margin-top: -0.05rem;
+  margin-left: -0.06rem;
+  padding-right: 0rem;
+  border-right: none;
+}
+
+/deep/ .login-box input {
+  font-size: 0.4rem !important;
+  color: #1c1c1c;
+  letter-spacing: 0.005rem;
+}
+
+.login-box ::-webkit-input-placeholder {
+  font-size: 0.32rem;
+  color: #b8b8b8 !important;
+  letter-spacing: 0.005rem;
+}
+
+.login-box input:-ms-input-placeholder {
+  font-size: 0.32rem;
+  color: #b8b8b8 !important;
+  letter-spacing: 0.005rem;
+}
+
+.login-box ::-moz-input-placeholder {
+  font-size: 0.32rem;
+  color: #b8b8b8 !important;
+  letter-spacing: 0.005rem;
+}
+
+// .login-box .field-focus ::-webkit-input-placeholder{
+//   color:#238cf9 !important;
+// }
+// .login-box input:-ms-input-placeholder {
+//    color:#238cf9 !important;
+//  }
+// .login-box .field-focus ::-moz-input-placeholder {
+//   color:#238cf9 !important;
+// }
+// .login-box .field-focus .login_tel{
+//   color:#238cf9 !important;
+// }
+// .login-box .field-focus .login_pwd {
+//   color:#238cf9 !important;
+// }
+.login-box .van-hairline--top-bottom:after {
+  border: none;
+  border-bottom: 0.02rem #efefef solid;
+  transform: scaleY(0.5);
+  left: 0.32rem;
+  right: 0.32rem;
+}
+
+.login-box .van-hairline-unset--top-bottom:after {
+  border: none;
+  border-bottom: 0.02rem #efefef solid;
+  transform: scaleY(0.5);
+  left: 0.32rem;
+  right: 0.32rem;
+}
+
+// /deep/ .login-box .field-focus:after {
+//   border-bottom: 0.02rem #238cf9 solid !important;
+// }
+.login-box .van-row {
+  margin-top: 0.08rem;
+  font-size: 0.28rem;
+}
+
+.login-box .van-row .van-col:not(:last-child) {
+  color: #9e9da3;
+}
+
+.login-box .van-row .van-col {
+  color: #28a2f1;
+  letter-spacing: 0.005rem;
+}
+
+.login-box .login_button {
+  height: 1rem;
+  line-height: 0.8rem;
+  border-radius: 0.04rem;
+}
+
+.footer {
+  font-size: 0.28rem;
+  line-height: 1rem;
+  text-align: center;
+  letter-spacing: 0.005rem;
+  margin-bottom: 0.5rem;
+}
+
+.footer a {
+  color: #1989fa;
+}
 </style>

+ 41 - 5
src/view/user/login_company_list.vue

@@ -1,6 +1,12 @@
 <template>
   <div>
-    <van-nav-bar title="我的组织" left-text="返回" @click-left="$route_back" left-arrow></van-nav-bar>
+    <van-nav-bar title="我的组织" left-text="返回" @click-left="$route_back" left-arrow>
+      <!-- <template slot="right" class="department_right_nav">
+        <van-dropdown-menu  duration="0.3" text="text"  class="head_dropdown_menu">
+          <van-dropdown-item title="•••"  @change="plus_menu" :options="option" />
+        </van-dropdown-menu>
+      </template> -->
+    </van-nav-bar>
     <div class="body_com has_header">
       <scroller>
         <div v-for="(item, index) in list" :key="index" style="padding-top:0.2rem; padding-left:0.2rem; padding-right:0.2rem;">
@@ -21,16 +27,17 @@
 import { getToken, setToken } from '@/utils/auth';
 import Vue from 'vue';
 import moment from 'moment';
-import { Panel } from 'vant';
+import { Panel,DropdownMenu,DropdownItem } from 'vant';
 
-Vue.use(Panel);
+Vue.use(Panel).use(DropdownMenu).use(DropdownItem);
 
 export default {
   name: 'login_company_list',
   data() {
     return {
       page: 0,
-      list: []
+      list: [],
+      option: [{ text: '账号注销', value: 1 }],
     };
   },
   filters: {
@@ -38,10 +45,18 @@ export default {
       return moment(time * 1000).format('YYYY-MM-DD HH:mm:ss');
     }
   },
-  created() {
+  // created() {
+  //   this.get_site_list();
+  // },
+  activated(){
     this.get_site_list();
   },
   methods: {
+    plus_menu (val) {
+      if (val) {
+        this.$router.push('/verify')
+      }
+    },
     get_site_list() {
       this.$toast.loading({
         mask: false,
@@ -90,4 +105,25 @@ export default {
   color: #1c1c1c;
   font-weight: bold;
 }
+.text{
+  text-align: center;
+  color: #969799;
+  font-size: 0.28rem;
+  padding: 0.2rem 0;
+}
+/deep/ .van-dropdown-menu__bar {
+  background-color: transparent;
+}
+/deep/ .van-dropdown-menu__title{
+  color: #FFF;
+}
+/deep/ .van-dropdown-menu__title::after{
+  display: none;
+}
+/deep/ .van-nav-bar__right{
+  overflow: hidden;
+}
+/deep/ .van-dropdown-menu__title--active{
+  color: #FFF!important;
+}
 </style>

+ 3 - 1
src/view/user/regWx.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="login-box-parent" style="background:#fff;">
-    <van-nav-bar title="手机号验证">
+    <van-nav-bar left-text="返回" @click-left="$router.push('/login')" left-arrow title="手机号验证">
       <div slot="right" @click="$router.push({ name: 'login' })" style="display:none;">登录</div>
     </van-nav-bar>
 
@@ -139,6 +139,7 @@ export default {
             let data=res.data.data;
             this.$toast("已绑定")
             localStorage.setItem('a-token-temp', data.token); // 保存平台账号登录的token
+            localStorage.setItem('a-token-tel', data.account.tel);
             this.openUrl(data.account_site,data.invitation_wait_count);
          }).finally(() => {this.reg_loading = false})
       }else{ //未绑定
@@ -190,6 +191,7 @@ export default {
           this.$toast("已注册")
           let data=res.data.data;
           localStorage.setItem('a-token-temp', data.token); // 保存平台账号登录的token
+          localStorage.setItem('a-token-tel', data.account.tel); // 保存平台账号登录的手机号
           this.openUrl(data.account_site,data.invitation_wait_count);
       }).finally(() => {this.reg_loading = false})
     },

+ 5 - 1
src/view/user/registration_experience.vue

@@ -118,7 +118,11 @@ export default {
         if (this.$route.query.iscompany) {
           this.$router.replace({ name: 'login_company_list' });
         } else {
-          this.$router.replace({name:'create_company'})
+          if (window.plus&&(navigator.userAgent.indexOf('iPhone') > 0)) {
+            this.$router.replace({name:'login'})
+          } else {
+            this.$router.replace({name:'create_company'})
+          }
         }
       });
     },

+ 28 - 4
src/view/user/verify.vue

@@ -1,6 +1,6 @@
 <template>
   <div style="height: 100vh;background-color: #fff;">
-    <van-nav-bar title="注销账号" left-text="返回" @click-left="$route_back" left-arrow/>
+    <van-nav-bar title="账号注销" left-text="返回" @click-left="$route_back" left-arrow/>
     <div class="all">
       <div style="text-align: center;margin-bottom: 0.3rem;"><img src="static/images/e66f.jpg" class="img" /></div>
       <div class="text">
@@ -13,7 +13,8 @@
           所有数据将被抹除且不可恢复,请谨慎操作!
         </div>
       </div>
-      <van-button @click="verify" type="primary" style="background-color: #F25542;border:1px solid #F25542;border-radius: 3px;" block >注销</van-button>
+      <van-button v-if="canNext" @click="$route_back" style="background-color: #26A2FF;border:1px solid #26A2FF;border-radius: 3px;color: #FFF;" block >我知道了</van-button>
+      <van-button v-else @click="verify" style="background-color: #26A2FF;border:1px solid #26A2FF;border-radius: 3px;color: #FFF;" block >注销</van-button>
     </div>
   </div>
 </template>
@@ -22,7 +23,12 @@
 export default {
   name: 'verify',
   data () {
-    return {}
+    return {
+      canNext:false
+    }
+  },
+  activated(){
+    this.get_site_list()
   },
   methods: {
     verify () {
@@ -33,7 +39,25 @@ export default {
       }).catch(() => {
         // on cancel
       })
-    }
+    },
+    get_site_list() {
+      this.$toast.loading({
+        mask: false,
+        message: '获取企业信息'
+      });
+      this.$axios('get', '/api/pro/account/site', '', 'token').then(res => {
+        this.$toast.clear();
+        if (res.data.code === 1) {
+          if (res.data.data.length > 0) {
+            this.canNext = true;
+          }else{
+            this.canNext = false;
+          }
+        } else {
+          console.log("获取企业失败")
+        }
+      });
+    },
   }
 }
 </script>

+ 176 - 102
src/view/user/wxInit.vue

@@ -2,7 +2,7 @@
   <div class="all">
     <div class="noData flex-box-v flex-center-center">
       <div class="data-all">
-        <img src="static/images/init.gif" class="appImg"/>
+        <img src="static/images/init.gif" class="appImg" />
       </div>
     </div>
   </div>
@@ -18,147 +18,221 @@
 7.考勤系统审批 (请假,出差,加班,补卡,外出) type=7   考勤审批ID
 8.okr计划 (创建任务指派的,任务审批的) type=8   okr计划ID -->
 <script>
-
-import {getToken} from '@/utils/auth'
+import { getToken, getWxToken, getUserToken } from "@/utils/auth";
+import { getUSerInfo } from "@/view/course/api";
+import router from "../../router";
 export default {
-  name:'wxInit',
+  name: "wxInit",
   data() {
-    return {
-
-    };
+    return {};
   },
   created() {
-    if(this.$isWx){
+    if (this.$isWx) {
       this.init();
-    }else{
-      this.$router.replace({ name: 'home' });
+    } else {
+      this.$router.replace({ name: "home" });
     }
   },
   methods: {
-    init(){
+    init() {
       var url = window.location.href;
-      let request =this.getStr(url)
-      let data={ name: 'home',query:{}};
-      let site_info=this.$getCache('site_info')
-      if(request&&request.type){
-        if(request.type==1||request.type==2){ //微信账号有绑定平台账号
-          if(request.code){
-            this.$axios('POST', '/api/pro/wo/mp/code', { code: request.code }).then(res => {
-                let data=res.data.data;
-                if(data.account_id===0){ //微信未绑定
-                  data={ name: 'regWx',query:{wo_token:data.wo_token}};
-                  this.openUrl(data)
-                }else{
-                  localStorage.setItem('a-token-temp', data.token); // 保存平台账号登录的token
-                  this.openUrl2(data.account_site,data.invitation_wait_count);
-                }
+      let request = this.getStr(url);
+      let data = { name: "home", query: {} };
+      let site_info = this.$getCache("site_info");
+      console.log(request);
+      if (
+        request &&
+        request.type &&
+        !(request.type == 9 || request.type == 10 || request.type == 11)
+      ) {
+        if (request.type == 1 || request.type == 2) {
+          //微信账号有绑定平台账号
+          if (request.code) {
+            this.$axios("POST", "/api/pro/wo/mp/code", {
+              code: request.code
+            }).then(res => {
+              let data = res.data.data;
+              if (data.account_id === 0) {
+                //微信未绑定
+                data = { name: "regWx", query: { wo_token: data.wo_token } };
+                this.openUrl(data);
+              } else {
+                localStorage.setItem("a-token-temp", data.token); // 保存平台账号登录的token
+                localStorage.setItem("a-token-tel", data.account.tel); // 保存平台账号的手机号
+                this.openUrl2(data.account_site, data.invitation_wait_count);
+              }
             });
           }
-          return false
+          return false;
         }
-        if(!getToken()){
-          this.$router.replace({ name: 'home' });
-          return false
+        if (!getToken()) {
+          this.$router.replace({ name: "home" });
+          return false;
         }
         // alert(`传过来的企业ID${request.siteId}当前ID${site_info.id}`)
-        if(request.siteId!=site_info.id){  //企业不一致
-          this.$dialog.alert({
-            title: '提示',
-            message: '当前登录企业与消息企业不一致,请重新选择企业',
-          }).then(() => {
-             this.$router.replace({ name: 'login_company_list' }); // 选择企业
-          });
-          return false
+        if (request.siteId != site_info.id) {
+          //企业不一致
+          this.$dialog
+            .alert({
+              title: "提示",
+              message: "当前登录企业与消息企业不一致,请重新选择企业"
+            })
+            .then(() => {
+              this.$router.replace({ name: "login_company_list" }); // 选择企业
+            });
+          return false;
         }
-        if(request.type==3){ //指派任务
-          data={ name: 'taskFile',query:{task_id:request.id}};
-          this.openUrl(data)
-        }else if(request.type==4){//接受悬赏任务
-          data={ name: 'task_hall',query:{}};
-          this.openUrl(data)
-        }else if(request.type==5){//现场管理问题整改
-          if(site_info.sm&&site_info.sm.enable){
-            data={ name: 'issueTaskDetail',query:{id:request.id}};
-            this.openUrl(data)
-          }else{
-            this.openHome('现场管理模块未开通,请联系管理员开通使用。')
+        if (request.type == 3) {
+          //指派任务
+          data = { name: "taskFile", query: { task_id: request.id } };
+          this.openUrl(data);
+        } else if (request.type == 4) {
+          //接受悬赏任务
+          data = { name: "task_hall", query: {} };
+          this.openUrl(data);
+        } else if (request.type == 5) {
+          //现场管理问题整改
+          if (site_info.sm && site_info.sm.enable) {
+            data = { name: "issueTaskDetail", query: { id: request.id } };
+            this.openUrl(data);
+          } else {
+            this.openHome("现场管理模块未开通,请联系管理员开通使用。");
           }
-        }else if(request.type==6){//积分审批
-          data={ name: 'approval_detail',query:{review_id:request.id}};
-          this.openUrl(data)
-        }else if(request.type==7){//考勤系统审批
-          data={ name: 'RecordDetail',query:{id:request.id}};
-          this.openUrl(data)
-        }else if(request.type==8){//okr计划
-          if(site_info.okr && site_info.okr.enable){
-            this.getUnitList(()=>{
-              data={ name: 'taskDetail',query:{id:request.id}};
-              this.openUrl(data)
-            })
-          }else{
-            this.openHome('OKR模块未开通,请联系管理员开通使用。')
+        } else if (request.type == 6) {
+          //积分审批
+          data = { name: "approval_detail", query: { review_id: request.id } };
+          this.openUrl(data);
+        } else if (request.type == 7) {
+          //考勤系统审批
+          data = { name: "RecordDetail", query: { id: request.id } };
+          this.openUrl(data);
+        } else if (request.type == 8) {
+          //okr计划
+          if (site_info.okr && site_info.okr.enable) {
+            this.getUnitList(() => {
+              data = { name: "taskDetail", query: { id: request.id } };
+              this.openUrl(data);
+            });
+          } else {
+            this.openHome("OKR模块未开通,请联系管理员开通使用。");
           }
         }
+      } else if (
+        request &&
+        request.type &&
+        (request.type == 9 || request.type == 10 || request.type == 11)
+      ) {
+        if (request.code) {
+          this.$axios("POST", "/api/pro/wo/mp/code", {
+            code: request.code
+          }).then(res => {
+            let data = res.data.data;
+            //微信已经绑定
+            localStorage.setItem("Wx-Token", data.wo_token); // 保存平台账号登录的token
+            getUSerInfo(data.wo_token).then(ress => {
+              localStorage.setItem("wx_user_info", JSON.stringify(ress));
+              if (
+                request.type == 10 &&
+                request.pid != undefined &&
+                !ress.marketable
+              ) {
+                this.$router.push(`/courseLogin?pid=${request.pid}`);
+              } else if (
+                request.type == 11 &&
+                request.expendCode &&
+                request.subjectId
+              ) {
+                this.$router.push({
+                  path: `/courseDetail/${request.subjectId}`,
+                  query: {
+                    code: request.expendCode
+                  }
+                });
+              } else if(sessionStorage.getItem('cur_path')){
+                this.$router.push(sessionStorage.getItem('cur_path')).then(()=>{
+                  sessionStorage.removeItem('cur_path')
+                })
+              }else{
+                this.$router.push("/courseHome");
+              }
+            });
+          });
+        }
       }
     },
-    getUnitList(fun){
-      this.$axiosUser('get', '/api/pro/okr/kr/unit_list').then(res => {
-        let data=res.data.data;
-        data.reverse()
-        this.$setCache('unitList',data)
-        fun()
-      })
+    getUnitList(fun) {
+      this.$axiosUser("get", "/api/pro/okr/kr/unit_list").then(res => {
+        let data = res.data.data;
+        data.reverse();
+        this.$setCache("unitList", data);
+        fun();
+      });
     },
     getStr(urlStr) {
-    	if (typeof urlStr == 'undefined') {
-    		var url = decodeURI(location.search); //获取url中"?"符后的字符串
-    	} else {
-    		var url = '?' + urlStr.split('?')[1];
-    	}
-    	var theRequest = new Object();
-    	var strs;
-    	if (url.indexOf('?') != -1) {
-    		var str = url.substr(1);
-    		strs = str.split('&');
-    		for (var i = 0; i < strs.length; i++) {
-    			theRequest[strs[i].split('=')[0]] = decodeURI(strs[i].split('=')[1]);
-    		}
-    	}
-    	return theRequest;
+      if (typeof urlStr == "undefined") {
+        var url = decodeURI(location.search); //获取url中"?"符后的字符串
+      } else {
+        var url = "?" + urlStr.split("?")[1];
+      }
+      var theRequest = new Object();
+      var strs;
+      if (url.indexOf("?") != -1) {
+        var str = url.substr(1);
+        strs = str.split("&");
+        for (var i = 0; i < strs.length; i++) {
+          theRequest[strs[i].split("=")[0]] = decodeURI(strs[i].split("=")[1]);
+        }
+      }
+      return theRequest;
     },
-    openUrl(data){
-      data.query.isHome=true;
+    openUrl(data) {
+      data.query.isHome = true;
       this.$router.replace(data);
     },
     openUrl2(account_site, invitation_wait_count) {
       if (account_site.length > 0) {
         // 公司数量
         if (invitation_wait_count > 0) {
-          this.$router.push({ name: 'registration_experience', query: { invite: 1, iscompany: 1 } }); // 选择行业
+          this.$router.push({
+            name: "registration_experience",
+            query: { invite: 1, iscompany: 1 }
+          }); // 选择行业
         } else {
-          this.$router.push({ name: 'login_company_list' }); // 选择企业
+          this.$router.push({ name: "login_company_list" }); // 选择企业
         }
       } else {
         if (invitation_wait_count > 0) {
           // 待邀请数量
-          this.$router.push({ name: 'registration_experience', query: { invite: 1 } }); // 选择行业
+          this.$router.push({
+            name: "registration_experience",
+            query: { invite: 1 }
+          }); // 选择行业
         } else {
-          this.$router.replace({name:'create_company'}) //进入体验账号
+          if (window.plus&&(navigator.userAgent.indexOf('iPhone') > 0)) {
+            this.$router.replace({
+              name: 'iosIntercept'
+            })
+          } else {
+            this.$router.replace({
+              name: 'create_company'
+            })
+          }
+          // this.$router.replace({ name: "create_company" }); //进入体验账号
         }
       }
     },
     openHome(msg) {
-      this.$dialog.alert({
-        title: '提示',
-        message: msg,
-      }).then(() => {
-         this.$router.replace({ name: 'home' }); // 选择企业
-      });
-    },
-  },
-  activated() {
-
+      this.$dialog
+        .alert({
+          title: "提示",
+          message: msg
+        })
+        .then(() => {
+          this.$router.replace({ name: "home" }); // 选择企业
+        });
+    }
   },
+  activated() {}
 };
 </script>
 

TEMPAT SAMPAH
static/images/course_dingdan.png


TEMPAT SAMPAH
static/images/course_ewm.png


TEMPAT SAMPAH
static/images/course_logo.png


TEMPAT SAMPAH
static/images/course_team.png