81 Commits 6ead56ddc6 ... f3f9ed35cd

Author SHA1 Message Date
  walter f3f9ed35cd 合并 11 months ago
  walter 5e0c37ac62 优化 11 months ago
  walter 9989350d9c 优化 11 months ago
  walter 351b699cd1 审批 11 months ago
  walter 7be876ca40 文案 11 months ago
  walter 56804c8118 规则范围组件 11 months ago
  walter 834f773bfe 审批拦截 11 months ago
  walter 1798e2fbad 规则选择器 11 months ago
  walter 29f511cfc3 日期组件 11 months ago
  walter 5726c65dc4 任务/悬赏/模板新增积分规则选项 11 months ago
  walter 477c1a90fb 特殊字符,优化 11 months ago
  walter 3fccb6413c 优化 1 year ago
  walter 7b4fc433e1 优化 1 year ago
  walter 4ab9e467a2 优化 1 year ago
  walter 3684351431 优化 1 year ago
  walter 90dc56f6d5 优化 1 year ago
  walter 6a7abe4beb 优化 1 year ago
  walter 6d5f49f4fb 优化 1 year ago
  walter 7af0d33fec 优化 1 year ago
  walter bff47f4a33 优化 1 year ago
  walter 8975b16b6e 审批驳回/积分申诉 1 year ago
  walter a6b3aaadca 审批驳回/积分申诉 1 year ago
  walter 1c09aa309f 重复任务详情 1 year ago
  walter 42180588ff 版本后缀 1 year ago
  walter 6bd967c125 优化 1 year ago
  walter b9b141256a 优化 1 year ago
  walter 069fca029f 审批奖票 1 year ago
  walter e71e91e83b 优化 1 year ago
  walter aa7d121def 部门排名 1 year ago
  walter d36130beca 部门排名 1 year ago
  walter c229f231d5 奖扣查询/审批详情/积分事件列表 1 year ago
  walter cf939de44d 合并 1 year ago
  walter 1847f754e7 团队PK 1 year ago
  walter 8d70a48109 团队PK 1 year ago
  walter 62e9bf412c 团队PK 1 year ago
  walter afc36f5c37 团队PK 1 year ago
  walter bef31fd87f 团队PK 1 year ago
  guojy 9eac5f4047 8.1.8_2 1 year ago
  guojy d790eaf795 Merge branch 'course-dev' into dev 1 year ago
  guojy 2ea6f2c249 8.1.8_2 1 year ago
  guojy 03ac6d69e3 8.1.8细节_1 1 year ago
  guojy 5c2702c265 update_4 1 year ago
  guojy a1a5cfe709 update_9 1 year ago
  guojy e51491e9a7 update_3 1 year ago
  guojy a8b9e8d3ff update_8 1 year ago
  guojy b7bd11cb0f update_2 1 year ago
  guojy 97c5af60f1 update_8 1 year ago
  guojy e7ac51ecaf update_1 1 year ago
  guojy d90302c193 朋友圈分享 1 year ago
  guojy 9dca1bb132 注销+苹果无邀请无创建跳转中间页 1 year ago
  guojy aab971c62b update_7 1 year ago
  guojy e64ef27404 update_6 1 year ago
  guojy a7a5ec77e1 分享的返回上一页 1 year ago
  guojy 436ff6e513 update_5 1 year ago
  guojy 4d72558cea updata_3 1 year ago
  guojy 038a291128 updata_1 1 year ago
  guojy eec9602419 qr2img_next 1 year ago
  guojy 3ab6ab7981 test_14 1 year ago
  guojy f9b989f67f test_12 1 year ago
  guojy 564887355c 禁止视频下载/禁止PC微信登录 1 year ago
  guojy 57897af099 test_12 1 year ago
  guojy 297ea350be test_10 1 year ago
  guojy b7b2df6719 test_10 1 year ago
  guojy b5d8b593cd 321 1 year ago
  guojy 261ec9dc54 test_9 1 year ago
  guojy 756dd26b96 test_7 1 year ago
  guojy dcca4c3058 test_6 1 year ago
  guojy b4fa95cb83 test_4 1 year ago
  guojy fba73bd110 test_3 1 year ago
  guojy e74b3b1ac2 test_2 1 year ago
  guojy 97db27a14b tets_end1 1 year ago
  guojy 5977300f3c 3 1 year ago
  guojy 1a71185f51 321 1 year ago
  guojy 560efb7021 post_1 1 year ago
  guojy ad977913c3 page_end 1 year ago
  guojy c4aa06e9b9 123 1 year ago
  guojy 33adec39e6 page_add 1 year ago
  guojy 74a9f8dd0e page_updata 1 year ago
  guojy 5909a2b6bc dealPage 1 year ago
  guojy 76d5137b98 course_setting&&courese_home_page 1 year ago
  guojy 4943015f07 course_first 1 year ago
100 changed files with 12625 additions and 1165 deletions
  1. 1 0
      .gitignore
  2. 1 0
      build/webpack.dev.conf.js
  3. 1 1
      build/webpack.prod.conf.js
  4. 2 2
      config/index.js
  5. 68 0
      package-lock.json
  6. 6 2
      package.json
  7. 3 3
      src/App.vue
  8. 13 1
      src/api/websocketTow.js
  9. 29 0
      src/assets/iconfont.css
  10. BIN
      src/assets/images/courseLogin.png
  11. BIN
      src/assets/images/courseUser.png
  12. BIN
      src/assets/images/headLogo.jpg
  13. 727 0
      src/components/AppealInfo.vue
  14. 253 0
      src/components/AppealRewrite.vue
  15. 5 0
      src/components/CategorySelectorCell.vue
  16. 10 2
      src/components/DeptSelectorBtn.vue
  17. 1 1
      src/components/EmployeeSelector.vue
  18. 30 0
      src/components/IntegralEventSelector.vue
  19. 6 2
      src/components/Mtextarea.vue
  20. 7 3
      src/components/Mtextarea2.vue
  21. 1 1
      src/components/NumberInput.vue
  22. 79 3
      src/components/RuleCategorySelector.vue
  23. 44 5
      src/components/RuleCategorySelector1.vue
  24. 17 9
      src/components/RuleCategorySelectorCell1.vue
  25. 5 5
      src/components/TabsList.vue
  26. 1 1
      src/components/user_image.vue
  27. 40 36
      src/main.js
  28. 8 1
      src/okr/view/okrHome.vue
  29. 8 1
      src/okr/view/project/projectList.vue
  30. 2 2
      src/okr/view/task/taskDetail.vue
  31. 59 19
      src/permission.js
  32. 22 14
      src/point/view/audit/integralAudit.vue
  33. 365 0
      src/point/view/integral/appealList.vue
  34. 141 28
      src/point/view/integral/approval_detail.vue
  35. 42 17
      src/point/view/integral/approval_list.vue
  36. 66 11
      src/point/view/integral/approval_process.vue
  37. 4 4
      src/point/view/integral/batchList.vue
  38. 272 0
      src/point/view/integral/deptRank.vue
  39. 98 7
      src/point/view/integral/event_detail.vue
  40. 49 10
      src/point/view/integral/event_list.vue
  41. 1 1
      src/point/view/integral/integral_application.vue
  42. 2 2
      src/point/view/integral/integral_entry_n.vue
  43. 2 2
      src/point/view/integral/manager_reward_deduction.vue
  44. 336 0
      src/point/view/integral/reward_deduction_search.vue
  45. 5 1
      src/point/view/integral/rule_category_add.vue
  46. 6 2
      src/point/view/integral/rule_category_edit.vue
  47. 5 1
      src/point/view/integral/rule_item_add.vue
  48. 6 1
      src/point/view/integral/rule_item_edit.vue
  49. 242 15
      src/point/view/pointHome.vue
  50. 529 0
      src/point/view/task/TaskEdit.vue
  51. 520 0
      src/point/view/task/WorkEdit.vue
  52. 14 2
      src/point/view/task/my_publish.vue
  53. 4 3
      src/point/view/task/my_task.vue
  54. 297 66
      src/point/view/task/repetitive_tasks_detail.vue
  55. 209 16
      src/point/view/task/short_task.vue
  56. 341 122
      src/point/view/task/taskFile.vue
  57. 188 43
      src/point/view/task/task_detail_a.vue
  58. 225 30
      src/point/view/task/temp_task.vue
  59. 102 0
      src/router/course.js
  60. 9 0
      src/router/index.js
  61. 37 0
      src/router/pointRoute.js
  62. 4 1
      src/store/getters.js
  63. 2 1
      src/store/modules/user.js
  64. 51 0
      src/utils/auth.js
  65. 167 0
      src/utils/axiosKc.js
  66. 13 5
      src/utils/axiosUser.js
  67. 3 0
      src/utils/helper.js
  68. 3 1
      src/utils/validator.js
  69. 338 0
      src/view/course/api/index.js
  70. 159 0
      src/view/course/components/CourseTeam.vue
  71. 296 0
      src/view/course/components/courseList.vue
  72. 203 0
      src/view/course/deal/dealOrder.vue
  73. 172 0
      src/view/course/deal/limitRecord.vue
  74. 257 0
      src/view/course/deal/transfer.vue
  75. 33 0
      src/view/course/error.vue
  76. 238 0
      src/view/course/home.vue
  77. 546 0
      src/view/course/user.vue
  78. 439 0
      src/view/course/user/courseAdDeal.vue
  79. 423 0
      src/view/course/user/courseDeal.vue
  80. 403 0
      src/view/course/user/deal.vue
  81. 208 0
      src/view/course/user/login.vue
  82. 160 0
      src/view/course/user/team.vue
  83. 155 0
      src/view/course/user/wxAuth.vue
  84. 591 0
      src/view/course/user_qr2img_next.vue
  85. 266 0
      src/view/course/utils/convas2Images.js
  86. 152 0
      src/view/course/utils/index.js
  87. 16 0
      src/view/course/utils/navBar.scss
  88. 338 0
      src/view/course/video/courseVideo.vue
  89. 310 0
      src/view/course/video/freeVideo.vue
  90. 4 2
      src/view/system/about.vue
  91. 2 0
      src/view/user/account.vue
  92. 56 64
      src/view/user/accountSet.vue
  93. 9 3
      src/view/user/accountVf.vue
  94. 44 3
      src/view/user/create_company.vue
  95. 222 0
      src/view/user/iosIntercept.vue
  96. 699 576
      src/view/user/login.vue
  97. 41 5
      src/view/user/login_company_list.vue
  98. 3 1
      src/view/user/regWx.vue
  99. 5 1
      src/view/user/registration_experience.vue
  100. 28 4
      src/view/user/verify.vue

+ 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 ?
       {

+ 1 - 1
build/webpack.prod.conf.js

@@ -35,7 +35,7 @@ const webpackConfig = merge(baseWebpackConfig, {
     new BundleAnalyzerPlugin({
       analyzerMode: 'server',
       analyzerHost: '127.0.0.1',
-      analyzerPort: 8889,
+      analyzerPort: 8890,
       reportFilename: 'report.html',
       defaultSizes: 'parsed',
       openAnalyzer: true,

+ 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";
+}

BIN
src/assets/images/courseLogin.png


BIN
src/assets/images/courseUser.png


BIN
src/assets/images/headLogo.jpg


+ 727 - 0
src/components/AppealInfo.vue

@@ -0,0 +1,727 @@
+<template>
+  <van-popup
+    v-model="showAppealInfo"
+    :position="position"
+    duration="0.2"
+    :style="{ height: height, width: width, 'background-color': 'rgb(245, 245, 245)' }"
+    @open="onOpen"
+    @closed="onClosed"
+  >
+    <div style="height: 100%;width: 100%;" >
+      <van-nav-bar
+        title="申诉信息"
+        :left-arrow="true"
+        @click-left="showAppealInfo = false"
+        @click-right="showActions = true"
+        fixed
+      >
+        <template slot="right" v-if="canActions">
+          <van-icon name="bars"/>
+        </template>
+      </van-nav-bar>
+      <div class="container" v-if="appealInfo" >
+        <div class="card-box">
+          <van-row type="flex" justify="center" gutter="10" align="center">
+            <van-col span="6" style="text-align: right">
+              <userImage
+                :img_url="appealInfo.employee_img_url"
+                :user_name="appealInfo.employee_name"
+              />
+            </van-col>
+            <van-col span="10" style="text-align: left" class="font-flex-word">
+              <span style="line-height: 0.8rem;">{{appealInfo.employee_name}}</span>
+            </van-col>
+            <van-col span="8">
+              <van-tag :type="appealStatusType(appealInfo.status)" size="medium" >{{appealStatusMap[appealInfo.status] || '--'}}</van-tag>
+            </van-col>
+          </van-row>
+          <van-divider/>
+          <div class="card-content">
+            <p><van-tag type="primary" size="medium">{{appealInfo.create_time}}</van-tag>&nbsp;发起申诉申请</p>
+            <p>共<van-tag type="primary" size="medium">{{appealInfo.events.length}}</van-tag>&nbsp;条积分事件</p>
+            <p v-if="appealInfo.global_remark">申请原因&nbsp;:&nbsp;<van-tag type="primary" size="medium">{{appealInfo.global_remark}}</van-tag></p>
+            <template v-if="appealInfo.complete_time">
+              <p><van-tag type="primary" size="medium">{{appealInfo.complete_time}}</van-tag>&nbsp;审批结束</p>
+            </template>
+          </div>
+        </div>
+        <van-collapse v-model="activeNames" accordion @change="collapseChange">
+          <van-collapse-item name="process">
+            <template slot="title">
+              <span class="content-font">审批流程</span>
+            </template>
+            <van-steps direction="vertical" :active="appealInfo.process.length - 1" >
+              <van-step v-for="(item,index) in appealInfo.process" :key="index" >
+                <div class="card-box">
+                  <div class="card-content" style="text-align: left;line-height: 0.25rem;">
+                    <p>阶段{{item.step}}&nbsp;<van-tag :type="processStatusType(item.status)" size="medium">{{processStatusMap[item.status] || '--'}}</van-tag></p>
+                    <p>发起人&nbsp;:&nbsp;{{item.publisher_name}}</p>
+                    <p>发起时间&nbsp;:&nbsp;{{item.create_time}}</p>
+                    <p>审批人&nbsp;:&nbsp;{{item.reviewer_name}}</p>
+                    <p v-if="item.remark" class="font-flex-word">审批意见&nbsp;:&nbsp;{{item.remark}}</p>
+                    <p v-if="item.complete_time">完结时间&nbsp;:&nbsp;{{item.complete_time}}</p>
+                  </div>
+                </div>
+              </van-step>
+            </van-steps>
+          </van-collapse-item>
+          <van-collapse-item name="events">
+            <template slot="title">
+              <span class="content-font">{{appealInfo.events.length + '条积分事件'}}</span>
+            </template>
+            <div class="card-box" v-for="(item,index) in appealInfo.events" :key="index">
+              <div class="card-content1">
+                <p>积分&nbsp;:&nbsp;{{item.point + ' ' + ptName(item.pt_id)}} <van-tag :type="pointStatusType(item.status)" >{{pointStatusMap[item.status] || '--'}}</van-tag> </p>
+                <p style="line-height: 0.5rem">积分备注&nbsp;:&nbsp;{{item.event_remark}}</p>
+                <p>时间&nbsp;:&nbsp;{{item.event_time}}</p>
+                <p v-if="item.appeal_remark" >申诉原因&nbsp;:&nbsp;{{item.appeal_remark}}</p>
+                <p v-if="item.delete_time" >已删除&nbsp;:&nbsp;{{item.delete_time}}</p>
+              </div>
+            </div>
+          </van-collapse-item>
+          <van-collapse-item name="logs" :disabled="appealInfo.logs.length === 0">
+            <template slot="title">
+              <span class="content-font">{{appealInfo.logs.length + '条操作日志'}}</span>
+            </template>
+            <p v-for="(item,index) in logs" :key="index" class="content-font font-flex-word">
+              <van-notice-bar
+                left-icon="info-o"
+                color="#1989fa"
+                background="#ecf9ff"
+                :text="item.create_time + item.msg"
+              />
+            </p>
+          </van-collapse-item>
+        </van-collapse>
+      </div>
+    </div>
+
+    <van-action-sheet
+      v-model="showActions"
+      :actions="appealActions"
+      @select="actionSelect"
+      :closeable="false"
+      close-on-click-action
+    />
+
+<!--  审批拒绝  -->
+    <van-dialog
+      v-model="showReviewRefuse"
+      title="审批拒绝"
+      :show-cancel-button="false"
+      :show-confirm-button="false"
+    >
+      <van-form @submit="refuseReview">
+        <van-cell-group>
+          <van-cell><Mtextarea v-model="formData.remark" placeholder="原因说明(选填)"></Mtextarea></van-cell>
+        </van-cell-group>
+        <van-row type="flex" justify="center" gutter="10" style="margin: 0.1rem;">
+          <van-col span="12">
+            <van-button round block type="warning" native-type="button" @click="closeRefuseReview">
+              取消
+            </van-button>
+          </van-col>
+          <van-col span="12">
+            <van-button round block type="info" native-type="submit">
+              提交
+            </van-button>
+          </van-col>
+        </van-row>
+      </van-form>
+    </van-dialog>
+
+<!--  驳回重做  -->
+    <van-dialog
+      v-model="showReviewRejectRewrite"
+      title="驳回重做"
+      :show-cancel-button="false"
+      :show-confirm-button="false"
+    >
+      <van-form @submit="rejectRewrite">
+        <van-cell-group>
+          <van-cell><Mtextarea v-model="formData.remark" placeholder="原因说明(选填)"></Mtextarea></van-cell>
+        </van-cell-group>
+
+        <van-row type="flex" justify="center" gutter="10" style="margin: 0.1rem;">
+          <van-col span="12">
+            <van-button round block type="warning" native-type="button" @click="closeRejectRewrite">
+              取消
+            </van-button>
+          </van-col>
+          <van-col span="12">
+            <van-button round block type="info" native-type="submit">
+              提交
+            </van-button>
+          </van-col>
+        </van-row>
+      </van-form>
+    </van-dialog>
+
+
+<!--  递交审批  -->
+    <van-dialog
+      v-model="showReviewSubmit"
+      title="递交审批"
+      :show-cancel-button="false"
+      :show-confirm-button="false"
+    >
+      <van-form @submit="reviewSubmit">
+        <van-cell-group>
+          <EmployeeSelectorCell
+            title="递交审批"
+            v-model="formData.reviewer"
+            :multi="false"
+            icon-type="records"
+            :employee_list="userInfo.employee_detail.superior_list"
+            :is_employee_list="true"
+          />
+        </van-cell-group>
+
+        <van-cell-group>
+          <van-cell><Mtextarea v-model="formData.remark" placeholder="原因说明(选填)"></Mtextarea></van-cell>
+        </van-cell-group>
+
+        <van-row type="flex" justify="center" gutter="10" style="margin: 0.1rem;">
+          <van-col span="12">
+            <van-button round block type="warning" native-type="button" @click="closeReviewSubmit">
+              取消
+            </van-button>
+          </van-col>
+          <van-col span="12">
+            <van-button round block type="info" native-type="submit">
+              提交
+            </van-button>
+          </van-col>
+        </van-row>
+      </van-form>
+    </van-dialog>
+
+<!--  审批通过  -->
+    <van-dialog
+      v-model="showReviewApproval"
+      title="通过"
+      :show-cancel-button="false"
+      :show-confirm-button="false"
+    >
+      <van-form @submit="reviewApproval">
+        <van-cell-group>
+          <van-cell><Mtextarea v-model="formData.remark" placeholder="原因说明(选填)"></Mtextarea></van-cell>
+        </van-cell-group>
+        <van-row type="flex" justify="center" gutter="10" style="margin: 0.1rem;">
+          <van-col span="12">
+            <van-button round block type="warning" native-type="button" @click="closeReviewApproval">
+              取消
+            </van-button>
+          </van-col>
+          <van-col span="12">
+            <van-button round block type="info" native-type="submit">
+              提交
+            </van-button>
+          </van-col>
+        </van-row>
+      </van-form>
+    </van-dialog>
+
+<!--  重新填写  -->
+<!--    <van-dialog-->
+<!--      v-model="showRewrite"-->
+<!--      title="申诉记录"-->
+<!--      :show-cancel-button="false"-->
+<!--      :show-confirm-button="false"-->
+<!--    >-->
+
+<!--    </van-dialog>-->
+    <AppealRewrite
+      v-if="appealInfo"
+      :visible.sync="showRewrite"
+      :id="appealInfo.id"
+      @hasSubmit="handleRewriteSubmit"
+    />
+
+
+  </van-popup>
+</template>
+
+<script>
+import Vue from "vue";
+import {NavBar,Steps,Step,Collapse,CollapseItem,Dialog,NoticeBar} from "vant";
+import EmployeeSelectorCell from "./EmployeeSelectorCell.vue";
+import Mtextarea from "./Mtextarea2.vue";
+import AppealRewrite from "./AppealRewrite.vue";
+Vue.use(NavBar)
+  .use(Steps)
+  .use(Step)
+  .use(Collapse)
+  .use(CollapseItem)
+  .use(Dialog)
+  .use(NoticeBar)
+
+export default {
+  name: 'appealInfo',
+  components: {AppealRewrite, Mtextarea, EmployeeSelectorCell},
+  props: {
+    visible:{
+      type: Boolean,
+      default : false
+    },
+    position:{
+      type: String,
+      default: 'bottom'
+    },
+    id:{
+      type: Number,
+      default: 0
+    },
+    height:{
+      type: String,
+      default: '90%'
+    },
+    width:{
+      type: String,
+      default: '100vw'
+    }
+  },
+  data(){
+    return {
+      userInfo: this.$userInfo(),
+      showAppealInfo:this.visible,
+      hasOpen:false,
+      hasSubmit:false,
+      loading:false,
+      appealInfo:null,
+      appealStatusMap:{
+        0:'全部',
+        1:'审批中',
+        2:'审批通过',
+        3:'驳回重做',
+        4:'撤回重填',
+        5:'拒绝'
+      },
+      pointStatusMap:{
+        1:'正常',
+        2:'已删除',
+        3:'已通过申诉并删除'
+      },
+      processStatusMap:{
+        1:'待处理',
+        2:'审批通过',
+        3:'递交审批',
+        4:'拒绝',
+        5:'驳回重做',
+        6:'撤回上个节点重填',
+        7:'申诉撤回',
+      },
+      pts:this.$getTypes,
+      formData:{
+        remark:'',
+        reviewer:[]
+      },
+      rewriteData:{
+        events:[],
+        globalRemark:'',
+        reviewerId:'',
+        reviewerName:'',
+        employeeSelected: { dept: [], employee: [] },
+      },
+      showReviewRefuse:false,
+      showReviewRejectRewrite:false,
+      showReviewApproval:false,
+      showReviewerSelector:false,
+      showReviewSubmit:false,
+      submitting:false,
+      showEventSelector:false,
+      showRewrite:false,
+      activeNames:'process',
+      showActions:false,
+      actions:{
+        delete:{name:'删除申诉',subname:'删除申诉后将不可恢复',action:'delete',loading:false,disabled:false},
+        refuse:{name:'拒绝',subname:'拒绝申请直接结束申诉流程',action:'refuse',loading:false,disabled:false},
+        rejectRewrite:{name:'驳回重做',subname:'申请人重新填写申诉内容',action:'rejectRewrite',loading:false,disabled:false},
+        cancel:{name:'撤回审批',subname:'撤回重新填写审批信息',action:'cancel',loading:false,disabled:false},
+        cancelAppeal:{name:'撤回申诉',subname:'撤回重新填写申诉内容',action:'cancelAppeal',loading:false,disabled:false},
+        rewrite:{name:'重新填写',subname:'填写申诉内容重新提交',action:'rewrite',loading:false,disabled:false},
+        submit:{name:'递交审批',subname:'递交其他人审批',action:'submit',loading:false,disabled:false},
+        approval:{name:'通过',subname:'通过审批结束申诉流程',action:'approval',loading:false,disabled:false},
+      },
+      logs:[]
+    }
+  },
+  watch:{
+    showAppealInfo(v){
+      this.$emit('update:visible', v)
+    },
+    visible(v){
+      this.showAppealInfo = v
+    }
+  },
+  computed:{
+    appealActions(){
+      let actions = []
+      if (!this.appealInfo) return actions
+      if (this.appealInfo.can_delete) actions.push(this.actions.delete)
+      if (this.appealInfo.can_refuse) actions.push(this.actions.refuse)
+      if (this.appealInfo.can_reject_rewrite) actions.push(this.actions.rejectRewrite)
+      if (this.appealInfo.can_cancel) actions.push(this.actions.cancel)
+      if (this.appealInfo.can_cancel_appeal) actions.push(this.actions.cancelAppeal)
+      if (this.appealInfo.can_rewrite) actions.push(this.actions.rewrite)
+      if (this.appealInfo.can_submit) actions.push(this.actions.submit)
+      if (this.appealInfo.can_approval) actions.push(this.actions.approval)
+      return actions
+    },
+    canActions(){
+      return this.appealActions.length > 0
+    }
+  },
+  methods:{
+    initData(){
+      this.formData.remark = ''
+      this.formData.reviewer = []
+      this.hasSubmit = false
+      this.appealInfo = null
+      this.showReviewRefuse = false
+      this.showReviewRejectRewrite = false
+      this.showReviewApproval = false
+      this.showReviewerSelector = false
+      this.showReviewSubmit = false
+      this.showRewrite = false
+      this.showEventSelector = false
+      this.submitting = false
+    },
+    onOpen(){
+      this.hasOpen = true
+      this.initData()
+      this.getAppealInfo()
+    },
+    onClosed(){
+      this.hasOpen = false
+      this.activeNames = 'process'
+      if (this.hasSubmit) this.$emit('hasSubmit')
+      this.$emit('closeInfo')
+    },
+    getAppealInfo(){
+      if (!this.$props.id) return
+      let self = this
+      self.loading = true
+      self.$axiosUser('get','api/pro/integral/appeal/info',{appeal_id:this.$props.id})
+        .then(res => {
+          if (res.data.code === 1) self.appealInfo = res.data.data
+        })
+        .finally(() => {
+          self.loading = false
+        })
+    },
+    appealStatusType(status){
+      const map = {
+        1:'primary',
+        2:'success',
+        3:'warning',
+        4:'warning',
+        5:'danger'
+      }
+      return map[status] || 'info'
+    },
+    processStatusType(status){
+      const map = {
+        1:'primary',
+        2:'success',
+        3:'success',
+        4:'danger',
+        5:'warning',
+        6:'warning',
+        7:'primary',
+      }
+      return map[status] || 'info'
+    },
+    ptName(ptId){
+      let item = this.pts.find(item => item.id === ptId)
+      return item ? item.name : ''
+    },
+    pointStatusType(status){
+      switch (status){
+        case 2:
+        case 3:
+          return 'warning'
+        default:
+          return "success"
+      }
+    },
+    actionSelect(item){
+      switch (item.action){
+        case 'delete':
+          Dialog.confirm({
+            title:'删除申诉',
+            message:'删除申诉后将不可恢复,确认提交吗',
+            showCancelButton:true,
+            confirmButtonText:'提交',
+            cancelButtonText:'取消',
+          })
+            .then(() => {
+              this.removeAppeal()
+            })
+            .catch(() => {})
+          break;
+        case 'refuse':
+          this.showReviewRefuse = true
+          break;
+        case 'rejectRewrite':
+          this.showReviewRejectRewrite = true
+          break;
+        case 'cancel':
+          Dialog.confirm({
+            title:'撤回审批',
+            message:'审批撤回后可以重新编辑内容重新提交',
+            showCancelButton:true,
+            confirmButtonText:'提交',
+            cancelButtonText:'取消',
+          })
+            .then(() => {
+              this.reviewCancel()
+            })
+            .catch(() => {})
+          break;
+        case 'cancelAppeal':
+          Dialog.confirm({
+            title:'撤回申诉',
+            message:'申诉撤回后可以重新编辑内容重新提交',
+            showCancelButton:true,
+            confirmButtonText:'提交',
+            cancelButtonText:'取消',
+          })
+            .then(() => {
+              this.appealCancel()
+            })
+            .catch(() => {})
+          break;
+        case 'rewrite':
+          this.showRewrite = true
+          break;
+        case 'submit':
+          this.showReviewSubmit = true
+          break;
+        case 'approval':
+          this.showReviewApproval = true
+          break;
+      }
+    },
+    removeAppeal(){
+      if (!this.appealInfo) return
+      let self = this
+      self.submitting = true
+      let params = {
+        appeal_id:self.appealInfo.id
+      }
+      self.$axiosUser('post','api/pro/integral/appeal/remove',params)
+        .then(res => {
+          if (res.data.code === 1){
+            self.hasSubmit = true
+            self.showAppealInfo = false
+          }else {
+            self.$toast(res.data.msg)
+          }
+        })
+        .finally(() => {
+          self.submitting = false
+        })
+    },
+    refuseReview(){
+      if (!this.appealInfo) return
+      let self = this
+      self.submitting = true
+      let params = {
+        appeal_id:self.appealInfo.id,
+        remark:self.formData.remark
+      }
+      self.$axiosUser('post','api/pro/integral/appeal/review/refuse',params)
+        .then(res => {
+          if (res.data.code === 1){
+            self.hasSubmit = true
+            self.getAppealInfo()
+            self.showReviewRefuse = false
+          }else {
+            self.$toast(res.data.msg)
+          }
+        })
+        .finally(() => {
+          self.submitting = false
+        })
+    },
+    closeRefuseReview(){
+      this.showReviewRefuse = false
+    },
+    rejectRewrite(){
+      if (!this.appealInfo) return
+      let self = this
+      self.submitting = true
+      let params = {
+        appeal_id:self.appealInfo.id,
+        remark:self.formData.remark
+      }
+      self.$axiosUser('post','api/pro/integral/appeal/review/reject',params)
+        .then(res => {
+          if (res.data.code === 1){
+            self.hasSubmit = true
+            self.getAppealInfo()
+            self.showReviewRejectRewrite = false
+          }else {
+            self.$toast(res.data.msg)
+          }
+        })
+        .finally(() => {
+          self.submitting = false
+        })
+    },
+    closeRejectRewrite(){
+      this.showReviewRejectRewrite = false
+    },
+    reviewSubmit(){
+      if (!this.appealInfo) return
+      let self = this
+      self.submitting = true
+      let params = {
+        appeal_id:self.appealInfo.id,
+        reviewer_id:self.formData.reviewer[0].id,
+        remark:self.formData.remark
+      }
+      self.$axiosUser('post','api/pro/integral/appeal/review/submit',params)
+        .then(res => {
+          if (res.data.code === 1){
+            self.hasSubmit = true
+            self.getAppealInfo()
+            self.showReviewSubmit = false
+          }else {
+            self.$message.error(res.data.msg)
+          }
+        })
+        .finally(() => {
+          self.submitting = false
+        })
+    },
+    closeReviewSubmit(){
+      this.showReviewSubmit = false
+    },
+    reviewApproval(){
+      if (!this.appealInfo) return
+      let self = this
+      self.submitting = true
+      let params = {
+        appeal_id:self.appealInfo.id,
+        remark:self.formData.remark
+      }
+      self.$axiosUser('post','api/pro/integral/appeal/review/approval',params)
+        .then(res => {
+          if (res.data.code === 1){
+            self.hasSubmit = true
+            self.getAppealInfo()
+            self.showReviewApproval = false
+          }else {
+            self.$toast(res.data.msg)
+          }
+        })
+        .finally(() => {
+          self.submitting = false
+        })
+    },
+    closeReviewApproval(){
+      this.showReviewApproval = false
+    },
+    reviewCancel(){
+      if (!this.appealInfo) return
+      this.submitting = true
+      let self = this
+      self.$axiosUser('post','api/pro/integral/appeal/review/cancel',{appeal_id:self.appealInfo.id})
+        .then(res => {
+          if (res.data.code === 1){
+            self.hasSubmit = true
+            self.getAppealInfo()
+          }else {
+            self.$toast(res.data.msg)
+          }
+        })
+        .finally(() => {
+          self.submitting = false
+        })
+    },
+    appealCancel(){
+      if (!this.appealInfo) return
+      this.submitting = true
+      let self = this
+      self.$axiosUser('post','api/pro/integral/appeal/cancel',{appeal_id:self.appealInfo.id})
+        .then(res => {
+          if (res.data.code === 1){
+            self.hasSubmit = true
+            self.getAppealInfo()
+          }else {
+            self.$toast(res.data.msg)
+          }
+        })
+        .finally(() => {
+          self.submitting = false
+        })
+    },
+    handleRewriteSubmit(){
+      this.hasSubmit = true
+      this.getAppealInfo()
+    },
+    collapseChange(activeName){
+      if (activeName === 'logs'){
+        this.logs = this.appealInfo.logs
+      }else {
+        this.logs = []
+      }
+    }
+  },
+}
+</script>
+
+
+<style scoped lang="less">
+/deep/ .van-nav-bar--fixed{
+  position: fixed;
+  top: 10%;
+  left: 0;
+  width: 100%;
+}
+.container {
+  position: relative;
+  width: 100%;
+  margin-top: 15%;
+
+  & .card-box{
+    margin: 0.2rem;
+    padding: 0.1rem;
+    border-radius: 0.3rem;
+    border: 1px solid #ebeef5;
+    background-color: #ffffff;
+    overflow: hidden;
+    color: #303133;
+    text-align: center;
+    box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
+
+    & .card-content{
+      font-size: 0.25rem;
+      line-height: 0.5rem;
+      color: #909399;
+      text-align: left;
+      margin-left: 0.3rem;
+    }
+
+    & .card-content1{
+      font-size: 0.25rem;
+      line-height: 0.25rem;
+      color: #909399;
+      text-align: left;
+
+    }
+
+  }
+
+  .content-font{
+    font-size: 0.25rem;
+    line-height: 0.25rem;
+    color: #909399;
+    text-align: left;
+  }
+
+}
+
+</style>

+ 253 - 0
src/components/AppealRewrite.vue

@@ -0,0 +1,253 @@
+<template>
+  <van-popup
+    v-model="showAppealRewrite"
+    position="bottom"
+    duration="0.2"
+    :style="{height: '90%', width:'100vw','background-color': 'rgb(245, 245, 245)'}"
+    @open="onOpen"
+    @closed="onClosed"
+  >
+    <van-nav-bar
+      title="申诉重写"
+      :left-arrow="true"
+      @click-left="showAppealRewrite = false"
+      @click-right="showActions = true"
+    >
+      <template slot="right" v-if="canActions">
+        <van-icon name="bars"/>
+      </template>
+    </van-nav-bar>
+
+    <div :style="{marginTop:'0.1rem',height:'90%'}">
+      <van-notice-bar
+        left-icon="volume-o"
+        text="手机端暂不支持添加积分事件,请在电脑端操作"
+      />
+      <van-form>
+        <van-cell-group>
+          <EmployeeSelectorCell
+            title="递交审批"
+            v-model="rewriteData.reviewer"
+            :multi="false"
+            icon-type="records"
+            :employee_list="userInfo.employee_detail.superior_list"
+            :is_employee_list="true"
+          />
+        </van-cell-group>
+        <van-cell-group>
+          <van-cell>
+            <Mtextarea v-model="rewriteData.globalRemark" :text_max="100" placeholder="申诉原因"/>
+          </van-cell>
+        </van-cell-group>
+        <div class="card-box">
+          <div class="box-header">
+            <span v-if="rewriteData.events.length > 0">共{{rewriteData.events.length}}条积分事件</span>
+            <span v-else>暂无积分事件</span>
+          </div>
+          <van-divider/>
+          <div class="box-content">
+            <div v-for="(item,index) in rewriteData.events" :key="index" class="box-content-item">
+              <div class="box-content-item-title">
+                <van-tag type="primary" size="medium" closeable @close="deleteEvent(item)" >{{item.remark}}</van-tag>
+              </div>
+              <div class="box-content-item-content">
+                <Mtextarea :text_max="100" placeholder="申诉原因" v-model="item.appeal_remark"/>
+              </div>
+            </div>
+          </div>
+        </div>
+      </van-form>
+    </div>
+
+
+    <van-action-sheet
+      v-model="showActions"
+      :actions="[actionRewrite]"
+      @select="actionSelect"
+      close-on-click-action
+    />
+
+  </van-popup>
+</template>
+
+<script>
+import Vue from "vue";
+import {NoticeBar} from "vant";
+Vue.use(NoticeBar)
+
+import EmployeeSelectorCell from "./EmployeeSelectorCell.vue";
+import Mtextarea from "./Mtextarea2.vue";
+export default {
+  name: "AppealRewrite",
+  components:{Mtextarea,EmployeeSelectorCell},
+  props:{
+    visible:{
+      type: Boolean,
+      default : false
+    },
+    id:{
+      type: Number,
+      default: 0
+    },
+  },
+  data(){
+    return {
+      userInfo:this.$userInfo(),
+      hasOpen:false,
+      showAppealRewrite:false,
+      showActions:false,
+      hasSubmit: false,
+      pts:this.$getTypes,
+      appealInfo:null,
+      rewriteData:{
+        events:[],
+        globalRemark:'',
+        reviewer:[]
+      },
+      loading:false,
+      actionRewrite:{name:'提交',subname:'提交申诉进入审批流程',action:'rewrite',loading:false,disabled:false},
+      submitting:false,
+    }
+  },
+  watch:{
+    showAppealRewrite(v){
+      this.$emit('update:visible',v)
+    },
+    visible(v){
+      this.showAppealRewrite = v
+    }
+  },
+  computed:{
+    canActions(){
+      return this.appealInfo && this.appealInfo.can_rewrite && this.rewriteData.reviewer.length === 1 && this.rewriteData.events.length >= 1 && !this.submitting
+    }
+  },
+  methods:{
+    onOpen(){
+      this.hasOpen = true
+      this.getAppealInfo()
+    },
+    onClosed(){
+      this.hasOpen = false
+      if (this.hasSubmit) this.$emit('hasSubmit')
+    },
+    initRewriteData(){
+      if (!this.appealInfo) return
+      this.rewriteData.events = this.appealInfo.events.map(event => {
+        let pt = this.pts.find(item => item.id === event.pt_id)
+        pt = pt ? pt.name : ''
+        return {
+          id:event.id,
+          remark:`${event.point} ${pt} ${event.event_time} ${event.event_remark}`,
+          appeal_remark:event.appeal_remark
+        }
+      })
+      this.rewriteData.globalRemark = this.appealInfo.global_remark
+      let node = this.appealInfo.process.find(item => item.step === 1)
+      if (node){
+        this.rewriteData.reviewer = []
+        this.rewriteData.reviewer.push({id: node.reviewer_id,name: node.reviewer_name,img_url:node.reviewer_img_url})
+      }
+
+    },
+    getAppealInfo(){
+      if (!this.id) return
+      let self = this
+      self.loading = true
+      self.$axiosUser('get','api/pro/integral/appeal/info',{appeal_id:this.id})
+        .then((res) => {
+          if (res.data.code === 1){
+            self.appealInfo = res.data.data
+            self.initRewriteData()
+          }
+        })
+        .finally(() => {
+          self.loading = false
+        })
+    },
+    deleteEvent(event){
+      let index = this.rewriteData.events.indexOf(event)
+      if (index >= 0) this.rewriteData.events.splice(index,1)
+    },
+    actionSelect(action){
+      if (action.action === 'rewrite') this.rewriteAppeal()
+
+    },
+    rewriteAppeal(){
+      let self = this
+      if (!self.canActions) return
+
+      let params = {
+        appeal_id:self.appealInfo.id,
+        reviewer_id:self.rewriteData.reviewer[0].id,
+        remark:self.rewriteData.globalRemark,
+        events:self.rewriteData.events.map(item => {
+          return {id:item.id,remark:item.appeal_remark}
+        })
+      }
+
+
+      self.submitting = true
+      self.$toast.loading({ message: '正在处理',overlay:true,duration:0})
+      self.$axiosUser('post','api/pro/integral/appeal/rewrite',params)
+        .then(res => {
+          if (res.data.code === 1){
+            self.hasSubmit = true
+            self.showAppealRewrite = false
+          }
+          self.$toast(res.data.msg)
+          self.$toast.clear()
+        })
+        .catch(e => {
+          self.$toast.clear()
+        })
+        .finally(() => {
+          self.submitting = false
+        })
+    }
+  }
+}
+</script>
+
+<style scoped lang="less">
+.van-nav-bar--fixed{}
+.card-box{
+  margin: 0.2rem auto;
+  border-radius: 0.3rem;
+  border: 1px solid #ebeef5;
+  background-color: #ffffff;
+  overflow: hidden;
+  color: #303133;
+  text-align: center;
+  min-height: 70%;
+  width: 95%;
+  box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
+
+  & .box-header{
+    height: 0.5rem;
+    line-height: 0.5rem;
+  }
+
+  & .box-content{
+    margin-bottom: 1rem;
+
+    & .box-content-item{
+      width: 95%;
+      margin: 0.3rem auto 0;
+
+      & .box-content-item-title{
+         padding: 0 0.3rem;
+      }
+
+      & .box-content-item-content{
+        padding: 0 0.3rem;
+        margin-top: 0.2rem;
+        border: 0.02rem solid #ebeef5;
+      }
+
+
+    }
+  }
+
+}
+</style>

+ 5 - 0
src/components/CategorySelectorCell.vue

@@ -45,6 +45,7 @@
       :visible.sync="show_dept_selector"
       :selected.sync="selected_data"
       :cycle_type="cycle_type"
+      :scope="scope"
     ></RuleCategorySelector>
   </van-cell>
 </template>
@@ -111,6 +112,10 @@ export default {
       type: Number,
       default: 0
     },
+    scope:{
+      type: Boolean,
+      default: false
+    }
   },
   watch: {
     selected(val) {

+ 10 - 2
src/components/DeptSelectorBtn.vue

@@ -1,8 +1,8 @@
 <template>
-  <van-button @click="show_dept_selector = true">
+  <van-button @click="show_dept_selector = true" :block="block" >
     <template v-if="selected_data.dept.length > 0">
       {{ selected_data.dept[0].dept_name }}
-      <van-icon name="arrow-down" />
+      <van-icon name="close" @click.stop="clearDept"/>
     </template>
     <template v-if="selected_data.dept.length == 0">
       {{ title }}
@@ -55,6 +55,10 @@ export default {
     max: {
       type: Number,
       default: 0
+    },
+    block:{
+      type: Boolean,
+      default: false
     }
   },
   watch: {
@@ -74,6 +78,10 @@ export default {
   methods: {
     confirm(data) {
       this.$emit('value', data.dept);
+    },
+    clearDept(){
+      this.selected_data = { dept: [], employee: [] };
+      this.$emit('value',this.selected_data.dept)
     }
   },
   created() {

+ 1 - 1
src/components/EmployeeSelector.vue

@@ -475,7 +475,7 @@ export default {
            return false
         }
       }
-      console.log(this.dept_selected_list)
+      // console.log(this.dept_selected_list)
       this.$emit('confirm', {
         employee: this.employee_selected_list,
         dept: this.dept_selected_list

+ 30 - 0
src/components/IntegralEventSelector.vue

@@ -0,0 +1,30 @@
+<template>
+
+</template>
+
+<script>
+export default {
+  name: "IntegralEventSelector",
+  props:{
+    visible:{
+      type: Boolean,
+      default:false
+    },
+    eid:{
+      type: Number,
+      default:0
+    },
+    selected:{
+      type: Array,
+      default: () => []
+    },
+    max:{
+      type: Number,
+      default: 100
+    }
+  }
+}
+</script>
+<style scoped lang="less">
+
+</style>

+ 6 - 2
src/components/Mtextarea.vue

@@ -15,7 +15,7 @@
 
       <div v-else style="position: relative;min-height: 1.6rem;margin: 0.16rem;">
         <div v-html="s_text"></div>
-        <textarea :placeholder="placeholder" v-model="text" class="diy_text"></textarea>
+        <textarea :placeholder="placeholder" v-model="text" class="diy_text" @input="onTextInput"></textarea>
       </div>
       <div style="height: 0.3rem;"></div>
       <span v-show="text_max != ''" class="text-max-tip">{{ text.length }}/{{ text_max }}</span>
@@ -28,6 +28,7 @@
 
 <script>
 import Uploader from '@/components/OssUploader';
+import {specialFilter} from "../utils/helper";
 
 export default {
   name: 'Mtextarea',
@@ -115,7 +116,7 @@ export default {
     }
   },
   created() {
-    this.text = this.value;
+    this.text = specialFilter(this.value);
     this.s_imgs = this.imgs;
   },
   methods: {
@@ -131,6 +132,9 @@ export default {
       // }
       return isJPG;
     },
+    onTextInput(e){
+      this.text = specialFilter(e.target.value)
+    }
   }
 };
 </script>

+ 7 - 3
src/components/Mtextarea2.vue

@@ -15,7 +15,7 @@
       </div>
       <div v-else>
         <div v-html="s_text"></div>
-        <textarea :placeholder="placeholder" v-model="text" class="diy_text"></textarea>
+        <textarea :placeholder="placeholder" v-model="text" class="diy_text" @input="onTextInput"></textarea>
       </div>
     </div>
     <div v-show="imgs.length > 0" style="padding:0.24rem;" class="upload_box">
@@ -37,6 +37,7 @@
 
 <script>
 import Uploader from '@/components/OssUploader'
+import {specialFilter} from "../utils/helper";
 
 export default {
   name: 'Mtextarea',
@@ -124,10 +125,13 @@ export default {
     }
   },
   created () {
-    this.text = this.value
+    this.text = specialFilter(this.value)
     this.s_imgs = this.imgs
   },
   methods: {
+    onTextInput(e){
+      this.text = specialFilter(e.target.value)
+    },
     // 返回布尔值
     beforeRead(file) {
       const isJPG = /^image\/(jpeg|png|jpg)$/.test(file.type);
@@ -256,4 +260,4 @@ export default {
 .mtext-box {
   position: relative;
 }
-</style>
+</style>

+ 1 - 1
src/components/NumberInput.vue

@@ -166,7 +166,7 @@ export default {
   },
   methods: {
     setCurrentValue(value) {
-      console.log('value:'+value,this.numVal)
+      // console.log('value:'+value,this.numVal)
       if(value===''){
         return false
       }

+ 79 - 3
src/components/RuleCategorySelector.vue

@@ -7,7 +7,7 @@
       <a v-for="(item, index) in pid_list_arr" :key="index" href="javascript:void(0);" @click="back_by_index(index + 1)"> <van-icon name="arrow" /> {{item.name}}</a>
     </div>
     <div class="body_com" :class="{show_dept_path:pid_list_arr.length > 0}">
-      <scroller :on-refresh="get_category_list">
+      <scroller :on-refresh="tt">
         <van-cell-group>
         <van-cell :is-link="!can_select_category" v-for="(item,index) in category_list" :key="index" :title="item.name" v-show="item.pid == pid && item.name.indexOf(keyword) >= 0 && category_not_select.indexOf(item.id) < 0" class="employee_cell" @click="select_dept(item)">
           <template slot="icon">
@@ -115,6 +115,10 @@ export default {
       type: Number,
       default: 0
     },
+    scope:{
+      type: Boolean,
+      default: false
+    }
   },
   name: 'RuleCategorySelector',
   data () {
@@ -379,7 +383,72 @@ export default {
         this.parse_tree(trees[i].child, rule_id)
       }
     },
+    getRuleScope(done){
+      let data = {
+        cycle_type:this.cycle_type,
+        pt_id:this.ptId
+      }
+      this.$axiosUser('get','/api/pro/integral/rule/trees/scope',data)
+        .then((res)=>{
+          this.category_list = []
+          this.item_list = res.data.data.item_list
+          let ruleSet = new Set(res.data.data.rule_tree.map(item => item.id))
+          this.rule_tree = res.data.data.rule_tree.map(item => {
+            let rule = {...item}
+            rule.pid = ruleSet.has(item.pid) ? item.pid : 0
+            return rule
+          })
+
+          // this.rule_tree = res.data.data.rule_tree
+          this.parse_tree(this.rule_tree, this.pid)
+          for (let i in this.category_list) {
+            this.category_list[i]['checked'] = false
+            if (this.category_selected.indexOf(this.category_list[i].id) >= 0) {
+              this.category_list[i]['checked'] = true
+              if (this.cate_multi == false) {
+                this.parse_tree(this.rule_tree, this.category_list[i].id)
+              }
+              this.$emit('get_items', this.cur_item_list)
+              this.category_list = []
+              this.parse_tree(res.data.data.rule_tree, this.pid)
+            }
+          }
+
+          if (this.pid == 0) {
+            this.list = []
+            for (let i in this.item_list) {
+              for (let k in this.item_list[i]) {
+                this.list.push(this.item_list[i][k])
+              }
+            }
+          } else {
+            this.list = this.cur_item_list
+          }
+          for (let i in this.list) {
+            this.list[i]['checked'] = false
+            if (this.rule_selected.indexOf(this.list[i].id) >= 0) {
+              this.list[i]['checked'] = true
+            }
+          }
+
+          done()
+          this.$toast.clear()
+        })
+        .catch(e => {
+          done()
+          this.$toast.clear()
+        })
+    },
+    tt(done){
+      this.get_category_list(done)
+    },
     get_category_list (done) {
+      //根据可见范围查询分类树
+      if (this.scope){
+        this.getRuleScope(done)
+        return
+      }
+
       this.category_list = []
       let params = {
         cycle_type:this.cycle_type
@@ -393,7 +462,14 @@ export default {
       this.$axiosUser('get', '/api/pro/integral/rule/trees', params).then((res) => {
         this.category_list = []
         this.item_list = res.data.data.item_list
-        this.rule_tree = res.data.data.rule_tree
+        let ruleSet = new Set(res.data.data.rule_tree.map(item => item.id))
+        this.rule_tree = res.data.data.rule_tree.map(item => {
+          let rule = {...item}
+          rule.pid = ruleSet.has(item.pid) ? item.pid : 0
+          return rule
+        })
+
+        // this.rule_tree = res.data.data.rule_tree
         this.parse_tree(res.data.data.rule_tree, this.pid)
         for (let i in this.category_list) {
           this.category_list[i]['checked'] = false
@@ -465,7 +541,7 @@ export default {
     this.deptIds = this.$userInfo().employee_detail.dept_list.map(item => {
       return item.dept_id
     })
-    this.get_category_list(function () {})
+    // this.get_category_list(function () {})
     this.get_point_types()
     this.$nextTick(() => {
       if (this.append_body) {

+ 44 - 5
src/components/RuleCategorySelector1.vue

@@ -5,7 +5,15 @@
     <div class="body_com">
       <scroller style="right:5.5rem;width:2rem;" class="selector-left _v-container">
         <van-collapse v-model="left_active" accordion>
-          <van-collapse-item :is-link="false" :name="item.id" v-for="(item,index) in category_list" :key="index" :title="item.name" v-show="item.pid == 0" :class="{on: left_active, no_child: item.child.length == 0}">
+          <van-collapse-item
+            :is-link="false"
+            :name="item.id"
+            v-for="(item,index) in category_list"
+            :key="index"
+            :title="item.name"
+            v-show="item.pid === 0"
+            :class="{on: left_active, no_child: item.child.length === 0}"
+          >
             <template v-if="item.child.length > 0">
               <div v-for="(child_item,child_index) in item.child" :key="child_index" @click.stop="show_child(child_item)" style="padding: 0.16rem 0;border-bottom: 1px solid #f1f1f1;">
                 <span :class="{blue: pid == child_item.id}">{{child_item.name}}</span>
@@ -104,6 +112,10 @@ export default {
       type: Number,
       default: 1
     },
+    scope:{
+      type: Boolean,
+      default: false
+    }
   },
   name: 'RuleCategorySelector',
   data () {
@@ -340,7 +352,24 @@ export default {
         this.parse_tree(trees[i].child, rule_id)
       }
     },
-
+    getRuleScope(){
+      let data = {
+        cycle_type:this.cycle_type,
+        pt_id:this.ptId
+      }
+      this.$axiosUser('get','/api/pro/integral/rule/trees/scope',data)
+        .then((res)=>{
+          this.category_list = []
+          // this.rule_tree = res.data.data.rule_tree
+          let ruleSet = new Set(res.data.data.rule_tree.map(item => item.id))
+          this.rule_tree = res.data.data.rule_tree.map(item => {
+            let rule = {...item}
+            rule.pid = ruleSet.has(item.pid) ? item.pid : 0
+            return rule
+          })
+          this.parse_tree(this.rule_tree, this.pid)
+        })
+    },
     get_category_list () {
       let params = {}
       if(this.ptId){ //指定分类
@@ -352,8 +381,14 @@ export default {
       params['cycle_type'] = this.cycle_type
       this.$axiosUser('get', '/api/pro/integral/rule/trees', params).then((res) => {
         this.category_list = []
-        this.rule_tree = res.data.data.rule_tree
-        this.parse_tree(res.data.data.rule_tree, this.pid)
+        // this.rule_tree = res.data.data.rule_tree
+        let ruleSet = new Set(this.rule_tree.map(item => item.id))
+        this.rule_tree = res.data.data.rule_tree.map(item => {
+          let rule = {...item}
+          rule.pid = ruleSet.has(item.pid) ? item.pid : 0
+          return rule
+        })
+        this.parse_tree(this.rule_tree, this.pid)
       })
     },
   },
@@ -364,7 +399,11 @@ export default {
     if (document.documentElement.style.height) {
       this.com_height = document.documentElement.style.height
     }
-    this.get_category_list();
+    if (this.scope){
+      this.getRuleScope()
+    }else {
+      this.get_category_list();
+    }
   }
 }
 </script>

+ 17 - 9
src/components/RuleCategorySelectorCell1.vue

@@ -3,7 +3,6 @@
     class="employee_cell"
     :title="title"
     :value="value"
-    :label="label"
     :icon="icon"
     :url="url"
     :border="border"
@@ -19,19 +18,24 @@
         选择了{{selected_data.rule.length}}条规则
       </div>
     </template>
+    <template slot="label">
+      <slot name="label">{{label}}</slot>
+    </template>
 
     <RuleCategorySelector1
-    :ptId="ptId"
-    :multi.sync="multi"
-    :max="max"
-    :close_clear_data="false"
-     ref="selector"
-     @confirm="confirm"
-    :can_select_category="false"
+      :scope="scope"
+      :ptId="ptId"
+      :multi.sync="multi"
+      :max="max"
+      :close_clear_data="false"
+      ref="selector"
+      @confirm="confirm"
+      :can_select_category="false"
      :visible.sync="show_dept_selector"
      :selected.sync="selected_data"
      :append_body="true"
-     :cycle_type="cycle_type">
+     :cycle_type="cycle_type"
+    >
      <template slot="append">
       <slot name="append"></slot>
     </template></RuleCategorySelector1>
@@ -108,6 +112,10 @@ export default {
     activeIndex: {
       type: Number
     },
+    scope:{
+      type: Boolean,
+      default:false,
+    }
   },
   watch: {
     selected (val) {

+ 5 - 5
src/components/TabsList.vue

@@ -11,13 +11,13 @@
       </van-tabs>
       <div class="list-search__bar">
         <span class="list-filter__btn" v-if="showToolBar" @click="onFilterIconClick">
-          <icon name="tab_filter" width="0.4rem" height="0.4rem"></icon>
+          <icon name="tab_filter" width="0.4rem" height="0.4rem" class="van-hairline--left"></icon>
         </span>
         <span class="list-filter__btn" v-else @click="tips">
           <icon name="tab_filter" width="0.4rem" height="0.4rem"></icon>
         </span>
       </div>
-      
+
     </div>
     <div class="tab-list__content">
       <scroller
@@ -43,7 +43,7 @@
         <van-loading v-if="loding" type="spinner" />
       </scroller>
     </div>
-    
+
     <div ref="popupContainer"  class="popup-container"  :style="popupContainerStyle"  v-show="showPopupContainer">
       <van-popup
         v-model="popupSearchBar"
@@ -60,7 +60,7 @@
         </div>
       </van-popup>
     </div>
-    
+
   </div>
 </template>
 <script>
@@ -96,7 +96,7 @@ export default {
       this.tabsOption.forEach(o => activeTabSatus[o.value] = 1)
     }
 
-    return {
+    return  {
       loding: false,
       activeTab: activeTab,
       activeTabName: activeTabName,

+ 1 - 1
src/components/user_image.vue

@@ -119,7 +119,7 @@
   }
   .user_name_div{
     position: absolute;
-    z-index: 1;
+    //z-index: 1;
     text-align: center;
     color: #fff;
   }

+ 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;

+ 2 - 2
src/okr/view/task/taskDetail.vue

@@ -501,7 +501,7 @@
     <!-- 审批拒绝 -->
     <van-dialog v-model="isShowError" title="审批拒绝" class="reject_popup" show-cancel-button :beforeClose="save_btn">
       <van-cell-group>
-        <van-field v-model="errorContent" rows="2" autosize type="textarea" maxlength="50" placeholder="请输入拒绝理由" show-word-limit v-validate="'required'" name="拒绝理由" />
+        <van-field v-model="errorContent" rows="2" autosize type="textarea" maxlength="50" placeholder="原因说明" show-word-limit v-validate="'required'" name="原因说明" />
       </van-cell-group>
     </van-dialog>
 
@@ -1294,7 +1294,7 @@ export default {
     save_btn(action, done) {
       if (action == 'confirm') {
         if(!this.errorContent){
-          this.$toast('请输入拒绝理由');
+          this.$toast('请填写原因说明');
           done();
           return false;
         }

+ 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) => { })//公司信息
 }

+ 22 - 14
src/point/view/audit/integralAudit.vue

@@ -61,17 +61,17 @@
        <template v-if="detail_data.item_id && detail_data.rule_id">
           <van-cell-group>
              <NumberInput
-               v-show="detail_data.pid == 0"
+               v-show="isFirstStep"
                title="积分"
                :min="data.item_min_point"
                :max="data.item_max_point"
-               :isForbidSet="detail_data.pid? true:false"
+               :isForbidSet="!isFirstStep"
                required
                v-model="data.point"
                name="积分"
                v-validate="'required'"
              ></NumberInput>
-             <div class="flex-box flex-v-ce jf" v-show="detail_data.item_range_type == 2 && detail_data.pid != 0">
+             <div class="flex-box flex-v-ce jf" v-show="detail_data.item_range_type == 2 && isFirstStep">
                <div>积分</div>
                <div>
                  <span class="red" v-if="data.point > 0">+{{ data.point }}</span>
@@ -86,25 +86,25 @@
          <NumberInput title="积分"
            :min="data.item_min_point"
            :max="data.item_max_point"
-           :isForbidSet="detail_data.pid? true:false"
+           :isForbidSet="!isFirstStep"
            required v-model="data.point"
            name="积分"
            v-validate="'required'">
          </NumberInput>
-        </van-cell-group>
+       </van-cell-group>
 
 
         <van-cell-group>
           <div class="tip" slot="title">奖票多用于优秀表现和重要事项的表彰</div>
           <van-cell center title="发放奖票">
             <template #right-icon>
-              <van-switch v-model="ticket_count" size="24" />
+              <van-switch v-model="ticket_count" size="24" :disabled="!isFirstStep" />
             </template>
           </van-cell>
         </van-cell-group>
 
         <DateCell
-          v-if="(detail_data.source_type == 2 || detail_data.source_type == 3) && detail_data.pid == 0"
+          v-if="(detail_data.source_type == 2 || detail_data.source_type == 3) && isFirstStep"
           title="发生时间"
           v-model="data.event_time"
           :defaultVal="data.event_default"
@@ -113,7 +113,7 @@
 
         <van-cell-group v-if="!isCreator">
           <EmployeeSelectorCell
-            title="递交审批"
+            title="审批"
             v-model="reviewer"
             :multi="false"
             iconType="records"
@@ -191,6 +191,11 @@ export default {
       maxDate: new Date()
     };
   },
+  computed:{
+    isFirstStep(){
+      return this.detail_data && ((this.detail_data.pid === 0 && this.detail_data.step === 0 || this.detail_data.step === 1))
+    },
+  },
   watch: {
     select_cate(val) {
       this.item_list = [];
@@ -294,6 +299,8 @@ export default {
           let obj=res.data.data
           this.data.item_id = obj.item_id;
           this.data.point = obj.point;
+          this.data.ticket_count = obj.ticket_count;
+          this.ticket_count = !!obj.ticket_count;
           if(obj.item_id){
             this.data.item_min_point = obj.item_min_point;
             this.data.item_max_point = obj.item_max_point;
@@ -383,12 +390,13 @@ export default {
           // 20200731
           /** 在 ruleLimitCheck 为0的时候, 超出积分权限都要选择审批人提交 */
           this.validateRuleLimit(items, callback, a => {
-            return !(
-              (a.reviewer_id && a.point !== 0 && a.rule_id > 0) ||
-              (a.reviewer_id <= 0 && a.item_id > 0 && ruleLimitCheck && a.point !== 0 && a.point <= maxPointPermission && Math.abs(a.point) <= maxPointPermission) ||
-              (a.reviewer_id <= 0 && !ruleLimitCheck && this.pointTypeId == 3 && a.rule_id > 0) ||
-              (a.reviewer_id <= 0 && a.item_id >= 0 && a.point !== 0 && a.point <= maxPointPermission && Math.abs(a.point) <= maxPointPermission && a.rule_id > 0)
-            );
+            return false   //统一不验证拦截,乱七八糟。后端会有拦截提示
+            // return !(
+            //   (a.reviewer_id && a.point !== 0 && a.rule_id > 0) ||
+            //   (a.reviewer_id <= 0 && a.item_id > 0 && ruleLimitCheck && a.point !== 0 && a.point <= maxPointPermission && Math.abs(a.point) <= maxPointPermission) ||
+            //   (a.reviewer_id <= 0 && !ruleLimitCheck && this.pointTypeId == 3 && a.rule_id > 0) ||
+            //   (a.reviewer_id <= 0 && a.item_id >= 0 && a.point !== 0 && a.point <= maxPointPermission && Math.abs(a.point) <= maxPointPermission && a.rule_id > 0)
+            // );
           });
 
           // /** 在 ruleLimitCheck 为0的时候, 超出积分权限都要选择审批人提交 */

+ 365 - 0
src/point/view/integral/appealList.vue

@@ -0,0 +1,365 @@
+<template>
+  <div>
+    <van-nav-bar title="申诉记录" left-text="返回" @click-left="$route_back" left-arrow >
+      <template slot="right" v-if="currentTab === 'my'">
+        <van-dropdown-menu>
+          <van-dropdown-item v-model="searchForm.status" :options="appealStatus" />
+        </van-dropdown-menu>
+      </template>
+    </van-nav-bar>
+    <van-notice-bar
+      left-icon="volume-o"
+      text="手机端到积分事件页面选择个人积分发起申诉,一旦审批,积分将自动删除"
+    />
+    <van-tabs
+      v-model="currentTab"
+      :border="false"
+      title-active-color="#26A2FF"
+      color="#FFFFFF"
+    >
+      <van-tab v-for="item in tabs" :key="item.name" :title="item.title" :name="item.name" />
+    </van-tabs>
+    <div class="content-list">
+      <scroller
+        ref="scroller"
+        :on-refresh="onRefresh"
+        :on-infinite="onInfinite"
+        no-data-text="我也是有底线的"
+        :list="list"
+      >
+        <van-cell v-for="item in list" :key="item.id" @click="openDetail(item.id)" >
+          <template slot="title">
+            <van-row>
+              <van-col span="4">
+                <div style="width: 100%; text-align: center;">
+                  <userImage
+                    :img_url="item.employee_img_url"
+                    :user_name="item.employee_name"
+                  />
+                </div>
+              </van-col>
+              <van-col span="6" class="font-flex-word" style="text-align: center">
+                <span style="font-size: 0.35rem;line-height: 0.8rem">
+                  {{item.employee_name}}
+                </span>
+              </van-col>
+              <van-col span="14" class="font-flex-word" >
+                <span style="font-size: 0.35rem;line-height: 0.8rem">
+                  提交了
+                  <van-tag type="primary" round size="medium">{{item.event_count <= 1000 ? item.event_count : '1000+'}}</van-tag>
+                  条积分申诉
+                </span>
+              </van-col>
+            </van-row>
+            <van-row  type="flex" justify="end">
+              <van-col span="8" style="text-align: center;">
+                <span style="font-size: 0.3rem;line-height: 0.8rem; " class="input-ccc">{{item.create_time}}</span>
+              </van-col>
+              <van-col span="8" style="text-align: center;line-height: 0.8rem">
+                <van-tag :type="statusType(item.status)" size="medium" mark>{{appealStatusMap[item.status] || ''}}</van-tag>
+              </van-col>
+            </van-row>
+          </template>
+        </van-cell>
+        <NoData :list="list"/>
+      </scroller>
+    </div>
+
+    <AppealInfo
+      :visible.sync="showAppealInfo"
+      :id="appealId"
+      @closeInfo="closeDetail"
+      @hasSubmit="refresh"
+    />
+  </div>
+</template>
+
+<script>
+import Vue from "vue";
+import {DropdownMenu,DropdownItem,Card,NoticeBar} from "vant";
+import AppealInfo from "@/components/AppealInfo.vue";
+import NoData from "../../../components/noData.vue";
+Vue.use(DropdownMenu).use(DropdownItem).use(Card).use(NoticeBar)
+export default {
+  name: "appeal",
+  components: {AppealInfo,NoData},
+  data(){
+    return {
+      first:true,
+      userInfo:this.$userInfo(),
+      currentTab:'waiting',
+      tabs:[
+        {name:'waiting',title:'待处理列表'},
+        {name:'my',title:'申诉列表'},
+        {name:'join',title:'参与列表'},
+      ],
+      searchForm:{
+        status: 3,
+        page: 1,
+        pageSize: 10,
+        hasFinish:false,
+      },
+      list:[],
+      ll:[],
+      appealStatusMap:{
+        0:'全部',
+        1:'审批中',
+        2:'审批通过',
+        3:'驳回重做',
+        4:'撤回重填',
+        5:'拒绝'
+      },
+      appealStatus:[
+        {
+          value:0,
+          text:'全部'
+        },
+        {
+          value:1,
+          text:'审批中'
+        },
+        {
+          value:2,
+          text:'审批通过'
+        },
+        {
+          value:3,
+          text:'驳回重做'
+        },
+        {
+          value:4,
+          text:'撤回重填'
+        },
+        {
+          value:5,
+          text:'拒绝'
+        },
+      ],
+      showToolBar:false,
+      loading:false,
+      showAppealInfo:false,
+      appealId:0
+    }
+  },
+  methods:{
+    initData(){
+      this.list = []
+      this.currentTab = 'waiting'
+      this.initSearchForm()
+    },
+    initSearchForm(){
+      this.searchForm.status = 3
+      this.searchForm.page = 1
+      this.searchForm.pageSize = 10
+      this.searchForm.hasFinish = false
+    },
+    initPage(){
+      this.searchForm.hasFinish = false
+      this.searchForm.page = 1
+      this.searchForm.pageSize = 10
+    },
+    refresh(){
+      this.initPage()
+      this.$refs.scroller.finishInfinite(false)
+      this.$refs.scroller.triggerPullToRefresh()
+    },
+    statusType(status){
+      let map = {
+        1:'primary',
+        2:'success',
+        3:'warning',
+        4:'warning',
+        5:'danger',
+      }
+      return map[status] || 'primary'
+    },
+    onRefresh(finishPullToRefresh){
+      this.initPage()
+      this.getList(finishPullToRefresh)
+    },
+    onInfinite(finishInfinite){
+      if (this.searchForm.hasFinish) {
+        finishInfinite()
+        this.$refs.scroller.finishPullToRefresh()
+        return
+      }
+      this.searchForm.page++
+      this.getList(finishInfinite)
+    },
+
+    getList(callback){
+      switch (this.currentTab) {
+        case 'waiting':
+          this.getListForWaiting(callback)
+          break;
+        case 'my':
+          this.getPublishList(callback)
+          break;
+        case 'join':
+          this.getJoinList(callback)
+          break;
+      }
+    },
+    getListForWaiting(callback){
+      let self = this
+      self.loading = true
+      let params = {
+        last_reviewer_id:self.userInfo.id,
+        status:1,
+        page:self.searchForm.page,
+        page_size:self.searchForm.pageSize
+      }
+
+      self.$axiosUser('get','/api/pro/integral/appeal/list',params)
+        .then(res => {
+          if (res.data.code === 1){
+            if (self.searchForm.page === 1){
+              self.list = res.data.data.list
+            }else {
+              self.list = self.list.concat(res.data.data.list)
+            }
+            callback && callback()    //将后台获取的数据,复制到vue组件的数据源后,再进行调用done函数。如果在之前调用,会循环调用。如果不调用这个函数,上拉获取数据函数调用不成功
+
+            self.$refs.scroller.finishPullToRefresh()   //停止下拉刷新  loading动画
+
+            self.searchForm.hasFinish = res.data.data.list.length !== self.searchForm.pageSize
+            self.$refs.scroller.finishInfinite(self.searchForm.hasFinish)    //当参数为false时,上拉获取数据可以重新调用。当参数为true,上拉获取数据回调函数停止使用,下拉下部不再显示loading,会显示‘’暂无更多数据
+          }else {
+            self.searchForm.hasFinish = true
+            self.$refs.scroller.finishInfinite(self.searchForm.hasFinish)
+          }
+        })
+        .finally(() => {
+          self.loading = false
+        })
+    },
+    getPublishList(callback){
+      let self = this
+      self.loading = true
+      let params = {
+        status:self.searchForm.status,
+        page:self.searchForm.page,
+        page_size:self.searchForm.pageSize
+      }
+
+      self.$axiosUser('get','/api/pro/integral/appeal/list/publisher',params)
+        .then(res => {
+          if (res.data.code === 1){
+            if (self.searchForm.page === 1){
+              self.list = res.data.data.list
+            }else {
+              self.list = self.list.concat(res.data.data.list)
+            }
+            callback && callback()    //将后台获取的数据,复制到vue组件的数据源后,再进行调用done函数。如果在之前调用,会循环调用。如果不调用这个函数,上拉获取数据函数调用不成功
+
+            self.$refs.scroller.finishPullToRefresh()   //停止下拉刷新  loading动画
+
+            self.searchForm.hasFinish = res.data.data.list.length !== self.searchForm.pageSize
+            self.$refs.scroller.finishInfinite(self.searchForm.hasFinish)    //当参数为false时,上拉获取数据可以重新调用。当参数为true,上拉获取数据回调函数停止使用,下拉下部不再显示loading,会显示‘’暂无更多数据
+          }else {
+            self.searchForm.hasFinish = true
+            self.$refs.scroller.finishInfinite(self.searchForm.hasFinish)
+          }
+        })
+        .finally(() => {
+          self.loading = false
+        })
+    },
+    getJoinList(callback){
+      let self = this
+      self.loading = true
+      let params = {
+        page:self.searchForm.page,
+        page_size:self.searchForm.pageSize
+      }
+
+      self.$axiosUser('get','/api/pro/integral/appeal/list/reviewer',params)
+        .then(res => {
+          if (res.data.code === 1){
+            if (self.searchForm.page === 1){
+              self.list = res.data.data.list
+            }else {
+              self.list = self.list.concat(res.data.data.list)
+            }
+
+            callback && callback()    //将后台获取的数据,复制到vue组件的数据源后,再进行调用done函数。如果在之前调用,会循环调用。如果不调用这个函数,上拉获取数据函数调用不成功
+
+            self.$refs.scroller.finishPullToRefresh()   //停止下拉刷新  loading动画
+
+            self.searchForm.hasFinish = res.data.data.list.length !== self.searchForm.pageSize
+            self.$refs.scroller.finishInfinite(self.searchForm.hasFinish)    //当参数为false时,上拉获取数据可以重新调用。当参数为true,上拉获取数据回调函数停止使用,下拉下部不再显示loading,会显示‘’暂无更多数据
+          }else {
+            self.searchForm.hasFinish = true
+            self.$refs.scroller.finishInfinite(self.searchForm.hasFinish)
+          }
+        })
+        .finally(() => {
+          self.loading = false
+        })
+    },
+    openDetail(appealId){
+      this.appealId = appealId
+      this.showAppealInfo = true
+    },
+    closeDetail(){
+      this.appealId = 0
+      this.showAppealInfo = false
+    },
+
+  },
+  computed:{
+  },
+  watch:{
+    currentTab(v){
+      this.refresh()
+    },
+    'searchForm.status'(){
+      this.refresh()
+    }
+  },
+
+  activated() {
+    this.initData()
+    this.getList()
+  },
+}
+</script>
+
+<style scoped lang="less">
+.popup-container{
+  position: fixed;
+  top: 5rem;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 10;
+  overflow: hidden;
+}
+
+/deep/ .van-dropdown-menu__title{
+  position: relative;
+  box-sizing: border-box;
+  max-width: 100%;
+  padding: 0 0.16rem;
+  color: #f8f8f8;
+  font-size: 0.3rem;
+  line-height: 0.44rem;
+}
+
+/deep/ .van-dropdown-menu__bar{
+  height: 0.8rem;
+  background-color: #26A2FF;
+}
+/deep/ .van-dropdown-menu{
+  border-bottom: 0;
+}
+
+.content-list{
+  margin-top: 0.2rem;
+  position: relative;
+  height: calc(100% - 3rem);
+}
+
+
+
+</style>

+ 141 - 28
src/point/view/integral/approval_detail.vue

@@ -3,6 +3,27 @@
     <van-nav-bar :title="title" :left-text="isHome? '首页':'返回'" @click-left="routeBack" left-arrow></van-nav-bar>
     <div class="body_com" :class="{ can_complete: detail_info.can_complete == 1}">
       <scroller>
+        <van-collapse
+          accordion
+          v-model="activeNames"
+          @change="collapseChange"
+        >
+          <van-collapse-item
+            :disabled="detail_info.logs.length === 0"
+            v-if="detail_info && detail_info.logs && detail_info.logs.length > 0"
+            :title="detail_info.logs.length + '条操作日志'"
+            name="logs"
+          >
+            <van-notice-bar
+              v-for="(item,index) in logs"
+              :key="index"
+              left-icon="info-o"
+              color="#1989fa"
+              background="#ecf9ff"
+              :text="item.create_time + item.msg"
+            />
+          </van-collapse-item>
+        </van-collapse>
         <van-cell-group>
           <van-cell :title="detail_info.employee_info.name" v-if="detail_info.process !== null && detail_info.status == 0">
             <template slot="icon">
@@ -94,41 +115,66 @@
         <approvalProcess :data.sync="detail_info.process"></approvalProcess>
         <div style="height: 3.5rem;"></div>
       </scroller>
+
       <!-- 审批者 ||  -->
-      <footer class="flex-box flex-v-ce footer" v-if="detail_info.can_refuse == '1'">
-        <div class="flex-2">撤回后需重新审批</div>
-        <van-button type="info" @click="revoke(1)" class="flex-1">撤回</van-button>
-      </footer>
+<!--      <footer class="flex-box flex-v-ce footer" v-if="detail_info.can_refuse === 1">-->
+<!--        <div class="flex-2">撤回后需重新审批</div>-->
+<!--        <van-button type="info" @click="revoke(1)" class="flex-1">撤回</van-button>-->
+<!--      </footer>-->
       <!-- 申请者 ||  -->
-      <footer class="flex-box flex-v-ce footer" v-if="detail_info.applyor_id==$userInfo().id&&detail_info.can_refuse == '1'&&(detail_info.source_type==2||detail_info.source_type==3)">
-        <div class="flex-2">撤销后数据将不可恢复</div>
-        <van-button type="info" @click="revoke(2)" class="flex-1">撤销</van-button>
+<!--      <footer class="flex-box flex-v-ce footer" v-if="detail_info.applyor_id==$userInfo().id&&detail_info.can_refuse === 1&&(detail_info.source_type===2||detail_info.source_type===3)">-->
+<!--        <div class="flex-2">撤销后数据将不可恢复</div>-->
+<!--        <van-button type="info" @click="revoke(2)" class="flex-1">撤销</van-button>-->
+<!--      </footer>-->
+      <footer class="flex-box flex-v-ce footer" v-if="canRefuse">
+        <van-button type="info" @click="revoke()" :loading="submitting" class="flex-1">撤回审批</van-button>
       </footer>
 
+
       <!-- 驳回弹窗 -->
       <van-popup v-model="show_refuse" position="right" :style="{ height: '100%', width: '100%', 'background-color': 'rgb(245, 245, 245)' }">
         <div :style="'padding-top:' + bar_height + 'px;background-color: #238dfa;'"></div>
-        <van-nav-bar title="确认驳回" left-text="返回" @click-left="show_refuse = false" left-arrow></van-nav-bar>
-        <van-cell-group><van-field v-model="refuse_msg" rows="5" autosize type="textarea" maxlength="50" placeholder="请输入审批意见" show-word-limit /></van-cell-group>
-        <div style="padding:0.32rem;"><van-button block type="info" @click="confirm_refuse">确认驳回</van-button></div>
+        <van-nav-bar title="审批拒绝" left-text="返回" @click-left="show_refuse = false" left-arrow></van-nav-bar>
+        <van-cell-group><van-field v-model="refuse_msg" rows="5" autosize type="textarea" maxlength="50" placeholder="请输入审批意见" show-word-limit @input="onRefuseMsgInput"/></van-cell-group>
+        <div style="padding:0.32rem;"><van-button block type="info" :loading="submitting" @click="confirm_refuse">确认</van-button></div>
       </van-popup>
+
+      <van-popup v-model="showRejectRewrite" position="right" :style="{height:'100%',width:'100%', backgroundColor:'rgb(245, 245, 245)'}">
+        <div :style="'padding-top:' + bar_height + 'px;background-color: #238dfa;'"></div>
+        <van-nav-bar title="驳回重做" left-text="返回" @click-left="showRejectRewrite = false" left-arrow></van-nav-bar>
+        <van-cell-group><van-field v-model="formRejectRewrite.remark" rows="5" autosize type="textarea" maxlength="100" placeholder="原因说明" show-word-limit @input="onRewriteRemarkInput" /></van-cell-group>
+        <div style="padding:0.32rem;"><van-button block type="info" :loading="submitting" @click="rejectRewrite">确认</van-button></div>
+      </van-popup>
+
     </div>
 
-    <van-row justify="center" type="flex" v-if="detail_info.can_complete == 1" class="footer">
-      <van-col :span="detail_info.source_type != 4 ? 8 : 0">
-        <div style="padding:0.16rem;">
-          <van-button block type="info" plain :disabled="detail_info.source_type == '4'" v-if="detail_info.source_type != 4" @click="refuse">驳回</van-button>
-        </div>
+<!--    <van-row justify="center" type="flex" v-if="detail_info.can_complete === 1" class="footer">-->
+<!--      <van-col :span="detail_info.source_type !== 4 ? 8 : 0">-->
+<!--        <div style="padding:0.16rem;">-->
+<!--          <van-button block type="info" plain :disabled="detail_info.source_type === 4" v-if="detail_info.source_type !== 4" @click="refuse">拒绝</van-button>-->
+<!--        </div>-->
+<!--      </van-col>-->
+<!--      <van-col :span="detail_info.source_type !== 4 ? 16 : 24">-->
+<!--        <div style="padding:0.16rem; padding-left:0;">-->
+<!--          <van-button block type="info" v-if="detail_info.source_type !== 4" @click="$router.push({ name: 'integralAudit', query: { review_id: detail_info.id } })">-->
+<!--            通过-->
+<!--          </van-button>-->
+<!--          <van-button block type="info" v-else @click="$router.push({ name: 'performanceAudit', query: { review_id: detail_info.id } })">-->
+<!--            通过-->
+<!--          </van-button>-->
+<!--        </div>-->
+<!--      </van-col>-->
+<!--    </van-row>-->
+    <van-row justify="space-around" gutter="10" type="flex" v-if="canComplete" class="footer" >
+      <van-col v-if="canReject" :span="8">
+        <van-button block plain :loading="submitting" @click="refuse" >拒绝</van-button>
       </van-col>
-      <van-col :span="detail_info.source_type != 4 ? 16 : 24">
-        <div style="padding:0.16rem; padding-left:0;">
-          <van-button block type="info" v-if="detail_info.source_type != '4'" @click="$router.push({ name: 'integralAudit', query: { review_id: detail_info.id } })">
-            通过
-          </van-button>
-          <van-button block type="info" v-else @click="$router.push({ name: 'performanceAudit', query: { review_id: detail_info.id } })">
-            通过
-          </van-button>
-        </div>
+      <van-col v-if="canRejectRewrite" :span="8">
+        <van-button block  plain type="warning" :loading="submitting" @click="showRejectRewrite = true" >驳回重做</van-button>
+      </van-col>
+      <van-col :span="canRejectRewrite ? 8 : 16">
+        <van-button block type="info" v-if="detail_info.source_type !== 4" @click="$router.push({ name: 'integralAudit', query: { review_id: detail_info.id } })" :loading="submitting" >通过</van-button>
+        <van-button block type="info" v-else @click="$router.push({ name: 'performanceAudit', query: { review_id: detail_info.id } })" :loading="submitting" >通过</van-button>
       </van-col>
     </van-row>
 
@@ -138,18 +184,24 @@
 <script>
 import Vue from 'vue'
 import approvalProcess from '@/point/view/integral/approval_process'
-import { Dialog, Panel, Step, Steps, Overlay, ImagePreview } from 'vant'
+import { Dialog, Panel, Step, Steps, Overlay, ImagePreview, Collapse, CollapseItem,NoticeBar } from 'vant'
+import Footer from "../../../components/footer.vue";
+import {specialFilter} from "../../../utils/helper";
 Vue.use(Dialog)
   .use(Panel)
   .use(Step)
   .use(Steps)
   .use(Overlay)
   .use(ImagePreview)
+  .use(Collapse)
+  .use(CollapseItem)
+  .use(NoticeBar)
 export default {
   // 数据
-  components: { approvalProcess },
+  components: {Footer, approvalProcess },
   data () {
     return {
+      userInfo:this.$userInfo(),
       imageSrc: [],
       show: false,
       title: '审批详情',
@@ -177,6 +229,13 @@ export default {
       adopt_two: false,
       types_list: {},
       isHome:false,//微信信息点击进来
+      showRejectRewrite:false,
+      formRejectRewrite:{
+        remark:''
+      },
+      submitting:false,
+      activeNames:[],
+      logs: []
     }
   },
   watch: {
@@ -188,6 +247,12 @@ export default {
   },
   // 方法
   methods: {
+    onRefuseMsgInput(v){
+      this.refuse_msg = specialFilter(v)
+    },
+    onRewriteRemarkInput(v){
+      this.formRejectRewrite.remark = specialFilter(v)
+    },
     routeBack(){
       this.isHome? this.$router.replace({ name: 'home' }):this.$route_back();
     },
@@ -320,7 +385,7 @@ export default {
       let self = this
       Dialog.confirm({
         title: '提示',
-        message: '您确定要' + str + '此项吗?'
+        message: '确定要撤回此项吗?'
       })
         .then(() => {
           self.showLoading()
@@ -343,11 +408,40 @@ export default {
         .catch(() => {
           // on cancel
         })
+    },
+    rejectRewrite(){
+      let self = this
+      this.submitting = true
+      self.showLoading()
+      let params = {
+        review_id:self.detail_info.id,
+        remark:self.formRejectRewrite.remark || ''
+      }
+      self.$axiosUser('post','/api/pro/integral/review/reject/rewrite',params)
+        .then(res => {
+          if (res.data.code === 1){
+            self.get_info()
+          }else {
+            self.$toast(res.data.msg)
+          }
+        })
+        .finally(() => {
+          self.$toast.clear()
+          self.showRejectRewrite = false
+          self.submitting = false
+        })
+    },
+    collapseChange(activeName){
+      if (activeName === 'logs'){
+        this.logs = this.detail_info.logs
+      }else {
+        this.logs = []
+      }
     }
   },
   created () {
     this.get_point_types()
-    
+
     if (window.plus) {
       this.bar_height = window.plus.navigator.getStatusbarHeight()
     }
@@ -361,6 +455,7 @@ export default {
     }
   },
   activated() {
+    this.activeNames = []
   	this.get_info()
     if(this.$route.query.isHome){
        this.isHome = true;
@@ -368,6 +463,24 @@ export default {
       this.isHome = false;
     }
   },
+  computed:{
+    isFirstStep(){
+      return this.detail_info && ((this.detail_info.pid === 0 && this.detail_info.step === 0) || this.detail_info.step === 1)
+    },
+    canComplete(){
+      return this.detail_info && this.detail_info.can_complete === 1
+    },
+    canRefuse(){
+      return this.detail_info && this.detail_info.can_refuse === 1
+    },
+    canRejectRewrite(){
+      return this.canComplete && this.detail_info.source_type === 1
+    },
+    canReject(){
+      return this.canComplete && this.detail_info.source_type !== 4
+    }
+
+  }
 }
 </script>
 <style scoped lang="less">

+ 42 - 17
src/point/view/integral/approval_list.vue

@@ -32,25 +32,24 @@
               <userImage :user_name="item.employee_name" v-if="item.source_type == 1 || item.source_type == 4" width="0.72rem" height="0.72rem" />
               <userImage :user_name="item.employee_name" v-if="item.source_type == 2 || item.source_type == 3" width="0.72rem" height="0.72rem" />
               <div class="task-title__bar">
-                <span class="title" v-show="item.source_type == 1">{{ item.employee_name }}的积分任务</span>
-                <span class="title" v-show="item.source_type == 2">{{ item.employee_name }}的积分申请</span>
-                <span class="title" v-show="item.source_type == 3">{{ item.employee_name }}的积分奖扣</span>
-                <!-- <span class="title" v-show="item.source_type == 4">{{item.employee_name}}的绩效工作</span> -->
-                <!-- <span class="title" v-show="item.source_type == 4">{{item.employee_name}}提交的绩效工作包</span> -->
+                <span class="title">
+                  {{item.employee_name}}
+                  &nbsp;<van-tag type="primary">{{sourceTypeMap[item.source_type] || '--'}}</van-tag>
+                </span>
                 <span v-if="filter.type === 'reviewed' && item.status !== 0 && item.status !== 2">
-                  <span class="task-item__point red" v-if="item.review_point >= 0">+{{ item.review_point }}{{ $getTypesName(item.pt_id) }}</span>
-                  <span class="task-item__point green" v-else>{{ item.review_point }}{{ $getTypesName(item.pt_id) }}</span>
+                  <span class="task-item__point red" v-if="item.review_point > 0">+{{ item.review_point }}{{ $getTypesName(item.pt_id) }}</span>
+                  <span class="task-item__point green" v-else-if="item.review_point < 0">{{ item.review_point }}{{ $getTypesName(item.pt_id) }}</span>
                 </span>
               </div>
             </div>
 
             <div class="task-remark__content">
-              <span>{{ item.remark.customize }}</span>
+              <span class="input-ccc">{{ item.remark.customize }}</span>
             </div>
             <div class="task-item__bottom" v-if="item.status == 0">
               <span class="task-item__date">{{ item.event_time }}</span>
               <span class="task-item__toolbar" v-if="item.status === 0">
-                <span v-show="item.source_type != 4" @click.stop="reject(item)">驳回</span>
+                <span v-show="item.source_type != 4" @click.stop="reject(item)">拒绝</span>
                 <div class="divider"></div>
                 <span v-if="item.source_type == '1'" @click.stop="$router.push({ name: 'integralAudit', query: { review_id: item.id } })">通过</span>
                 <span v-if="item.source_type == '2'" @click.stop="$router.push({ name: 'integralAudit', query: { review_id: item.id } })">通过</span>
@@ -65,8 +64,7 @@
             <div class="task-item__bottom" v-else>
               <span class="task-item__date">{{ item.event_time }}</span>
               <span class="task-item__toolbar">
-                <span class="green" v-if="item.status == 1">审批通过</span>
-                <span class="red" v-if="item.status == 2">审批驳回</span>
+                <van-tag :type="statusType(item.review_status)" mark size="medium" >{{statusMap[item.review_status] || '--'}}</van-tag>
               </span>
             </div>
           </div>
@@ -75,9 +73,9 @@
       </div>
     </TabsList>
 
-    <van-dialog v-model="show" title="确认驳回" class="reject_popup" show-cancel-button :beforeClose="save_btn">
+    <van-dialog v-model="show" title="审批拒绝" class="reject_popup" show-cancel-button :beforeClose="save_btn">
       <van-cell-group>
-        <van-field v-model="reject_text" rows="2" autosize type="textarea" maxlength="50" placeholder="请输入审批意见" show-word-limit v-validate="'required'" name="审批意见" />
+        <van-field v-model="reject_text" rows="2" autosize type="textarea" maxlength="50" placeholder="请输入审批意见" show-word-limit v-validate="'required'" name="审批意见" @input="onRejectTextInput" />
       </van-cell-group>
     </van-dialog>
   </div>
@@ -89,6 +87,7 @@ import { Tab, Tabs, Empty, DropdownMenu, DropdownItem, Search } from 'vant';
 
 import TabsList from '@/components/TabsList';
 import { _debounce } from '@/utils/auth';
+import {specialFilter} from "../../../utils/helper";
 
 Vue.use(Empty)
   .use(Tab)
@@ -117,7 +116,7 @@ export default {
       reject_text: '',
 
       // 0411
-      tabsOption: [{ title: '待我审批', value: 'waiting' }, { title: '我已审批', value: 'reviewed' }],
+      tabsOption: [{ title: '待审批', value: 'waiting' }, { title: '参与审批', value: 'reviewed' }],
       screen_list: [
         {
           title: '任务类型',
@@ -130,7 +129,19 @@ export default {
             // {name: '绩效工作', id: '4'}
           ]
         }
-      ]
+      ],
+      statusMap:{
+        0:'待审核',
+        1:'审核通过',
+        2:'拒绝',
+        3:'驳回重做',
+        4:'重填',
+      },
+      sourceTypeMap:{
+        1:'积分任务',
+        2:'积分申请',
+        3:'积分奖扣',
+      }
     };
   },
   components: { TabsList },
@@ -153,7 +164,7 @@ export default {
     }
   },
   activated() {
-  	 this.onRefresh({ pageIndex: 1, isRefresh: true });
+  	this.onRefresh({ pageIndex: 1, isRefresh: true });
   },
   methods: {
     openBatch() {
@@ -271,6 +282,20 @@ export default {
       } else {
         done();
       }
+    },
+    statusType(status){
+      if (status === -1) return 'info'
+      const map = {
+        0:'warning',
+        1:'success',
+        2:'danger',
+        3:'danger',
+        4:'primary',
+      }
+      return map[status] || 'info'
+    },
+    onRejectTextInput(v){
+      this.reject_text = specialFilter(v)
     }
   },
 };
@@ -349,7 +374,7 @@ export default {
   .task-remark__content {
     display: -webkit-box;
     padding-left: 0.92rem;
-    font-size: 0.32rem;
+    font-size: 0.3rem;
     color: #333;
     text-overflow: ellipsis;
     overflow: hidden;

+ 66 - 11
src/point/view/integral/approval_process.vue

@@ -12,23 +12,47 @@
         <userImage :user_name="item.name" :id="0" :img_url="item.img_url"></userImage>
       </template>
       <template slot="title">
-        <span class="process-item__name">{{ item.name }}</span>
-        <span class="process-item__remark" v-if="item.remark == '申请人'">{{ item.remark }}</span>
-        <span class="process-item__remark" v-else :class="{orange:item.remark == '待审核',green:item.remark == '审核通过',red:item.remark == '审核驳回','color-FF9600': item.remark == '待处理','color-F56C6C':item.remark == '驳回'}">
-          {{ item.remark }}
-        </span>
+        <span v-if="item.step > 0">阶段{{item.step}}</span>
+        <van-tag :type="processStatusType(item.status)" size="medium" mark>{{processStatusMap[item.status] || '--'}}</van-tag>
       </template>
       <template slot="right-icon">
         <span class="red" v-if="item.review_point > 0">+{{ item.review_point }}</span>
         <span class="green" v-else>{{ item.review_point || '' }}</span>
       </template>
       <template slot="label">
-        <span class="datetime">{{ item.time }}</span>
-        <div v-if="item.remark != '申请人'" style="color: #323233;font-size: 0.28rem;margin-top: 0.12rem;">{{ item.review_remark }}</div>
-        <div class="h40"></div>
+        <span class="datetime" v-if="item.time">{{ item.time }}</span>
+<!--        <van-cell title="姓名" :value="item.name" />-->
+<!--        <van-cell title="申请分值" v-if="item.point" :value="item.point ? item.point : ''" />-->
+<!--        <van-cell title="发放奖票" v-if="i > 0" :value="item.ticket_count ? '是': '否'"  />-->
+<!--        <van-cell title="审批分值" v-if="item.remark !== '发起' && item.review_point" :value="item.review_point ? item.review_point : ''"  />-->
+        <van-row >
+          <van-col span="8" class="process-title">姓名</van-col>
+          <van-col span="16" class="process-content">{{item.name}}</van-col>
+        </van-row>
+        <van-row v-if="item.point">
+          <van-col span="8" class="process-title">申请分值</van-col>
+          <van-col span="16" class="process-content">{{item.point ? item.point : ''}}</van-col>
+        </van-row>
+        <van-row v-if="i > 0">
+          <van-col span="8" class="process-title">发放奖票</van-col>
+          <van-col span="16" class="process-content">{{item.ticket_count ? '是': '否'}}</van-col>
+        </van-row>
+        <van-row v-if="item.remark !== '发起' && item.review_point">
+          <van-col span="8" class="process-title">审批分值</van-col>
+          <van-col span="16" class="process-content">{{item.review_point ? item.review_point : ''}}</van-col>
+        </van-row>
+        <van-row v-if="item.review_remark">
+          <van-col span="8" class="process-title">备注</van-col>
+          <van-col span="16" class="process-content">
+            <van-notice-bar
+              color="#1989fa"
+              background="#ecf9ff"
+              :text="item.review_remark"
+            />
+          </van-col>
+        </van-row>
       </template>
     </van-cell>
-
   </div>
 </template>
 
@@ -44,7 +68,16 @@ export default {
     }
   },
   data() {
-    return {};
+    return {
+      processStatusMap:{
+        '-1':'发起',
+        0:'待审核',
+        1:'审核通过',
+        2:'拒绝',
+        3:'驳回重做',
+        4:'重填',
+      }
+    };
   },
   methods: {
     getIconText(employeeName) {
@@ -53,6 +86,17 @@ export default {
         return employeeName[len - 2] + employeeName[len - 1];
       }
       return employeeName;
+    },
+    processStatusType(status){
+      if (status === -1) return 'primary'
+      const map = {
+        0:'warning',
+        1:'success',
+        2:'danger',
+        3:'danger',
+        4:'primary',
+      }
+      return map[status] || 'info'
     }
   }
 };
@@ -61,7 +105,7 @@ export default {
 <style scoped>
 .process-item {
   padding-top: 0;
-  padding-bottom: 0;
+  padding-bottom: 0.1rem;
   position: relative;
 }
 
@@ -126,4 +170,15 @@ export default {
 /deep/ .img_round {
   margin-right: 0.16rem;
 }
+.process-title{
+  font-size: 0.3rem;
+  line-height: 0.7rem;
+  text-align: center;
+}
+.process-content{
+  font-size: 0.3rem;
+  line-height: 0.7rem;
+  text-align: right;
+}
+
 </style>

+ 4 - 4
src/point/view/integral/batchList.vue

@@ -265,12 +265,12 @@
         <div style="height: 2rem;"></div>
       </scroller>
       <div class="flex-box btns" v-show="rightText" :class="{ isIos: isIos }" >
-        <van-button plain type="danger" class="flex-1" style="margin-right: 0.24rem" @click="reject()">驳回</van-button>
+        <van-button plain type="danger" class="flex-1" style="margin-right: 0.24rem" @click="reject()">拒绝</van-button>
         <van-button plain type="info" class="flex-1" @click="pass()">通过</van-button>
       </div>
-      <van-dialog v-model="showReject" title="确认驳回" class="reject_popup" show-cancel-button :beforeClose="save_btn">
+      <van-dialog v-model="showReject" title="批量拒绝" class="reject_popup" show-cancel-button :beforeClose="save_btn">
         <van-cell-group>
-          <van-field v-model="reject_text" rows="2" autosize  type="textarea" maxlength="50" placeholder="请输入审批意见"  show-word-limit v-validate="'required'" name="审批意见"/>
+          <van-field v-model="reject_text" rows="2" autosize  type="textarea" maxlength="50" placeholder="原因说明"  show-word-limit v-validate="'required'" name="原因说明"/>
         </van-cell-group>
       </van-dialog>
       <van-image-preview v-model="show" :images="imageSrc"></van-image-preview>
@@ -353,7 +353,7 @@ export default {
     reject () {
       Dialog.confirm({
         title: '提示',
-        message: `确定驳回已选的${this.activeCheckedNum}条审批吗?`
+        message: `确定拒绝已选的${this.activeCheckedNum}条审批吗?`
       }).then(() => {
         this.showReject = true
       }).catch(() => {

+ 272 - 0
src/point/view/integral/deptRank.vue

@@ -0,0 +1,272 @@
+<template>
+  <div class="mrd-container">
+    <van-nav-bar title="部门对比" left-text="返回" @click-left="$route_back" left-arrow />
+    <van-dropdown-menu v-if="showSearchBar">
+<!--  A/B分    -->
+      <van-dropdown-item @open="calendarOpen">
+        <van-icon name="calendar-o" slot="title" size="1.5em" />
+      </van-dropdown-item>
+      <van-dropdown-item :title="searchForm.deptName" ref="deptDropdownItem"><DeptSelectorDropdown @onConfirm="onConfirmDept" /></van-dropdown-item>
+      <van-dropdown-item title="规则" ref="ruleDropdownItem"><RuleCategorySelDropdown @onConfirm="onConfirmRule" @onCancel="searchForm.ruleId = 0"/></van-dropdown-item>
+      <van-dropdown-item>
+        <van-icon name="list-switch" slot="title" size="1.5em" />
+        <template slot="default">
+          <van-cell center title="积分类型">
+            <template #right-icon>
+              <van-radio-group v-model="searchForm.ptId" direction="horizontal">
+                <van-radio v-for="pt in pts" :key="pt.value" :name="pt.value">{{pt.text}}</van-radio>
+              </van-radio-group>
+            </template>
+          </van-cell>
+          <van-cell center title="包含子部门">
+            <van-switch v-model="searchForm.deptIncludeSub" active-color="#26A2FF" slot="right-icon" size="24"/>
+          </van-cell>
+          <van-cell center title="包含子规则分类">
+            <van-switch v-model="searchForm.ruleIncludeSub" active-color="#26A2FF" slot="right-icon" size="24"/>
+          </van-cell>
+        </template>
+      </van-dropdown-item>
+    </van-dropdown-menu>
+    <div class="mrd-content">
+      <scroller
+        ref="scroller"
+        :on-refresh="onRefresh"
+      >
+        <van-cell v-for="item in dataList" :key="item.id" :title="item.name" :value="item.point"/>
+        <noData :list="dataList" />
+
+      </scroller>
+    </div>
+
+
+
+    <van-calendar
+      v-model="showCalendar"
+      type="range"
+      :allow-same-day="true"
+      :min-date="minDate"
+      :max-date="maxDate"
+      :default-date="timeScope"
+      :show-confirm="false"
+      color="#26A2FF"
+      @close="calendarClose"
+      @confirm="calendarConfirm"
+    >
+      <template v-slot:title>
+        <van-row>
+          <van-col span="20">
+            <van-row type="flex" justify="space-between" style="height: 1rem;">
+              <van-col span="6" style="text-align: center; align-self: center;">
+                <van-tag type="success" size="medium" @click="timeScopeThisWeek">本周</van-tag>
+              </van-col>
+              <van-col span="6" style="text-align: center; align-self: center;">
+                <van-tag type="success" size="medium" @click="timeScopeLastWeek">上周</van-tag>
+              </van-col>
+              <van-col span="6" style="text-align: center; align-self: center;">
+                <van-tag type="primary" size="medium" @click="timeScopeThisMoth">本月</van-tag>
+              </van-col>
+              <van-col span="6" style="text-align: center; align-self: center;">
+                <van-tag type="primary" size="medium" @click="timeScopeLastMonth">上月</van-tag>
+              </van-col>
+            </van-row>
+          </van-col>
+        </van-row>
+      </template>
+    </van-calendar>
+
+
+  </div>
+</template>
+
+
+<script>
+import Vue from 'vue';
+import moment from "moment/moment";
+import { DropdownMenu, DropdownItem ,Calendar,Switch} from 'vant';
+import DeptSelectorDropdown from '@/components/DeptSelectorDropdown';
+import RuleCategorySelDropdown from '@/components/RuleCategorySelDropdown';
+
+Vue.use(DropdownMenu).use(DropdownItem).use(Calendar).use(Switch);
+
+export default {
+  name: "dept_rank",
+  components:{
+    DeptSelectorDropdown,
+    RuleCategorySelDropdown
+  },
+  data(){
+    let startDate = new Date();
+    startDate.setTime(startDate.getTime() - 3600 * 1000 * 24 * 7);
+    startDate = moment(startDate).format('YYYY-MM-DD');
+    let endDate = moment().format('YYYY-MM-DD');
+    let pts = this.$getTypes.map(type => {
+      return {value:type.id,text:type.name,code:type.code}
+    });
+    let ptB = pts.filter(pt => pt.code === 'BF');
+    ptB = ptB.length > 0 ? ptB[0] : null;
+
+    let today = new Date();
+    let minDate = new Date();
+    minDate.setTime(today.getTime() - 3600 * 1000 * 24 * 30 * 6);
+    let maxDate = new Date(today.getFullYear(),today.getMonth(),1);
+    maxDate.setMonth(maxDate.getMonth() + 1);
+    maxDate.setDate(0);
+
+    return{
+      pts:pts,
+      searchForm:{
+        startDate:startDate,
+        endDate:endDate,
+        deptId:0,
+        deptName:'全公司',
+        deptIncludeSub:false,
+        ptId:ptB ? ptB.value : 0,
+        ptName: ptB ? ptB.text : '',
+        ruleId:0,
+        ruleIncludeSub:false,
+        itemId:0
+      },
+      dataList:[],
+      showCalendar:false,
+      minDate:minDate,
+      maxDate:maxDate,
+      timeScope:[new Date(startDate),new Date(endDate)],
+      showSearchBar:!this.$supremeAuthority('employee')
+    }
+  },
+  computed:{
+    timeScopeText(){
+      return moment(this.searchForm.startDate).format('MM/DD') + '-' + moment(this.searchForm.endDate).format('MM/DD')
+    },
+    currentPtName(){
+      if (this.searchForm.ptId <= 0) return '积分分类';
+      let pt = this.pts.filter(pt => pt.id === this.searchForm.ptId);
+      return pt ? pt.name : '积分分类';
+    }
+  },
+  watch:{
+    timeScope(val){
+      this.$nextTick(()=>{
+        this.searchForm.startDate = moment(val[0]).format('YYYY-MM-DD');
+        this.searchForm.endDate = moment(val[1]).format('YYYY-MM-DD');
+      })
+    },
+    'searchForm.startDate'(val){
+      this.onRefresh()
+    },
+    'searchForm.endDate'(val){
+      this.onRefresh()
+    },
+    'searchForm.deptId'(val){
+      this.onRefresh()
+    },
+    'searchForm.deptIncludeSub'(val){
+      this.onRefresh()
+    },
+    'searchForm.ptId'(val){
+      this.onRefresh()
+    },
+    'searchForm.ruleId'(val){
+      this.onRefresh()
+    },
+    'searchForm.ruleIncludeSub'(val){
+      this.onRefresh()
+    },
+
+  },
+  created() {},
+  methods:{
+    timeScopeThisWeek(){
+      this.timeScope = [new Date(moment().startOf('week').format('YYYY-MM-DD')),new Date(moment().endOf('week').format('YYYY-MM-DD'))]
+      this.showCalendar= false
+    },
+    timeScopeLastWeek(){
+      this.timeScope = [new Date(moment().subtract(1,'week').startOf('week').format('YYYY-MM-DD')),new Date(moment().subtract(1,'week').endOf('week').format('YYYY-MM-DD'))]
+      this.showCalendar = false
+    },
+    timeScopeThisMoth(){
+      this.timeScope = [new Date(moment().startOf('month').format('YYYY-MM-DD')),new Date(moment().endOf('month').format('YYYY-MM-DD'))]
+      this.showCalendar = false
+    },
+    timeScopeLastMonth(){
+      this.timeScope = [new Date(moment().subtract(1,'month').startOf('month').format('YYYY-MM-DD')),new Date(moment().subtract(1,'month').endOf('month').format('YYYY-MM-DD'))]
+      this.showCalendar = false
+    },
+    calendarOpen(){
+      this.showCalendar = true;
+    },
+    calendarClose(){
+      this.showCalendar = false;
+    },
+    calendarConfirm(event){
+      const [start,end] = event;
+      this.timeScope = [start,end];
+      this.showCalendar = false;
+    },
+    truncateString(str,length){
+      if (str.length > length){
+      }
+      return str.length > length ? str.substring(0,length) : str;
+    },
+    onConfirmDept(deptItem){
+      if (deptItem){
+        this.searchForm.deptId = deptItem.id;
+        this.searchForm.deptName = this.truncateString(deptItem.name,3);
+      }else {
+        this.searchForm.deptId = 0;
+        this.searchForm.deptName = '全公司';
+      }
+      this.$refs.deptDropdownItem.toggle();
+    },
+    onConfirmRule(ruleId){
+      this.searchForm.ruleId = ruleId || 0;
+      this.$refs.ruleDropdownItem.toggle();
+    },
+    onRefresh(done){
+      if (!this.searchForm.startDate || !this.searchForm.endDate || !this.searchForm.ptId){
+        if (typeof done === 'function') done();
+        return;
+      }
+
+      let msg = {
+        type:'dr',
+        start_date:this.searchForm.startDate,
+        end_date:this.searchForm.endDate,
+        pt_id:this.searchForm.ptId,
+        dept_id:this.searchForm.deptId,
+        dept_include_sub:this.searchForm.deptIncludeSub ? 1 : 0,
+        item_id:0,
+        rule_id:this.searchForm.ruleId,
+        rule_include_sub:this.searchForm.ruleIncludeSub ? 1 : 0
+      }
+
+      this.$socketApiTow.sendData(msg,(res) => {
+        if (res.code !== 1 || res.type !== msg.type){
+          if (typeof done === 'function') done();
+          return;
+        }
+        this.dataList = res.result.list;
+        if (typeof done === 'function') done();
+      })
+
+
+    }
+  }
+}
+
+</script>
+
+
+
+<style scoped lang="less">
+.mrd-container {
+  background-color: white;
+
+  & .mrd-content {
+    margin-top: 0.2rem;
+    position: relative;
+    height: calc(100% - 2.1rem);
+  }
+
+}
+</style>

+ 98 - 7
src/point/view/integral/event_detail.vue

@@ -8,7 +8,10 @@
             <div class="flex-1 flex-box-ce">
               <userImage :id="eventInfo.employee_id" :img_url="eventInfo.img_url" :user_name="eventInfo.employee_name" width="1.1rem" height="1.1rem"></userImage>
               <div style="margin-left: 0.1rem;">
-                <div class="event-employee__name">{{ eventInfo.employee_name }}</div>
+                <div class="event-employee__name">
+                  {{ eventInfo.employee_name }}
+                  <van-tag type="primary" size="medium"  v-if="eventInfo && eventInfo.has_appeal" >已申诉</van-tag>
+                </div>
                 <div class="deptName">{{ deptName }}</div>
               </div>
             </div>
@@ -82,12 +85,43 @@
         <div style="height: 1.5rem;"></div>
       </scroller>
 
-      <!-- 奖扣者 ||  -->
-      <footer class="flex-box flex-v-ce footer" v-if="eventInfo.recorder_id == $userInfo().id && eventInfo.process.length == 1 && (eventInfo.event_type == 3 || eventInfo.event_type == 4)">
-        <div class="flex-2">撤销后数据将不可恢复</div>
-        <van-button type="info" @click="revocation()" class="flex-1">撤销</van-button>
+      <footer class="footer">
+        <van-row type="flex" justify="center">
+          <!--    发起申诉    -->
+          <van-col span="24" v-if="appealEnable">
+            <van-button type="info" block @click="showAppeal = true">发起申诉</van-button>
+          </van-col>
+          <!-- 奖扣者 ||  -->
+          <van-col span="24" v-else-if="eventInfo.recorder_id == $userInfo().id && eventInfo.process.length == 1 && (eventInfo.event_type == 3 || eventInfo.event_type == 4)">
+            <van-button type="info" @click="revocation()" block>撤销</van-button>
+          </van-col>
+        </van-row>
       </footer>
     </div>
+    <van-popup v-model="showAppeal" position="bottom" :style="{height:'100%',width:'100%',backgroundColor:'rgb(245, 245, 245)'}">
+      <div :style="'padding-top:' + barHeight + 'px;background-color: #238dfa;'"></div>
+      <van-nav-bar title="发起申诉" left-text="返回" @click-left="showAppeal = false" left-arrow></van-nav-bar>
+      <van-cell-group>
+        <EmployeeSelectorCell
+          title="审批人"
+          v-model="appealForm.reviewer"
+          :multi="false"
+          iconType="records"
+          :employee_list="userInfo.employee_detail.superior_list"
+          :is_employee_list="true"
+        />
+        <van-cell>
+          <Mtextarea
+            v-model="appealForm.remark"
+            placeholder="申诉原因"
+          />
+        </van-cell>
+      </van-cell-group>
+      <footer class="flex-box flex-v-ce footer">
+        <van-button type="info" block :loading="submitting" :disabled="!canAppealSubmit" @click="createAppeal">提交</van-button>
+      </footer>
+
+    </van-popup>
   </div>
 </template>
 
@@ -95,6 +129,9 @@
 import approval_process from '@/point/view/integral/approval_process'
 import Vue from 'vue'
 import { Panel, Skeleton, Image, ImagePreview, Dialog } from 'vant'
+import Footer from "../../../components/footer.vue";
+import EmployeeSelectorCell from "../../../components/EmployeeSelectorCell.vue";
+import Mtextarea from "../../../components/Mtextarea2.vue";
 
 Vue.use(Panel)
   .use(Skeleton)
@@ -103,12 +140,21 @@ Vue.use(Panel)
   .use(Dialog)
 export default {
   name: 'event_detail_info',
-  components: {approval_process },
+  components: {Mtextarea, EmployeeSelectorCell, Footer, approval_process },
   data () {
     return {
+      userInfo:this.$userInfo(),
       loading: true,
       eventInfo: { remark: { customize: '' }, process: [] },
       deptName:'',
+      siteAppealEnable: false,
+      showAppeal: false,
+      barHeight:'',
+      appealForm:{
+        reviewer:[],
+        remark:''
+      },
+      submitting:false
     }
   },
   computed: {
@@ -117,15 +163,30 @@ export default {
     },
     hasAttachmentFile () {
       return Array.isArray(this.eventInfo.files) && this.eventInfo.files.length > 0
+    },
+    appealEnable(){
+      return this.eventInfo && this.userInfo && this.siteAppealEnable && this.eventInfo.employee_id === this.userInfo.id
+    },
+    canAppealSubmit(){
+      return this.appealEnable && this.appealForm.reviewer.length === 1 && !this.submitting
     }
   },
   methods: {
+    getConfig(){
+      let self = this
+      self.$axiosUser('get','/api/pro/integral/site/config')
+        .then(res => {
+          if (res.data.code === 1){
+            self.siteAppealEnable = res.data.data.appeal === 1
+          }
+        })
+    },
     // 撤销奖扣
     revocation () {
       var that = this
       Dialog.confirm({
         title: '提示',
-        message: '您确定要撤销此项吗?'
+        message: '撤销后数据将不可恢复,确定要撤销此项吗?'
       }).then(() => {
         let data = { target_id: this.$route.query.id, type: 1}
         this.$axiosUser('post', '/api/pro/integral/review/prize/destroy', data).then(res => {
@@ -165,10 +226,40 @@ export default {
           this.$toast.clear()
           this.loading = false
         })
+    },
+    createAppeal(){
+      let self = this
+      self.submitting = true
+      self.$toast.loading({message:'提交中...'})
+      let params = {
+        reviewer_id:self.appealForm.reviewer[0].id,
+        events:[{id:self.eventInfo.event_id,remark:self.appealForm.remark}]
+      }
+      self.$axiosUser('post','api/pro/integral/appeal/create',params)
+        .then(res => {
+          if (res.data.code === 1){
+            self.appealForm.reviewer = []
+            self.appealForm.remark = ''
+            self.$toast('申诉已发起')
+            self.showAppeal = false
+          }else {
+            self.$toast(res.data.msg)
+          }
+        })
+        .finally(() => {
+          self.$toast.clear()
+          self.submitting = false
+        })
+    }
+  },
+  created() {
+    if (window.plus){
+      this.barHeight = window.plus.navigator.getStatusbarHeight()
     }
   },
   mounted () {
     this.getEventDetail()
+    this.getConfig()
   }
 }
 </script>

+ 49 - 10
src/point/view/integral/event_list.vue

@@ -1,12 +1,17 @@
 <template>
   <div class="event-list__container">
     <van-nav-bar title="积分事件" left-text="返回" @click-left="$route_back" left-arrow></van-nav-bar>
+    <van-notice-bar
+      left-icon="volume-o"
+      text="积分事件列表,根据角色数据权限返回对应的人员积分事件.用户可对自己的积分事件进行申诉,审批通过后积分事件将自动删除"
+    />
     <van-search placeholder="请输入事件内容搜索" v-model="searchParams.keyword" @input="keyVal()" />
     <van-dropdown-menu>
       <van-dropdown-item :title="dateItemTitle" ref="dateDropdownItem"><DateSelectorDropdown :title.sync="dateItemTitle" @onConfirm="onConfirmDate" /></van-dropdown-item>
       <van-dropdown-item :title="deptDropdownItemTitle" ref="deptDropdownItem"><DeptSelectorDropdown @onConfirm="onConfirmDept" /></van-dropdown-item>
-      <van-dropdown-item title="规则分类" ref="ruleDropdownItem"><RuleCategorySelDropdown @onConfirm="onConfirmRule" @onCancel="searchParams.rule_id = null"/></van-dropdown-item>
+      <van-dropdown-item title="规则" ref="ruleDropdownItem"><RuleCategorySelDropdown @onConfirm="onConfirmRule" @onCancel="searchParams.rule_id = null"/></van-dropdown-item>
       <van-dropdown-item :title="pointTypeDropdownItemTitle" :options="pointTypeOption" v-model="pointType" @change="onChangePointType" />
+      <van-dropdown-item v-model="searchParams.add_subtract"  :options="[{text:'全部',value:0},{text:'奖分',value: 1},{text:'扣分',value: 2}]" ><van-icon name="list-switch" slot="title" size="1.5em" /></van-dropdown-item>
     </van-dropdown-menu>
     <div class="event-list__content">
       <scroller ref="scroller" :on-refresh="refresh" :on-infinite="infinite" noDataText="我也是有底线的" :list="eventData">
@@ -27,7 +32,7 @@
               <span class="event-item__value red" v-if="item.point >= 0">+{{ item.point }}{{ $getTypesName(item.pt_id)}}</span>
               <span class="event-item__value green" v-else>{{ item.point }}{{ $getTypesName(item.pt_id) }}</span>
             </div>
-            <div class="event-content__text">
+            <div class="event-content__text input-ccc">
               <span>{{ item.remark }}</span>
             </div>
             <div class="event-time__text">
@@ -46,7 +51,7 @@ import Vue from 'vue';
 import moment from 'moment';
 
 import { _debounce, _throttle } from '@/utils/auth';
-import { DropdownMenu, DropdownItem, Empty, Search } from 'vant';
+import { DropdownMenu, DropdownItem, Empty, Search,NoticeBar } from 'vant';
 import DateSelectorDropdown from '@/components/DateSelectorDropdown';
 import DeptSelectorDropdown from '@/components/DeptSelectorDropdown';
 import RuleCategorySelDropdown from '@/components/RuleCategorySelDropdown';
@@ -54,7 +59,8 @@ import RuleCategorySelDropdown from '@/components/RuleCategorySelDropdown';
 Vue.use(Empty)
   .use(DropdownMenu)
   .use(DropdownItem)
-  .use(Search);
+  .use(Search)
+  .use(NoticeBar)
 
 export default {
   name: 'event_list',
@@ -67,6 +73,7 @@ export default {
       dateItemTitle: '本月',
       deptDropdownItemTitle: '全公司',
       eventData: [],
+      hasFinish: false,
       searchParams: {
         dept_ids: null,
         end_day: null,
@@ -77,10 +84,25 @@ export default {
         page_size: 10,
         rule_id: null,
         pt_id: pointTypeId,
-        keyword: ''
+        keyword: '',
+        add_subtract:0
       },
       types_list: {},
-      month: moment().format('YYYY-MM')
+      month: moment().format('YYYY-MM'),
+      add_subtract_items: [
+        {
+          value: '全部',
+          id: 0
+        },
+        {
+          value: '奖分',
+          id: 1
+        },
+        {
+          value: '扣分',
+          id: 2
+        },
+      ]
     };
   },
   components: {
@@ -98,7 +120,7 @@ export default {
     },
     pointTypeDropdownItemTitle() {
       if (this.pointType === -1) {
-        return '积分类';
+        return '积分类';
       }
       return this.pointTypeOption.find(a => a.value === this.pointType).text;
     },
@@ -135,9 +157,15 @@ export default {
     },
     refresh(done) {
       this.searchParams.page = 1;
+      this.hasFinish = false
       this.getEventData(done);
     },
     infinite(done) {
+      if (this.hasFinish){
+        done()
+        this.$refs.scroller.finishPullToRefresh()
+        return
+      }
       this.searchParams.page++;
       this.getEventData(done);
     },
@@ -216,16 +244,27 @@ export default {
             } else {
               this.eventData = this.eventData.concat(list);
             }
-            scroller.finishInfinite(list.length !== this.searchParams.page_size);
+            callback && callback();
+            scroller.finishPullToRefresh();
+
+            this.hasFinish = list.length !== this.searchParams.page_size
+
+            scroller.finishInfinite(this.hasFinish);
           } else {
-            scroller.finishInfinite(true);
+            this.hasFinish = true
+            scroller.finishInfinite(this.hasFinish);
           }
         })
         .finally(() => {
           this.loading = false;
-          callback && callback();
         });
     }
+  },
+  watch: {
+    'searchParams.add_subtract'(val,oVal){
+      this.searchParams.page = 1;
+      this.$refs.scroller.triggerPullToRefresh();
+    }
   }
 };
 </script>

+ 1 - 1
src/point/view/integral/integral_application.vue

@@ -19,7 +19,7 @@
             </template>
           </van-cell>
           <!--选择规则  -->
-          <RuleCategorySelectorCell v-if="rule_switch" required  ref="rule_selector" name="选择规则"  title="选择规则" v-model="itemRule"></RuleCategorySelectorCell>
+          <RuleCategorySelectorCell v-if="rule_switch" required  ref="rule_selector" name="选择规则"  title="选择规则" v-model="itemRule" scope/>
         </van-cell-group>
 
         <div v-for="(item, index) in items" :key="index">

+ 2 - 2
src/point/view/integral/integral_entry_n.vue

@@ -16,9 +16,9 @@
             </template>
           </van-cell>
           <!--选择规则  -->
-          <RuleCategorySelectorCell v-if="rule_switch" required  ref="rule_selector" name="选择规则"  title="选择规则" v-model="itemRule" :ptId="ptId"></RuleCategorySelectorCell>
+          <RuleCategorySelectorCell v-if="rule_switch" required  ref="rule_selector" name="选择规则"  title="选择规则" v-model="itemRule" :ptId="ptId" scope></RuleCategorySelectorCell>
           <!--选择分类  -->
-          <CategorySelectorCell v-if="!rule_switch" title="选择分类" ref="rule_selector2" v-model="ruleCate" required :ptId="ptId"></CategorySelectorCell>
+          <CategorySelectorCell v-if="!rule_switch" title="选择分类" ref="rule_selector2" v-model="ruleCate" required :ptId="ptId" scope></CategorySelectorCell>
         </van-cell-group>
 
         <div v-for="(item, index) in items" :key="index">

+ 2 - 2
src/point/view/integral/manager_reward_deduction.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="mrd-container">
-   <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="department" slot="right">
         <DeptSelectorBtn title="选择部门" v-model="dept" :multi="false"></DeptSelectorBtn>
       </div>
@@ -168,7 +168,7 @@ export default {
         complete:this.checkedAllStandard? 1:0
       };
       this.$socketApiTow.sendData(params,(res)=>{
-      	if (res.code == 1&&res.type=='es') {
+      	if (res.code === 1&&res.type === params.type) {
             let list=res.result.list;
             if (this.searchParams.page === 1) {
               this.list = list

+ 336 - 0
src/point/view/integral/reward_deduction_search.vue

@@ -0,0 +1,336 @@
+
+
+<template>
+  <div class="mrd-container">
+    <van-nav-bar title="奖扣信息" left-text="返回" @click-left="$route_back" left-arrow />
+    <van-notice-bar color="#1989fa" background="#ecf9ff" left-icon="info-o" mode="closeable">
+      管理者奖扣任务均为B分,对A分不做要求
+    </van-notice-bar>
+    <van-cell-group>
+      <DeptSelectorBtn title="选择部门" v-model="dept" :multi="false" :block="true"></DeptSelectorBtn>
+      <van-cell title="姓名" :value="searchForm.keyword" @click="showKeyword = true" :center="true" >
+        <van-icon name="arrow" slot="right-icon" v-if="!searchForm.keyword" />
+        <van-icon name="close" slot="right-icon" v-else style="margin-left: 10px" color="#646464" @click.stop="searchForm.keyword = ''" />
+      </van-cell>
+      <van-cell title="时间" :value="timeScopeText" is-link @click="showTimeScope = true" />
+    </van-cell-group>
+
+    <div class="mrd-content">
+      <scroller
+        ref="scroller"
+        :on-refresh="onRefresh"
+      >
+        <div class="mrd-list__item" v-for="item in dataList" :key="item.id" >
+          <div class="mrd-item__header">
+            <span>{{ item.name }}</span>
+          </div>
+          <div class="mrd-item__content">
+            <div class="mrd-item">
+              <span class="mrd-item__value">{{ item.reward_point}}</span>
+              <span class="mrd-item__label">奖分</span>
+            </div>
+            <div class="mrd-item">
+              <span class="mrd-item__value">{{ item.deduction_point}}</span>
+              <span class="mrd-item__label">扣分</span>
+            </div>
+            <div class="mrd-item">
+              <span class="mrd-item__value black-color">{{ item.ratio ? item.ratio : '--' }}</span>
+              <span class="mrd-item__label">奖扣比例</span>
+            </div>
+            <div class="mrd-item">
+              <span class="mrd-item__value black-color">{{ item.exec}}</span>
+              <span class="mrd-item__label">奖扣人次</span>
+            </div>
+          </div>
+        </div>
+        <noData :list="dataList" />
+
+      </scroller>
+    </div>
+
+
+<!--  姓名输入  -->
+    <van-dialog
+      v-model="showKeyword"
+      :close-on-click-overlay="true"
+      @confirm="searchForm.keyword = keyword"
+    >
+      <van-field label="姓名" placeholder="搜索姓名" v-model="keyword"></van-field>
+    </van-dialog>
+<!--  日期区间选择  -->
+    <van-calendar
+      v-model="showTimeScope"
+      type="range"
+      :allow-same-day="true"
+      :min-date="minDate"
+      :max-date="maxDate"
+      :default-date="timeScope"
+      :show-confirm="false"
+      color="#26A2FF"
+      @close="calendarClose"
+      @confirm="calendarConfirm"
+    />
+
+  </div>
+
+</template>
+
+
+<script>
+import Vue from 'vue'
+import moment from 'moment'
+import {Calendar, Empty, NoticeBar} from 'vant'
+import DeptSelectorBtn from '@/components/DeptSelectorBtn'
+import {_debounce } from '@/utils/auth'
+Vue.use(Empty).use(Calendar).use(NoticeBar)
+export default {
+  name: 'reward_deduction_search',
+  components:{DeptSelectorBtn},
+  data(){
+
+
+    let today = new Date();
+    let minDate = new Date();
+    minDate.setTime(today.getTime() - 3600 * 1000 * 24 * 30 * 6);
+    let maxDate = new Date(today.getFullYear(),today.getMonth(),1);
+    maxDate.setMonth(maxDate.getMonth() + 1);
+    maxDate.setDate(0);
+
+    let startDate = new Date();
+    startDate.setTime(today.getTime() - 3600 * 1000 * 24 * 7);
+    startDate = moment(startDate).format('YYYY-MM-DD');
+    let endDate = moment(today).format('YYYY-MM-DD');
+
+    return{
+      dept:[],
+      searchForm:{
+        startDate:startDate,
+        endDate:endDate,
+        deptId:0,
+        keyword:'',
+        page:1,
+        pageSize:10
+      },
+      showKeyword:false,
+      keyword:'',
+      showTimeScope:false,
+      timeScope:[new Date(startDate),new Date(endDate)],
+      minDate:minDate,
+      maxDate:maxDate,
+      dataList:[],
+      isLoading:false,
+      isFinished:true
+    }
+  },
+  watch:{
+    dept(val){
+      if (Array.isArray(val) && val.length > 0) {
+        this.searchForm.deptId = val[0].dept_id
+      } else {
+        this.searchForm.deptId = 0
+      }
+    },
+    timeScope(val){
+      this.searchForm.startDate = moment(val[0]).format('YYYY-MM-DD');
+      this.searchForm.endDate = moment(val[1]).format('YYYY-MM-DD');
+    },
+    'searchForm.deptId'(val,oVal){
+      if (val === oVal) return;
+      this.$refs.scroller.triggerPullToRefresh();
+    },
+    'searchForm.keyword'(val,oVal){
+      if (val === oVal) return;
+      this.$refs.scroller.triggerPullToRefresh();
+    },
+    'searchForm.startDate'(){
+      this.$refs.scroller.triggerPullToRefresh();
+    },
+    'searchForm.endDate'(){
+      this.$refs.scroller.triggerPullToRefresh();
+    },
+  },
+  computed:{
+    timeScopeText(){
+      return moment(this.searchForm.startDate).format('MM/DD') + '-' + moment(this.searchForm.endDate).format('MM/DD')
+    }
+  },
+  methods:{
+    calendarClose(){
+      this.showTimeScope = false;
+    },
+    calendarConfirm(event){
+      const [start,end] = event;
+      this.timeScope = [start,end];
+      this.showTimeScope = false;
+    },
+    onRefresh(done){
+      if (!this.searchForm.startDate || !this.searchForm.endDate) {
+        if (typeof done === 'function') done();
+        return;
+      }
+      let msg = {
+        type:'ess',
+        dept_id: this.searchForm.deptId,
+        employee_id:this.$userInfo().id,
+        start_date: this.searchForm.startDate,
+        end_date: this.searchForm.endDate,
+        keyword: this.searchForm.keyword,
+        page:0,
+        page_size:10
+      }
+      this.$socketApiTow.sendData(msg,(res)=>{
+        if (res.code !== 1 || res.type !== msg.type){
+          if (typeof done === 'function') done();
+          return;
+        }
+        this.dataList = res.result.list;
+        if (typeof done === 'function') done();
+      })
+    },
+  }
+}
+
+</script>
+
+<style scoped lang="less">
+.mrd-container {
+  & /deep/ .department .van-button {
+    background-color: transparent;
+    border: none;
+    color: #fff;
+    max-width: 2.5rem;
+    padding: 0;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+
+  & .mrd-filter__wrap {
+    position: relative;
+    padding: 0.15rem 0.32rem;
+
+    & /deep/ .van-checkbox__label {
+      font-size: 0.28rem;
+      color: #909399;
+    }
+
+    & /deep/ .van-checkbox__icon {
+      position: relative;
+      top: -0.05em;
+    }
+  }
+
+  & .mrd-content {
+    position: relative;
+    height: calc(100% - 5rem);
+  }
+
+  & .mrd-list__item {
+    margin-bottom: 0.24rem;
+    padding: 0 0.32rem 0.32rem 0.32rem;
+    font-size: 0.32rem;
+    color: #303133;
+    background: #fff;
+    touch-action: none;
+
+    & .mrd-item__header {
+      display: flex;
+      padding: 0.24rem 0;
+      align-items: center;
+
+      & .mrd-item__icon {
+        display: flex;
+        margin-right: 0.16rem;
+        width: 0.56rem;
+        height: 0.56rem;
+        font-size: 0.24rem;
+        color: #fff;
+        background: #26a2ff;
+        align-items: center;
+        justify-content: center;
+        border-radius: 100%;
+      }
+
+      & .mrd-item__standard {
+        margin-left: 0.2rem;
+        padding: 0.02rem 0.08rem;
+        font-size: 0.24rem;
+        color: #fff;
+        background: #53B87F;
+        border-radius: 0.06rem;
+      }
+    }
+
+    & .mrd-item__content {
+      display: flex;
+      flex-direction: row;
+
+      & .mrd-item {
+        display: flex;
+        flex: 1;
+        align-items: center;
+        justify-content: center;
+        flex-direction: column;
+
+        & /deep/ .icon-doubt {
+          position: absolute;
+          top: 0.13rem;
+          right: -0.3rem;
+        }
+
+        & .mrd-item__value {
+          color: #26a2ff;
+          font-size: 0.44rem;
+          font-weight: 600;
+
+          &.black-color {
+            color: #444444;
+          }
+        }
+
+        & .mrd-item__label {
+          position: relative;
+          display: inline-block;
+          padding-top: 0.04rem;
+          font-size: 0.28rem;
+          color: #303133;
+          font-weight: 400;
+        }
+
+        & .mrd-item__target {
+          padding-top: 0.08rem;
+          font-size: 0.24rem;
+          color: #909399;
+          font-weight: 400;
+        }
+      }
+    }
+
+    .mrd-standard__wrap {
+      display: flex;
+      padding-top: 0.1rem;
+      flex-direction: row;
+
+      .mrd-standard__item {
+        display: flex;
+        flex: 1;
+        justify-content: center;
+
+        & .mrd-standard__text {
+          padding: 0.02rem 0.08rem;
+          font-size: 0.24rem;
+          color: #fff;
+          background: #53B87F;
+          border-radius: 0.06rem;
+        }
+      }
+    }
+  }
+
+  & .van-list{
+    background-color: #F5F7FA;
+  }
+}
+
+
+</style>

+ 5 - 1
src/point/view/integral/rule_category_add.vue

@@ -4,7 +4,7 @@
     <div class="body_com has_header">
       <scroller>
         <van-cell-group>
-          <van-field v-model="data.name" label="分类名称" name="名称" placeholder="请输入名称" v-validate="'required|max:10'" required maxlength="10" show-word-limit/>
+          <van-field v-model="data.name" label="分类名称" name="名称" placeholder="请输入名称" v-validate="'required|max:20'" required maxlength="20" show-word-limit @input="onNameInput"/>
         </van-cell-group>
         <van-cell-group>
           <CategorySelectorCell title="选择父级分类" v-model="rule_cate" :max="2" :multi="false"></CategorySelectorCell>
@@ -20,6 +20,7 @@
 
 import CategorySelectorCell from '@/components/CategorySelectorCell'
 import DeptSelectorCell from '@/components/DeptSelectorCell'
+import {specialFilter} from "../../../utils/helper";
 export default {
   name: 'rule_category_add',
   components: {
@@ -87,6 +88,9 @@ export default {
         self.send_loading = false
         self.$toast.clear()
       })
+    },
+    onNameInput(v){
+      this.data.name = specialFilter(v)
     }
   },
   created () {

+ 6 - 2
src/point/view/integral/rule_category_edit.vue

@@ -4,7 +4,7 @@
     <div class="body_com has_header">
       <scroller>
         <van-cell-group>
-          <van-field v-model="data.name" label="分类名称" name="名称" placeholder="请输入名称" v-validate="'required|max:10'" required  maxlength="10" show-word-limit/>
+          <van-field v-model="data.name" label="分类名称" name="名称" placeholder="请输入名称" v-validate="'required|max:10'" required  maxlength="10" show-word-limit @input="onNameInput"/>
         </van-cell-group>
         <van-cell-group>
           <CategorySelectorCell title="选择父级分类" v-model="rule_cate" :max="2" :multi="false"></CategorySelectorCell>
@@ -23,6 +23,7 @@
 
 import CategorySelectorCell from '@/components/CategorySelectorCell'
 import DeptSelectorCell from '@/components/DeptSelectorCell'
+import {specialFilter} from "../../../utils/helper";
 export default {
   name: 'rule_category_edit',
   components: {
@@ -116,13 +117,16 @@ export default {
         self.send_loading = false
         self.$toast.clear()
       })
+    },
+    onNameInput(v){
+      this.data.name = specialFilter(v)
     }
   },
   created () {
     if (this.$route.query.rule_id) {
       this.data.rule_id = this.$route.query.rule_id
       this.data.pid = this.$route.query.pid
-      this.data.name = this.$route.query.rule_name
+      this.data.name = specialFilter(this.$route.query.rule_name)
       let departments = JSON.parse(this.$route.query.departments)
       if (departments.length > 0) {
         this.depts = departments.map(item => {

+ 5 - 1
src/point/view/integral/rule_item_add.vue

@@ -5,7 +5,7 @@
       <scroller>
         <van-cell-group>
           <van-cell required>
-            <Mtextarea required v-model="item.remark" placeholder="输入规则内容" :text_max="300" :imgs_max="3"></Mtextarea>
+            <Mtextarea required v-model="item.remark" placeholder="输入规则内容" :text_max="300" :imgs_max="3" @input="onRemarkInput" ></Mtextarea>
           </van-cell>
         </van-cell-group>
         <van-cell-group>
@@ -65,6 +65,7 @@ import { Switch } from 'vant'
 import Mtextarea from '@/components/Mtextarea'
 import NumberInput from '@/components/NumberInput'
 import CategorySelectorCell from '@/components/CategorySelectorCell'
+import {specialFilter} from "../../../utils/helper";
 
 Vue.use(Switch)
 export default {
@@ -181,6 +182,9 @@ export default {
           self.types_list.push(list[i])
         }
       }
+    },
+    onRemarkInput(v){
+      this.item.remark = specialFilter(v)
     }
   },
   created () {

+ 6 - 1
src/point/view/integral/rule_item_edit.vue

@@ -4,7 +4,7 @@
     <div class="body_com has_header">
       <scroller>
         <van-cell-group>
-          <van-cell><Mtextarea v-model="item.remark" placeholder="输入规则内容" :text_max="300" :imgs_max="3"></Mtextarea></van-cell>
+          <van-cell><Mtextarea v-model="item.remark" placeholder="输入规则内容" :text_max="300" :imgs_max="3" @input="onRemarkInput"></Mtextarea></van-cell>
         </van-cell-group>
         <van-cell-group>
           <van-cell title="分值" class="cell-right-4rem">
@@ -41,6 +41,7 @@ import NumberInput from '@/components/NumberInput';
 import CategorySelectorCell from '@/components/CategorySelectorCell';
 import Vue from 'vue';
 import { Switch } from 'vant';
+import {specialFilter} from "../../../utils/helper";
 
 Vue.use(Switch);
 export default {
@@ -175,6 +176,9 @@ export default {
           this.types_list.push(list[i]);
         }
       }
+    },
+    onRemarkInput(v){
+      this.item.remark = specialFilter(v)
     }
   },
   created() {
@@ -189,6 +193,7 @@ export default {
         this.rule_cate = [{ id: this.item.rule_id * 1, name: this.$route.query.rule_name }];
       }
     }
+    this.item.remark = specialFilter(this.item.remark)
     this.get_point_types();
   }
 };

+ 242 - 15
src/point/view/pointHome.vue

@@ -13,8 +13,8 @@
               <div class="blue" style="font-size: 26px;font-weight: 600;">{{showPoint? userStatistics.b:userStatistics.a}}</div>
             </div>
             <div class="point-box flex-box">
-              <span @click.stop="showPoint=!showPoint" style="border-top-left-radius: 4px;border-bottom-left-radius: 4px;border-right: none;" :class="showPoint? 'pointActive':''">B分</span>
-              <span @click.stop="showPoint=!showPoint" style="border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-left: none;" :class="!showPoint? 'pointActive':''">A分</span>
+              <span class="tp" @click.stop="showPoint=!showPoint" style="border-top-left-radius: 4px;border-bottom-left-radius: 4px;border-right: none;" :class="showPoint? 'pointActive':''">B分</span>
+              <span class="tp" @click.stop="showPoint=!showPoint" style="border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-left: none;" :class="!showPoint? 'pointActive':''">A分</span>
             </div>
           </div>
           <div class="flex-box-ce">
@@ -41,12 +41,25 @@
           </div>
         </div>
         <van-grid :border="false" style="background-color: #fff;position: relative;" class="border-bottom">
-
           <van-grid-item v-for="(app, app_index) in topMenuList" :dot="app.dot" :badge="app.badge" :key="app.code" @click="openUrl(4,app)" :text="app.code">
             <template slot="icon">
               <img :src="app.icon" style="-webkit-touch-callout: none;" />
             </template>
           </van-grid-item>
+          <van-grid-item @click="goAppeal" text="申诉">
+            <template #icon>
+              <img src="static/images/caback6.png" style="-webkit-touch-callout: none;"/>
+            </template>
+          </van-grid-item>
+          <van-grid-item @click="goDeptRank">
+            <template #text>
+              <van-loading v-if="!deptRank" type="spinner" size="10px"/>
+              <span class="van-grid-item__text" v-else>部门对比</span>
+            </template>
+            <template #icon>
+              <img src="static/images/callback1.png" style="-webkit-touch-callout: none;"/>
+            </template>
+          </van-grid-item>
 
           <van-grid-item v-for="(app, app_index) in common_menu" :key="app_index" @click="url_jump(app)" :icon="app.icon" :text="app.code">
             <template slot="icon">
@@ -100,6 +113,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;">
@@ -132,11 +146,45 @@
             </div>
           </div>
         </div>
-        <div class="rankingLists flex-box-ce flex-center-center" @click="openUrl(3)" style="border-top: 1px solid #f1f1f1;">
-          <span>查看所有管理者奖扣</span>
-          <i class="van-icon van-icon-arrow van-cell__right-icon"></i>
-        </div>
+<!--        <div class="rankingLists flex-box-ce flex-center-center" @click="openUrl(3)" style="border-top: 1px solid #f1f1f1;">-->
+<!--          <span>查看管理者奖扣目标</span>-->
+<!--          <i class="van-icon van-icon-arrow van-cell__right-icon"></i>-->
+<!--        </div>-->
+<!--        <div class="rankingLists flex-box-ce flex-center-center" @click="openUrl(3)" style="border-top: 1px solid #f1f1f1;">-->
+<!--          <span>查看管理者奖扣信息</span>-->
+<!--          <i class="van-icon van-icon-arrow van-cell__right-icon"></i>-->
+<!--        </div>-->
+        <van-row type="flex" justify="center" align="center">
+          <van-col span="12" @click="openUrl(3)">
+            <div class="van-hairline--right" style="text-align: center; color: #909399; height: 3em; line-height: 3em; font-size: 0.28rem;">
+              <span style="line-height: 3em" >查看奖扣目标</span>
+            </div>
+          </van-col>
+          <van-col span="12" @click="openUrl(7)">
+            <div style="text-align: center; color: #909399;  height: 3em; line-height: 3em; font-size: 0.28rem;">
+              <span >查看奖扣信息</span>
+            </div>
+          </van-col>
+        </van-row>
       </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,28 +194,63 @@
         <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"
+      :show-confirm="false"
+      color="#26A2FF"
+    >
+      <template v-slot:title >
+        <van-row>
+          <van-col span="20">
+            <van-row type="flex" justify="space-between" style="height: 1rem;">
+              <van-col span="6" style="text-align: center; align-self: center;">
+                <van-tag type="success" size="medium" @click="timeScopeThisWeek">本周</van-tag>
+              </van-col>
+              <van-col span="6" style="text-align: center; align-self: center;">
+                <van-tag type="success" size="medium" @click="timeScopeLastWeek">上周</van-tag>
+              </van-col>
+              <van-col span="6" style="text-align: center; align-self: center;">
+                <van-tag type="primary" size="medium" @click="timeScopeThisMoth">本月</van-tag>
+              </van-col>
+              <van-col span="6" style="text-align: center; align-self: center;">
+                <van-tag type="primary" size="medium" @click="timeScopeLastMonth">上月</van-tag>
+              </van-col>
+            </van-row>
+          </van-col>
+        </van-row>
+      </template>
+    </van-calendar>
   </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 { NoticeBar, Swipe, SwipeItem, Cell, Dialog,Popup,Loading  } from 'vant';
 Vue.use(NoticeBar)
   .use(Swipe)
   .use(SwipeItem)
   .use(Cell)
+  .use(Loading)
   .use(Popup);
 
 export default {
   name: 'pointHome',
   data() {
     return {
+      deptRank:false,
       userMonth:{task:{reward:{},deduction:{},exec:{}},ratio:{}},
 
-      rankingList: [], // 我的排名列表
+      // rankingList: [], // 我的排名列表
       rankingTotal: 0, // 我的排名列表数
       situationChart: '', // 管理者奖扣
       rankingIndex: 1,
@@ -205,6 +288,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 +312,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 => {
@@ -219,6 +340,22 @@ export default {
     });
   },
   methods: {
+    timeScopeThisWeek(){
+      this.pkTimeScope = [new Date(moment().startOf('week').format('YYYY-MM-DD')),new Date(moment().endOf('week').format('YYYY-MM-DD'))]
+      this.pk.showDocDatePicker= false
+    },
+    timeScopeLastWeek(){
+      this.pkTimeScope = [new Date(moment().subtract(1,'week').startOf('week').format('YYYY-MM-DD')),new Date(moment().subtract(1,'week').endOf('week').format('YYYY-MM-DD'))]
+      this.pk.showDocDatePicker = false
+    },
+    timeScopeThisMoth(){
+      this.pkTimeScope = [new Date(moment().startOf('month').format('YYYY-MM-DD')),new Date(moment().endOf('month').format('YYYY-MM-DD'))]
+      this.pk.showDocDatePicker = false
+    },
+    timeScopeLastMonth(){
+      this.pkTimeScope = [new Date(moment().subtract(1,'month').startOf('month').format('YYYY-MM-DD')),new Date(moment().subtract(1,'month').endOf('month').format('YYYY-MM-DD'))]
+      this.pk.showDocDatePicker = false
+    },
     getCount(done) {
       var http1 = this.$axiosUser('get','/api/pro/integral/review/list', { type: 'waiting', page: 1,page_size:1, pt_id: 0, source_type: 0 }); // 获取为审批数量
       var http2 = this.$axiosUser('get','/api/pro/integral/work/list', { status: 'running', page: 1,page_size:1, pt_id: 0 }); // 获取任务数
@@ -310,7 +447,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 +608,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;
@@ -494,8 +635,12 @@ export default {
               ratio: ratio,
               target_ratio: target_ratio
             }
-            this.userMonth=data
-            this.$socketApiTow.closewebsocket();
+            this.userMonth=data;
+
+            //ws数据初始化完成,部门排名才可以点击
+            this.deptRank = true;
+            // this.$socketApiTow.closewebsocket();
+
         }
       }, true);
     },
@@ -544,9 +689,88 @@ export default {
           this.$router.push({ name: 'statistics_personal_a', query: { month: this.month } });
           break;
         }
+        case 7: {
+          this.$router.push({ name: 'reward_deduction_search' })
+          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;
+
+        //ws数据初始化完成,部门排名才可以点击
+        this.deptRank = true;
+      })
+      this.$nextTick(() => {
+        setTimeout(() => {
+          this.restoreScrollerPosition()
+        },50)
+      })
+    },
+    goDeptRank(){
+      if (!this.deptRank) return;
+      this.$router.push({ name: 'dept_rank' });
+    },
+    goAppeal(){
+      this.$router.push({name:'appeal'})
     }
   },
+  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>
 
@@ -562,7 +786,7 @@ export default {
 .point-box{
    border-radius: 2px;
 }
-.point-box span{
+.point-box .tp{
   padding: 0rem 0.2rem;
   border: 1px solid #c0c4cc;
   height: 0.4rem;
@@ -849,5 +1073,8 @@ export default {
   }
 }
 
+.dept-rank-active{
+  background-color: #F1F1F1;
+}
 
 </style>

+ 529 - 0
src/point/view/task/TaskEdit.vue

@@ -0,0 +1,529 @@
+<template>
+  <div>
+    <van-nav-bar
+      title="悬赏更新"
+      left-text="返回"
+      @click-left="$route_back"
+      left-arrow
+    />
+    <div class="content">
+      <scroller :is-need="isNeed">
+        <van-cell-group>
+          <van-cell required>
+            <Mtextarea
+              v-model="formData.task_name"
+              name="任务内容"
+              v-validate="'required|max:20'"
+              placeholder="请输入任务内容"
+              :text_max="20"
+              :imgs_max="3"
+              images
+              :imgs.sync="formData.file_list"
+            ></Mtextarea>
+          </van-cell>
+        </van-cell-group>
+
+        <van-cell-group class="point-field">
+          <van-cell title="积分类型" required id="task_types">
+            <template slot="right-icon">
+              <van-radio-group v-model="formData.pt_id" direction="horizontal" class="radio_button">
+                <van-radio checked-color class="list" :name="item.id" v-for="(item, index) in pts" v-if="item.code !== 'JX'" :key="index">{{ item.name }}</van-radio>
+              </van-radio-group>
+            </template>
+          </van-cell>
+          <van-cell title="指定规则">
+            <template slot="right-icon">
+              <van-radio-group
+                v-model="formData.rule_type"
+                direction="horizontal"
+              >
+                <van-radio class="list" :name="0" >
+                  <span class="rule_type_span">不指定</span>
+                </van-radio>
+                <van-radio class="list" :name="1" >
+                  <span class="rule_type_span">分类</span>
+                </van-radio>
+                <van-radio class="list" :name="2" >
+                  <span class="rule_type_span">规则</span>
+                </van-radio>
+              </van-radio-group>
+            </template>
+          </van-cell>
+
+          <!--     选择分类     -->
+          <CategorySelectorCell
+            v-if="formData.rule_type === 1"
+            title="细则分类"
+            v-model="rules"
+            required
+            :pt-id="formData.pt_id"
+            :multi="false"
+            scope
+          />
+
+          <!--选择规则  -->
+          <RuleCategorySelectorCell
+            v-if="formData.rule_type === 2"
+            :pt-id="formData.pt_id"
+            required
+            name="请选择积分规则"
+            title="积分规则"
+            v-model="rule_items"
+            scope
+            :multi="false"
+          >
+            <template slot="label">
+              <span style="color: red">{{ruleItemLabel}}</span>
+            </template>
+          </RuleCategorySelectorCell>
+
+          <van-cell title="任务积分" style="padding:0 0.32rem; padding-top:0.16rem;" :border="false" required/>
+          <NumberInput v-model="formData.base_point" v-validate="'required'"  :min="minPoint" :max="maxPoint"/>
+        </van-cell-group>
+
+        <van-cell-group>
+          <EmployeeSelectorCell
+            required
+            title="审批人"
+            iconType="records"
+            :show_manager_only="true"
+            v-model="reviewer"
+            v-validate="'required'"
+            name="审批人"
+            :multi="false"
+          />
+          <DateTimeCell
+            required
+            title="截止时间"
+            v-validate="'required'"
+            name="截止时间"
+            v-model="formData.expire_time"
+          />
+          <van-field v-model="formData.ahead_award_point" type="digit">
+            <template slot="label">
+              <div class="flex-box-ce">
+                <span>提前奖分(天)</span>
+                <span class="flex-1 red" style="text-align: right;">+</span>
+              </div>
+            </template>
+          </van-field>
+          <van-field v-model="formData.ahead_award_point_limit" type="digit" label="奖分上限">
+            <template slot="label">
+              <div class="flex-box-ce">
+                <span>奖分上限</span>
+                <span class="flex-1 red" style="text-align: right;">+</span>
+              </div>
+            </template>
+          </van-field>
+          <van-field v-model="formData.timeout_deduction_point" type="digit" label="逾期扣分(天)">
+            <template slot="label">
+              <div class="flex-box-ce">
+                <span>逾期扣分(天)</span>
+                <span class="flex-1 green" style="text-align: right;">-</span>
+              </div>
+            </template>
+          </van-field>
+          <van-field v-model="formData.timeout_deduction_point_limit" type="digit" label="扣分上限">
+            <template slot="label">
+              <div class="flex-box-ce">
+                <span>扣分上限</span>
+                <span class="flex-1 green" style="text-align: right;">-</span>
+              </div>
+            </template>
+          </van-field>
+        </van-cell-group>
+
+        <van-cell-group :border="false">
+          <van-cell title="任务备注"/>
+          <van-cell>
+            <Mtextarea v-model="formData.task_remark" placeholder="请输入关于任务备注" :text_max="300"/>
+          </van-cell>
+          <DeptSelectorCell title="可见范围" v-model="departments"></DeptSelectorCell>
+        </van-cell-group>
+
+
+        <van-button type="info" block @click="taskSubmit">确定修改</van-button>
+        <div style="height: 1rem;"></div>
+      </scroller>
+    </div>
+  </div>
+</template>
+
+<script>
+import Mtextarea from "@/components/Mtextarea";
+import RuleCategorySelectorCell from '@/components/RuleCategorySelectorCell1'
+import CategorySelectorCell from '@/components/CategorySelectorCell'
+import NumberInput from '@/components/NumberInput';
+import EmployeeSelectorCell from '@/components/EmployeeSelectorCell';
+import DateTimeCell from '@/components/DateTimeCell'
+import DeptSelectorCell from '@/components/DeptSelectorCell'
+
+export default {
+  name: "TaskEdit",
+  components:{
+    Mtextarea,
+    RuleCategorySelectorCell,
+    CategorySelectorCell,
+    NumberInput,
+    EmployeeSelectorCell,
+    DateTimeCell,
+    DeptSelectorCell
+  },
+  props:{
+    taskId:{
+      require:true,
+      type: String
+    }
+  },
+  data(){
+    return {
+      isNeed: !this.$getCache('isAndroid'),
+      pts:this.$getTypes,
+      rule_items:[],
+      rules:[],
+      reviewer:[],
+      departments:[],
+      hasInit:false,
+      formData:{
+        id:0,
+        pt_id:0,
+        base_point:0,
+        expire_time:'',
+        reviewer_id:0,
+        rule_type:0,
+        rule_id:0,
+        item_id:0,
+        rule_item:{
+          id:0,
+          remark:"",
+          cycle_type: 0,
+          is_attendance: 0,
+          max_point: 0,
+          min_point: 0,
+          prize_type: 0,
+          pt_id: 0,
+          range_type: 0,
+          rule_id: 0,
+        },
+        task_remark:'',
+        task_name:'',
+        file_list: [],
+        ahead_award_point:0,
+        ahead_award_point_limit:0,
+        timeout_deduction_point:0,
+        timeout_deduction_point_limit:0,
+        dept_ids:[],
+        dept_names:''
+      }
+    }
+  },
+  watch:{
+    'formData.pt_id'(v){
+      if (this.hasInit && this.formData.rule_type === 2) this.initRuleData()
+    },
+    'formData.rule_type'(v){
+      if(this.hasInit) this.initRuleData()
+    },
+    rules(rules){
+      if (this.hasInit) this.formData.rule_id = rules.length <= 0 ? 0 : rules[0].id
+    },
+    rule_items(items){
+      if (!this.hasInit) return
+      this.formData.rule_item = items.length <= 0 ? {
+        id:0,
+        remark:"",
+        cycle_type: 0,
+        is_attendance: 0,
+        max_point: 0,
+        min_point: 0,
+        prize_type: 0,
+        pt_id: 0,
+        range_type: 0,
+        rule_id: 0,
+      } : {
+        id:items[0].id,
+        remark:items[0].remark,
+        cycle_type: items[0].cycle_type,
+        is_attendance: items[0].is_attendance,
+        max_point: items[0].max_point,
+        min_point: items[0].min_point,
+        prize_type: items[0].prize_type,
+        pt_id: items[0].pt_id,
+        range_type: items[0].range_type,
+        rule_id: items[0].rule_id,
+      }
+      this.formData.rule_id = this.formData.rule_item.rule_id
+      this.formData.item_id = this.formData.rule_item.id
+      this.formData.base_point = this.formData.rule_item.min_point !== 0 ? this.formData.rule_item.min_point : 1
+    },
+    reviewer(v){
+      if (v.length === 0){
+        this.formData.reviewer_id = 0
+      } else {
+        this.formData.reviewer_id = v[0].id
+      }
+    },
+    departments(v){
+      if (v.length === 0){
+        this.formData.dept_ids = []
+      }else {
+        this.formData.dept_ids = v.map(item => item.dept_id)
+      }
+    },
+  },
+  computed:{
+    ruleItemLabel(){
+      if (this.formData.rule_item.id <= 0) return ''
+      let pt = this.pts.find( t => t.id === this.formData.rule_item.pt_id)
+      return this.formData.rule_item.range_type === 1 ? `${this.formData.rule_item.min_point} ${pt.name}` : `${this.formData.rule_item.min_point} - ${this.formData.rule_item.max_point} ${pt.name}`
+    },
+    minPoint(){
+      return this.formData.rule_type !== 2 ? 1 : (this.formData.rule_item.id <= 0 ? 1 : this.formData.rule_item.min_point)
+    },
+    maxPoint(){
+      return this.formData.rule_type !== 2 ? 100000 : (this.formData.rule_item.id <= 0 ? 1 : this.formData.rule_item.max_point)
+    }
+  },
+  methods:{
+    initRuleData(){
+      this.formData.rule_id = 0
+      this.formData.item_id = 0
+      this.formData.rule_item = {
+        id:0,
+        remark:"",
+        cycle_type: 0,
+        is_attendance: 0,
+        max_point: 0,
+        min_point: 0,
+        prize_type: 0,
+        pt_id: 0,
+        range_type: 0,
+        rule_id: 0,
+      }
+      this.formData.base_point = 1
+      this.rules = []
+      this.rule_items = []
+    },
+    getInfo(){
+      if (!this.taskId){
+        this.$toast.fail('悬赏信息丢失')
+        return
+      }
+
+      this.$toast.loading({
+        loadingType: 'spinner',
+        forbidClick:true
+      })
+
+      let data = {
+        task_id:this.taskId
+      }
+      this.hasInit = false
+      this.$axiosUser('get','/api/pro/integral/task',data)
+        .then(res => {
+          if (res.data.code !== 1) throw new Error(res.data.msg)
+
+          let info = res.data.data
+          let formData = {
+            id:info.id,
+            pt_id:info.pt_id,
+            base_point:info.point_config.base_point,
+            expire_time:info.expire_time,
+            reviewer_id:info.reviewer_id,
+            rule_type:0,
+            rule_id:info.rule_id,
+            item_id:info.item_id,
+            rule_item:{
+              id:0,
+              remark:"",
+              cycle_type: 0,
+              is_attendance: 0,
+              max_point: 0,
+              min_point: 0,
+              prize_type: 0,
+              pt_id: 0,
+              range_type: 0,
+              rule_id: 0,
+            },
+            task_remark:info.task_remark,
+            task_name:info.task_name,
+            task_file_list: info.task_file_list,
+            ahead_award_point:info.point_config.ahead_award_point,
+            ahead_award_point_limit:info.point_config.ahead_award_point_limit,
+            timeout_deduction_point:info.point_config.timeout_deduction_point,
+            timeout_deduction_point_limit:info.point_config.timeout_deduction_point_limit,
+            dept_ids:[],
+            dept_names:'',
+          }
+          if (info.item_info){
+            formData.rule_item = {
+              id:info.item_id,
+              remark:info.item_info.remark,
+              cycle_type: info.item_info.cycle_type,
+              is_attendance: info.item_info.is_attendance,
+              max_point: info.item_info.max_point,
+              min_point: info.item_info.min_point,
+              prize_type: info.item_info.prize_type,
+              pt_id: info.item_info.pt_id,
+              range_type: info.item_info.range_type,
+              rule_id: info.rule_id,
+            }
+            this.rule_items = [formData.rule_item]
+          } else if (info.rule_info){
+            this.rules = [{id:info.rule_info.id,name:info.rule_info.name}]
+          }
+          this.reviewer = [{id:info.reviewer_id,name:info.reviewer_name,img_url:info.reviewer_img_url}]
+          formData.rule_type = formData.item_id > 0 && formData.rule_id > 0 ? 2 : (formData.rule_id > 0 ? 1 : 0)
+          this.departments = []
+          if (info.department_info){
+            info.department_info.forEach((item,index) => {
+              formData.dept_ids.push(item.id)
+              this.departments.push({dept_id: item.id, dept_name: item.name})
+              formData.dept_names +=  index === 0 ? item.name : `,${item.name}`
+            })
+          }
+
+          this.formData = formData
+
+
+          this.$nextTick(() => {
+            this.hasInit = true
+          })
+        })
+        .catch(err => {
+          this.$toast.fail(err)
+        })
+        .finally(() => {
+          this.$toast.clear()
+        })
+
+    },
+    taskSubmit(){
+      if (this.formData.rule_type === 1 && this.formData.rule_id <= 0){
+        this.$toast.fail('请选择规则分类')
+        return
+      }
+      if (this.formData.rule_type === 2 && this.formData.item_id <= 0){
+        this.$toast.fail('请选择积分规则')
+        return
+      }
+      this.$validator.validate().then(result => {
+        if (!result){
+          this.$notify({type: 'danger', message: this.$validator.errors.items[0].msg});
+        }else {
+          this.sub()
+        }
+      })
+    },
+    ahead_timeout(item,arr,codes,code){
+      if(item){
+        if(arr){
+          if(Number(item) > Number(arr)){
+            this.$notify({type: 'danger', message: code + '上限不能小于每日' + codes});
+            return true
+          }
+        }else{
+          this.$notify({type: 'danger', message:codes + '不为0时,' + code + '上限不能为空'});
+          return true
+        }
+      }
+    },
+    sub(){
+      let data = {
+        id:this.formData.id,
+        pt_id:this.formData.pt_id,
+        task_name:this.formData.task_name,
+        task_remark:this.formData.task_remark,
+        base_point:this.formData.base_point,
+        expire_time:this.formData.expire_time,
+        reviewer_id:this.formData.reviewer_id,
+        timeout_deduction_point:this.formData.timeout_deduction_point,
+        timeout_deduction_point_limit:this.formData.timeout_deduction_point_limit,
+        ahead_award_point:this.formData.ahead_award_point,
+        ahead_award_point_limit:this.formData.ahead_award_point_limit,
+        dept_ids:this.formData.dept_ids,
+        rule_id:this.formData.rule_id,
+        item_id:this.formData.item_id,
+      }
+      if (!data.ahead_award_point && data.ahead_award_point_limit) {
+        this.$notify({type: 'danger', message: '奖分上限不为0时,提前奖分不能为空'});
+        return;
+      } else if (data.ahead_award_point && !data.ahead_award_point_limit) {
+        this.$notify({type: 'danger', message: '提前奖分不为0时,奖分上限不能为空'});
+        return;
+      }
+      if (!data.timeout_deduction_point && data.timeout_deduction_point_limit) {
+        this.$notify({type: 'danger', message: '扣分上限不为0时,逾期扣分不能为空'});
+        return;
+      } else if (data.timeout_deduction_point && !data.timeout_deduction_point_limit) {
+        this.$notify({type: 'danger', message: '逾期扣分不为0时,扣分上限不能为空'});
+        return;
+      }
+
+      if (this.ahead_timeout(data.ahead_award_point, data.ahead_award_point_limit, '提前奖分', '奖分')) return;
+      if (this.ahead_timeout(data.timeout_deduction_point, data.timeout_deduction_point_limit, '逾期扣分', '扣分')) return;
+
+      let point_limit = this.$userInfo().point_config.point_limit ? this.$userInfo().point_config.point_limit.find(pt => pt.pt_id === 3) : null
+      if (!this.$userInfo().is_creator && point_limit) {
+        let entry_limit = Number(point_limit.point);
+        if (entry_limit > 0) {
+          if (data.ahead_award_point > entry_limit || data.timeout_deduction_point > entry_limit) {
+            this.$notify({type: 'danger', message: '每日奖扣分 不能超过您的奖扣分权限(您的奖扣分权限:' + entry_limit + '分)'});
+            return;
+          }
+          if (data.ahead_award_point_limit > entry_limit * 10 || data.timeout_deduction_point_limit > entry_limit * 10) {
+            this.$notify({type: 'danger', message: '奖扣分上限不能超过' + entry_limit * 10 + '分(您的奖扣分权限' + entry_limit + '分*10)'});
+            return;
+          }
+        }
+      }
+
+      let self = this
+      self.$toast.loading({
+        loadingType: 'spinner',
+        forbidClick:true
+      })
+
+      self.$axiosUser('post','/api/pro/integral/task/update',data)
+        .then(res => {
+          if (res.data.code !== 1) throw new Error(res.data.msg)
+
+          self.$toast.success(res.data.msg)
+          setTimeout(() => {
+            self.$route_back()
+          },500)
+        })
+        .catch(err => {
+          self.$toast.fail(err)
+        })
+        .finally(() => {
+          self.$toast.clear()
+        })
+
+
+    }
+  },
+  activated() {
+    this.getInfo()
+  }
+}
+</script>
+
+
+<style scoped lang="less">
+.content{
+  height: calc(100% - 0.92rem);
+  position: relative;
+  overflow-y: scroll;
+}
+.point-field /deep/ .van-cell__title.van-field__label span {
+  width: 0;
+  color: transparent;
+  height: 0;
+  overflow: hidden;
+  font-size: 0;
+}
+.point-field /deep/ .van-cell__title {
+  width: 0;
+}
+</style>

+ 520 - 0
src/point/view/task/WorkEdit.vue

@@ -0,0 +1,520 @@
+<template>
+  <div>
+    <van-nav-bar
+      title="任务更新"
+      left-text="返回"
+      @click-left="$route_back"
+      left-arrow
+    />
+    <div class="content">
+      <scroller :is-need="isNeed">
+        <van-cell-group>
+          <van-cell required>
+            <Mtextarea
+              v-model="formData.task_name"
+              name="任务内容"
+              v-validate="'required|max:20'"
+              placeholder="请输入任务内容"
+              :text_max="20"
+              :imgs_max="3"
+              images
+              :imgs.sync="formData.file_list"
+            ></Mtextarea>
+          </van-cell>
+        </van-cell-group>
+
+        <van-cell-group class="point-field">
+          <van-cell title="积分类型" required id="task_types">
+            <template slot="right-icon">
+              <van-radio-group v-model="formData.pt_id" direction="horizontal" class="radio_button">
+                <van-radio checked-color class="list" :name="item.id" v-for="(item, index) in pts" v-if="item.code !== 'JX'" :key="index">{{ item.name }}</van-radio>
+              </van-radio-group>
+            </template>
+          </van-cell>
+          <van-cell title="指定规则">
+            <template slot="right-icon">
+              <van-radio-group
+                v-model="formData.rule_type"
+                direction="horizontal"
+              >
+                <van-radio class="list" :name="0" >
+                  <span class="rule_type_span">不指定</span>
+                </van-radio>
+                <van-radio class="list" :name="1" >
+                  <span class="rule_type_span">分类</span>
+                </van-radio>
+                <van-radio class="list" :name="2" >
+                  <span class="rule_type_span">规则</span>
+                </van-radio>
+              </van-radio-group>
+            </template>
+          </van-cell>
+
+          <!--     选择分类     -->
+          <CategorySelectorCell
+            v-if="formData.rule_type === 1"
+            title="细则分类"
+            v-model="rules"
+            required
+            :pt-id="formData.pt_id"
+            :multi="false"
+            scope
+          />
+
+          <!--选择规则  -->
+          <RuleCategorySelectorCell
+            v-if="formData.rule_type === 2"
+            :pt-id="formData.pt_id"
+            required
+            name="请选择积分规则"
+            title="积分规则"
+            v-model="rule_items"
+            scope
+            :multi="false"
+          >
+            <template slot="label">
+              <span style="color: red">{{ruleItemLabel}}</span>
+            </template>
+          </RuleCategorySelectorCell>
+
+          <van-cell title="任务积分" style="padding:0 0.32rem; padding-top:0.16rem;" :border="false" required/>
+          <NumberInput v-model="formData.base_point" v-validate="'required'"  :min="minPoint" :max="maxPoint"/>
+        </van-cell-group>
+
+        <van-cell-group>
+          <EmployeeSelectorCell
+            required
+            title="执行人"
+            :max="10"
+            is_employee_list
+            v-validate="'required'"
+            :employee_list="$userInfo().employee_detail.manage_scope"
+            name="执行人"
+            :multi="false"
+            v-model="executor_name"
+          />
+          <EmployeeSelectorCell
+            required
+            title="审批人"
+            iconType="records"
+            :show_manager_only="true"
+            v-model="reviewer"
+            v-validate="'required'"
+            name="审批人"
+            :multi="false"
+          />
+          <DateTimeCell
+            required
+            title="截止时间"
+            v-validate="'required'"
+            name="截止时间"
+            v-model="formData.expire_time"
+          />
+          <van-field v-model="formData.ahead_award_point" type="digit">
+            <template slot="label">
+              <div class="flex-box-ce">
+                <span>提前奖分(天)</span>
+                <span class="flex-1 red" style="text-align: right;">+</span>
+              </div>
+            </template>
+          </van-field>
+          <van-field v-model="formData.ahead_award_point_limit" type="digit" label="奖分上限">
+            <template slot="label">
+              <div class="flex-box-ce">
+                <span>奖分上限</span>
+                <span class="flex-1 red" style="text-align: right;">+</span>
+              </div>
+            </template>
+          </van-field>
+          <van-field v-model="formData.timeout_deduction_point" type="digit" label="逾期扣分(天)">
+            <template slot="label">
+              <div class="flex-box-ce">
+                <span>逾期扣分(天)</span>
+                <span class="flex-1 green" style="text-align: right;">-</span>
+              </div>
+            </template>
+          </van-field>
+          <van-field v-model="formData.timeout_deduction_point_limit" type="digit" label="扣分上限">
+            <template slot="label">
+              <div class="flex-box-ce">
+                <span>扣分上限</span>
+                <span class="flex-1 green" style="text-align: right;">-</span>
+              </div>
+            </template>
+          </van-field>
+        </van-cell-group>
+        <van-cell-group :border="false">
+          <van-cell title="任务备注"/>
+          <van-cell>
+            <Mtextarea v-model="formData.task_remark" placeholder="请输入关于任务备注" :text_max="300"/>
+          </van-cell>
+        </van-cell-group>
+
+        <van-button type="info" block @click="taskSubmit">确定修改</van-button>
+        <div style="height: 1rem;"></div>
+      </scroller>
+    </div>
+  </div>
+</template>
+
+<script>
+import Mtextarea from "@/components/Mtextarea";
+import RuleCategorySelectorCell from '@/components/RuleCategorySelectorCell1'
+import CategorySelectorCell from '@/components/CategorySelectorCell'
+import NumberInput from '@/components/NumberInput';
+import EmployeeSelectorCell from '@/components/EmployeeSelectorCell';
+import DateTimeCell from '@/components/DateTimeCell'
+
+export default {
+  name: "WorkEdit",
+  components: {
+    Mtextarea,
+    RuleCategorySelectorCell,
+    CategorySelectorCell,
+    NumberInput,
+    EmployeeSelectorCell,
+    DateTimeCell,
+  },
+  props:{
+    workId:{
+      require:true,
+      type: String
+    }
+  },
+  data() {
+    return {
+      isNeed: !this.$getCache('isAndroid'),
+      pts:this.$getTypes,
+      rule_items:[],
+      rules:[],
+      executor_name:[],
+      reviewer:[],
+      hasInit:false,
+      formData:{
+        id:0,
+        pt_id:0,
+        publisher_id:0,
+        base_point:0,
+        expire_time:'',
+        reviewer_id:0,
+        rule_type:0,
+        rule_id:0,
+        item_id:0,
+        rule_item:{
+          id:0,
+          remark:"",
+          cycle_type: 0,
+          is_attendance: 0,
+          max_point: 0,
+          min_point: 0,
+          prize_type: 0,
+          pt_id: 0,
+          range_type: 0,
+          rule_id: 0,
+        },
+        task_remark:'',
+        task_name:'',
+        targets:[],
+        file_list: [],
+        ahead_award_point:0,
+        ahead_award_point_limit:0,
+        timeout_deduction_point:0,
+        timeout_deduction_point_limit:0,
+      }
+    }
+  },
+  watch:{
+    'formData.pt_id'(v){
+      if (this.hasInit && this.formData.rule_type === 2) this.initRuleData()
+    },
+    executor_name(v){
+      if (v.length === 0){
+        this.formData.targets = []
+      } else {
+        this.formData.targets = [v[0].id]
+      }
+    },
+    'formData.rule_type'(v){
+      if (this.hasInit) this.initRuleData()
+    },
+    rules(rules){
+      if (this.hasInit) this.formData.rule_id = rules.length <= 0 ? 0 : rules[0].id
+    },
+    rule_items(items){
+      if (!this.hasInit) return
+      this.formData.rule_item = items.length <= 0 ? {
+        id:0,
+        remark:"",
+        cycle_type: 0,
+        is_attendance: 0,
+        max_point: 0,
+        min_point: 0,
+        prize_type: 0,
+        pt_id: 0,
+        range_type: 0,
+        rule_id: 0,
+      } : {
+        id:items[0].id,
+        remark:items[0].remark,
+        cycle_type: items[0].cycle_type,
+        is_attendance: items[0].is_attendance,
+        max_point: items[0].max_point,
+        min_point: items[0].min_point,
+        prize_type: items[0].prize_type,
+        pt_id: items[0].pt_id,
+        range_type: items[0].range_type,
+        rule_id: items[0].rule_id,
+      }
+      this.formData.rule_id = this.formData.rule_item.rule_id
+      this.formData.item_id = this.formData.rule_item.id
+      this.formData.base_point = this.formData.rule_item.min_point !== 0 ? this.formData.rule_item.min_point : 1
+    },
+    reviewer(v){
+      if (v.length === 0){
+        this.formData.reviewer_id = 0
+      } else {
+        this.formData.reviewer_id = v[0].id
+      }
+    }
+  },
+  computed:{
+    ruleItemLabel(){
+      if (this.formData.rule_item.id <= 0) return ''
+      let pt = this.pts.find( t => t.id === this.formData.rule_item.pt_id)
+      return this.formData.rule_item.range_type === 1 ? `${this.formData.rule_item.min_point} ${pt.name}` : `${this.formData.rule_item.min_point} - ${this.formData.rule_item.max_point} ${pt.name}`
+    },
+    minPoint(){
+      return this.formData.rule_type !== 2 ? 1 : (this.formData.rule_item.id <= 0 ? 1 : this.formData.rule_item.min_point)
+    },
+    maxPoint(){
+      return this.formData.rule_type !== 2 ? 100000 : (this.formData.rule_item.id <= 0 ? 1 : this.formData.rule_item.max_point)
+    }
+  },
+  methods:{
+    initRuleData(){
+      this.formData.rule_id = 0
+      this.formData.item_id = 0
+      this.formData.rule_item = {
+        id:0,
+        remark:"",
+        cycle_type: 0,
+        is_attendance: 0,
+        max_point: 0,
+        min_point: 0,
+        prize_type: 0,
+        pt_id: 0,
+        range_type: 0,
+        rule_id: 0,
+      }
+      this.formData.base_point = 1
+      this.rules = []
+      this.rule_items = []
+    },
+    getInfo(){
+      if (!this.workId){
+        this.$toast.fail('任务信息丢失')
+        return
+      }
+
+      this.$toast.loading({
+        loadingType: 'spinner',
+        forbidClick:true
+      })
+
+      this.hasInit = false
+      this.$axiosUser('get', '/api/pro/integral/work', { work_id: this.workId })
+        .then(res => {
+          if (res.data.code !== 1){
+            this.$toast.fail(res.data.msg)
+            return
+          }
+          let info = res.data.data
+          this.formData = {
+            id:info.id,
+            pt_id:info.pt_id,
+            publisher_id:info.publisher_id,
+            base_point:info.point_config.base_point,
+            expire_time:info.expire_time,
+            reviewer_id:info.reviewer_id,
+            rule_type:0,
+            rule_id:info.rule_id,
+            item_id:info.item_id,
+            rule_item:{
+              id:0,
+              remark:"",
+              cycle_type: 0,
+              is_attendance: 0,
+              max_point: 0,
+              min_point: 0,
+              prize_type: 0,
+              pt_id: 0,
+              range_type: 0,
+              rule_id: 0,
+            },
+            task_remark:info.task_remark,
+            task_name:info.task_name,
+            targets:[info.employee_id],
+            file_list: info.task_file_list ? info.task_file_list : [],
+            ahead_award_point:info.point_config.ahead_award_point,
+            ahead_award_point_limit:info.point_config.ahead_award_point_limit,
+            timeout_deduction_point:info.point_config.timeout_deduction_point,
+            timeout_deduction_point_limit:info.point_config.timeout_deduction_point_limit,
+          }
+          if (info.item_info){
+            this.formData.rule_item = {
+              id:info.item_id,
+              remark:info.item_info.remark,
+              cycle_type: info.item_info.cycle_type,
+              is_attendance: info.item_info.is_attendance,
+              max_point: info.item_info.max_point,
+              min_point: info.item_info.min_point,
+              prize_type: info.item_info.prize_type,
+              pt_id: info.item_info.pt_id,
+              range_type: info.item_info.range_type,
+              rule_id: info.rule_id,
+            }
+            this.rule_items = [this.formData.rule_item]
+          } else if (info.rule_info){
+            this.rules = [{id:info.rule_info.id,name:info.rule_info.name}]
+          }
+          this.executor_name = [{id:info.employee_id,name:info.employee_name,img_url:info.img_url}]
+          this.reviewer = [{id:info.reviewer_id,name:info.reviewer_name,img_url:info.reviewer_img_url}]
+          this.formData.rule_type = this.formData.item_id > 0 && this.formData.rule_id > 0 ? 2 : (this.formData.rule_id > 0 ? 1 : 0)
+
+
+          this.$nextTick(() => {
+            this.hasInit = true
+          })
+        })
+        .finally(() => {
+          this.$toast.clear()
+        })
+    },
+    taskSubmit(){
+      if (this.formData.rule_type === 1 && this.formData.rule_id <= 0){
+        this.$toast.fail('请选择规则分类')
+        return
+      }
+      if (this.formData.rule_type === 2 && this.formData.item_id <= 0){
+        this.$toast.fail('请选择积分规则')
+        return
+      }
+      this.$validator.validate().then(result => {
+        if (!result){
+          this.$notify({type: 'danger', message: this.$validator.errors.items[0].msg});
+        }else {
+          this.sub()
+        }
+      })
+    },
+    ahead_timeout(item,arr,codes,code){
+      if(item){
+        if(arr){
+          if(Number(item) > Number(arr)){
+            this.$notify({type: 'danger', message: code + '上限不能小于每日' + codes});
+            return true
+          }
+        }else{
+          this.$notify({type: 'danger', message:codes + '不为0时,' + code + '上限不能为空'});
+          return true
+        }
+      }
+    },
+    sub(){
+      let data = {
+        id:this.formData.id,
+        targets:this.formData.targets,
+        pt_id:this.formData.pt_id,
+        task_name:this.formData.task_name,
+        task_remark:this.formData.task_remark,
+        base_point:Number(this.formData.base_point),
+        expire_time:this.formData.expire_time,
+        package_id:0,
+        weight:0,
+        file_list:this.formData.file_list,
+        reviewer_id:this.formData.reviewer_id,
+        ahead_award_point:this.formData.ahead_award_point,
+        ahead_award_point_limit:this.formData.ahead_award_point_limit,
+        timeout_deduction_point:this.formData.timeout_deduction_point,
+        timeout_deduction_point_limit:this.formData.timeout_deduction_point_limit,
+        rule_id:this.formData.rule_id,
+        item_id:this.formData.item_id,
+      }
+      if (!data.ahead_award_point && data.ahead_award_point_limit) {
+        this.$notify({type: 'danger', message: '奖分上限不为0时,提前奖分不能为空'});
+        return;
+      } else if (data.ahead_award_point && !data.ahead_award_point_limit) {
+        this.$notify({type: 'danger', message: '提前奖分不为0时,奖分上限不能为空'});
+        return;
+      }
+      if (!data.timeout_deduction_point && data.timeout_deduction_point_limit) {
+        this.$notify({type: 'danger', message: '扣分上限不为0时,逾期扣分不能为空'});
+        return;
+      } else if (data.timeout_deduction_point && !data.timeout_deduction_point_limit) {
+        this.$notify({type: 'danger', message: '逾期扣分不为0时,扣分上限不能为空'});
+        return;
+      }
+
+      if (this.ahead_timeout(data.ahead_award_point, data.ahead_award_point_limit, '提前奖分', '奖分')) return;
+      if (this.ahead_timeout(data.timeout_deduction_point, data.timeout_deduction_point_limit, '逾期扣分', '扣分')) return;
+
+      let point_limit = this.$userInfo().point_config.point_limit ? this.$userInfo().point_config.point_limit.find(pt => pt.pt_id === 3) : null
+
+      if (!this.$userInfo().is_creator && point_limit) {
+        let entry_limit = Number(point_limit.point);
+        if (entry_limit > 0) {
+          if (data.ahead_award_point > entry_limit || data.timeout_deduction_point > entry_limit) {
+            this.$notify({type: 'danger', message: '每日奖扣分 不能超过您的奖扣分权限(您的奖扣分权限:' + entry_limit + '分)'});
+            return;
+          }
+          if (data.ahead_award_point_limit > entry_limit * 10 || data.timeout_deduction_point_limit > entry_limit * 10) {
+            this.$notify({type: 'danger', message: '奖扣分上限不能超过' + entry_limit * 10 + '分(您的奖扣分权限' + entry_limit + '分*10)'});
+            return;
+          }
+        }
+      }
+
+      let self = this
+      self.$toast.loading({
+        loadingType: 'spinner',
+        forbidClick:true
+      })
+      self.$axiosUser('post', '/api/pro/integral/work/update', data)
+        .then(res => {
+          if (res.data.code !== 1){
+            self.$toast.fail(res.data.msg)
+            return
+          }
+          self.$toast.success(res.data.msg)
+          setTimeout(() => {
+            self.$route_back()
+          },500)
+        })
+        .finally(() => {
+          self.$toast.clear()
+        })
+    }
+  },
+  activated() {
+    this.getInfo()
+  }
+}
+</script>
+
+<style scoped lang="less">
+.content{
+  height: calc(100% - 0.92rem);
+  position: relative;
+  overflow-y: scroll;
+}
+.point-field /deep/ .van-cell__title.van-field__label span {
+  width: 0;
+  color: transparent;
+  height: 0;
+  overflow: hidden;
+  font-size: 0;
+}
+.point-field /deep/ .van-cell__title {
+  width: 0;
+}
+</style>

+ 14 - 2
src/point/view/task/my_publish.vue

@@ -108,7 +108,7 @@
 
       <div slot="repetitive">
         <van-cell-group class="list_box" :border="false">
-          <van-cell v-for="(item, index) in list" style="border-bottom: 17px solid #F5F7FA;" :key="index" @click="repetitive_detail(item)">
+          <van-cell v-for="(item, index) in list" style="border-bottom: 17px solid #F5F7FA;" :key="index" @click="repetitive_detail(item)" v-bind:class="scheduleClassName(item)">
             <template slot="title">
               <span class="title_name">{{ item.name }}</span>
             </template>
@@ -194,7 +194,7 @@ export default {
   computed: {
     hasData() {
       return this.loading || (Array.isArray(this.list) && this.list.length > 0);
-    }
+    },
   },
   // 方法
   methods: {
@@ -321,7 +321,14 @@ export default {
     // 时间对比
     date_contrast(date) {
       return moment(this.date) > moment(date);
+    },
+    scheduleClassName(schedule){
+      if (!schedule.schedule_expire_time) return "";
+      let now = new Date();
+      let expire_date = new Date(schedule.schedule_expire_time);
+      return now >= expire_date ? "schedule-expire" : "";
     }
+
   },
   // 组件挂载完成
   mounted() {
@@ -415,4 +422,9 @@ export default {
   padding: 0;
   margin-right: 0.1rem;
 }
+
+.schedule-expire{
+  background-color: oldlace;
+}
+
 </style>

+ 4 - 3
src/point/view/task/my_task.vue

@@ -131,7 +131,7 @@
                 <van-button class="fr complete_task" v-show="item.status == 1" type="info" @click.stop="complete_task(item)" size="small">完成任务</van-button>
                 <span class="fr orange bg" v-show="item.review_status == 0">待处理</span>
                 <span class="fr green  bg" v-show="item.review_status == 1">已通过</span>
-                <span class="fr red bg" v-show="item.review_status == 2">已驳回</span>
+                <span class="fr red bg" v-show="item.review_status == 2">已拒绝</span>
               </div>
             </template>
           </van-cell>
@@ -171,7 +171,7 @@ export default {
       time: moment().format('YYYY-MM-DD HH:mm'),
       date: moment().format('YYYY-MM-DD'),
       tips: '暂无数据',
-      title: '我的任务',
+      title: '我负责的',
       loading: true,
       activeNames: '2',
       filter: {
@@ -184,6 +184,7 @@ export default {
       },
       tabsOption: [
         { title: '待完成', value: 'running' },
+        { title: '驳回重做', value: 'rewrite' },
         { title: '待审批', value: 'complete' },
         { title: '已审批', value: 'reviewed' }
       ],
@@ -251,7 +252,7 @@ export default {
       }
     },
     onRefresh (params) {
-      if(this.filter.status=='running'){
+      if(this.filter.status === 'running'){
         this.getToDay(false,params.done)
       }else{
         this.get_list(false,params.done)

+ 297 - 66
src/point/view/task/repetitive_tasks_detail.vue

@@ -9,74 +9,243 @@
     </van-nav-bar>
     <div class="body_com has_header">
       <scroller class="scroller-top">
-        <van-cell-group>
-          <div class="flex-box item-box">
-            <div class="laber">任务内容</div>
-            <div class="flex-1">{{info.name}}</div>
-          </div>
-          <div class="flex-box item-box" v-if="info.remark">
-            <div class="laber">任务备注</div>
-            <div class="flex-1">{{info.remark}}</div>
-          </div>
-          <div class="flex-box item-box flex-v-ce">
-            <div class="laber">执行周期</div>
-            <div class="flex-1">{{info.target_info.length>0? '临时任务-':'悬赏任务-'}}{{info.task_cycle_mark}}</div>
-          </div>
-          <div class="flex-box item-box flex-v-ce" v-if="info.point_config.base_point">
-            <div class="laber">任务积分</div>
-            <div class="flex-1">{{info.point_config.base_point}}{{info.pt_name}}</div>
-          </div>
-          <div class="flex-box item-box flex-v-ce">
-            <div class="laber">发布人</div>
-            <div class="flex-1">{{info.owner_name}}</div>
-          </div>
-          <div class="flex-box item-box">
-            <div class="laber">截止时间</div>
-            <div class="flex-1" v-if="info.task_cycle==1">{{info.task_cycle_mark}}{{info.task_cycle_value > 9 ? info.task_cycle_value + ': 00' : '0' + info.task_cycle_value + ': 00'}}点截止</div>
-            <div class="flex-1" v-if="info.task_cycle==2">{{info.task_cycle_mark}}{{weekList[info.task_cycle_value - 1] }}截止</div>
-            <div class="flex-1" v-if="info.task_cycle==3">{{info.task_cycle_mark}}{{info.task_cycle_value}}号截止</div>
-          </div>
-          <div class="flex-box item-box flex-v-ce">
-            <div class="laber">可见范围</div>
-            <div class="flex-1" v-if="info.department_info.length>0">
-              <span v-for="item in info.department_info" :key="item.id">{{item.name}},</span>
-            </div>
-            <div class="flex-1" v-else>全公司</div>
-          </div>
-          <div class="flex-box item-box flex-v-ce" v-if="info.point_config.ahead_award_point">
-            <div class="laber">提前奖分</div>
-            <div class="flex-1">{{info.point_config.ahead_award_point}}B分/天</div>
-          </div>
-          <div class="flex-box item-box flex-v-ce" v-if="info.point_config.ahead_award_point_limit">
-            <div class="laber">奖分上限</div>
-            <div class="flex-1">{{info.point_config.ahead_award_point_limit}}B分</div>
-          </div>
-          <div class="flex-box item-box flex-v-ce" v-if="info.point_config.timeout_deduction_point">
-            <div class="laber">逾期扣分</div>
-            <div class="flex-1">{{info.point_config.timeout_deduction_point}}B分/天</div>
-          </div>
-          <div class="flex-box item-box flex-v-ce" v-if="info.point_config.timeout_deduction_point_limit">
-            <div class="laber">扣分上限</div>
-            <div class="flex-1">{{info.point_config.timeout_deduction_point_limit}}B分</div>
-          </div>
-
-
-        </van-cell-group>
-        <van-cell-group class="padding-cell-group">
-          <div class="tip">审批人</div>
-          <div style="width:0.9rem; margin-top:0.16rem;">
-              <userImage :user_name="info.reviewer_name" :id="parseInt(info.reviewer_id)"  width="0.8rem" height="0.8rem"  ></userImage>
-            <div style=" font-size: 0.2rem; text-align: center;">{{info.reviewer_name}}</div>
-          </div>
+        <van-cell-group inset>
+          <van-cell
+            title-class="align_self"
+            value-class="align_self"
+          >
+            <template slot="icon">
+              <user-image
+                class="fl"
+                :img_url="info.owner_img_url"
+                :user_name="info.owner_name"
+              />
+            </template>
+            <template slot="title">
+              {{info.owner_name}}&nbsp;
+              {{$getTypesName(info.pt_id)}}{{scheduleTypeMark}}&nbsp;
+            </template>
+            <template slot="default">
+              <van-tag type="primary" size="medium" >{{info.point_config.base_point}}</van-tag>
+            </template>
+          </van-cell>
+          <van-cell
+            :border="false"
+            :title="scheduleTypeMark + '内容'"
+            :value="info.name"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            v-if="info.remark"
+            :border="false"
+            :title="scheduleTypeMark + '备注'"
+            :value="info.remark"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            :border="false"
+            title="执行周期"
+            :value="`${info.target_info.length > 0 ? '临时任务-' : '悬赏任务-'}${info.task_cycle_mark}`"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            :border="false"
+            v-if="info.point_config"
+            :title="`${scheduleTypeMark}积分`"
+            :value="`${info.point_config.base_point}${$getTypesName(info.pt_id)}`"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            :border="false"
+            v-if="info.file_list && info.file_list.length > 0"
+            title="附件"
+            title-class="align_self"
+            value-class="align_self"
+          >
+            <template slot="default">
+              <van-image
+                @click="open_img(index)"
+                style="margin-right: 0.1rem"
+                v-for="(item,index) in info.file_list"
+                :key="index"
+                :src="item"
+                width="50"
+                height="50"
+                radius="5"
+                type="contain"
+              />
+            </template>
+          </van-cell>
+          <van-cell
+            :border="false"
+            title="截止时间"
+            :title="expireTimeMark"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            :border="false"
+            v-if="info.schedule_expire_time"
+            title="有效日期"
+            title-class="align_self"
+            value-class="align_self"
+          >
+            <template slot="default">
+              <span v-if="!isExpire(info.schedule_expire_time)">{{info.schedule_expire_time}}</span>
+              <span v-else>
+                <van-tag type="warning" size="medium">{{info.schedule_expire_time}}</van-tag>
+              </span>
+            </template>
+          </van-cell>
+          <van-cell
+            :border="false"
+            v-if="info.department_info"
+            title="可见范围"
+            title-class="align_self"
+            value-class="align_self"
+          >
+            <template v-if="info.department_info.length > 0">
+              <span
+                v-for="(item,index) in info.department_info"
+                :key="index"
+              >
+                {{item.name}}&nbsp;
+              </span>
+            </template>
+            <span v-else >全公司</span>
+          </van-cell>
+          <template v-if="info.point_config">
+            <van-cell
+              title="逾期扣分"
+              :value="`${info.point_config.timeout_deduction_point} B分/天`"
+              title-class="align_self"
+              value-class="align_self"
+            />
+            <van-cell
+              title="提前奖分"
+              :value="`${info.point_config.ahead_award_point} B分/天`"
+              title-class="align_self"
+              value-class="align_self"
+            />
+          </template>
         </van-cell-group>
 
-        <van-cell-group class="padding-cell-group" >
-          <div class="tip">执行者</div>
-          <div class="" style="margin-top:0.16rem;display: inline-block;margin-right: 0.2rem; width: 0.8rem;" v-if="info.target_info" v-for="(item,index) in info.target_info" :key="index">
-            <userImage fontSize="0.28" :user_name="item.name" :id="parseInt(item.id)" width="0.8rem" height="0.8rem"></userImage>
-            <div style="font-size: 0.2rem; text-align: center; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">{{item.name}}</div>
-          </div>
+        <van-cell-group inset>
+          <van-cell
+            title="审批人"
+            :value="info.reviewer_name"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            v-if="info.target_info.length > 0"
+            title="执行人"
+            title-class="align_self"
+            value-class="align_self"
+          >
+            <template slot="default">
+              <span
+                v-for="(item,index) in info.target_info"
+                :key="index"
+              >
+                {{item.name}}&nbsp;
+              </span>
+            </template>
+          </van-cell>
         </van-cell-group>
+
+        <template v-if="info.item_info">
+          <van-row justify="space-around" class="item-title" >
+            <van-col span="6">规则依据</van-col>
+          </van-row>
+          <van-cell-group
+            :border="false"
+            class="task_detail_group"
+            inset
+          >
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              :border="false"
+              title="规则"
+              :value="info.item_info.remark"
+            />
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              :border="false"
+              title="积分"
+              :value="pointRemark"
+            />
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              v-if="info.item_info.has_delete"
+              :border="false"
+              title="规则状态"
+            >
+              <template slot="default">
+                <van-tag type="warning">规则已删除</van-tag>
+              </template>
+            </van-cell>
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              v-if="info.rule_info"
+              :border="false"
+              title="分类"
+              :value="info.rule_info.name"
+            />
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              v-if="info.rule_info && info.rule_info.has_delete"
+              :border="false"
+              title="分类状态"
+            >
+              <template slot="default">
+                <van-tag type="warning">分类已删除</van-tag>
+              </template>
+            </van-cell>
+          </van-cell-group>
+        </template>
+
+        <template v-else-if="info.rule_info">
+          <van-row justify="space-around" class="item-title">
+            <van-col span="6" >分类依据</van-col>
+          </van-row>
+          <van-cell-group
+            :border="false"
+            class="task_detail_group"
+            inset
+          >
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              :border="false"
+              title="分类"
+              :value="info.rule_info.name"
+            />
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              v-if="info.rule_info.has_delete"
+              :border="false"
+              title="分类状态"
+            >
+              <template slot="default">
+                <van-tag type="warning">分类已删除</van-tag>
+              </template>
+            </van-cell>
+          </van-cell-group>
+        </template>
+
+
+
       </scroller>
     </div>
     <van-action-sheet
@@ -112,8 +281,35 @@ export default {
       user_info: this.$userInfo()
     }
   },
+  computed:{
+    scheduleTypeMark(){
+      return !this.info ? '--' : (this.info.type === 2 ? '悬赏' : '任务')
+    },
+    expireTimeMark(){
+      if (!this.info) return '--'
+      let etMark = {
+        1:`${this.info.task_cycle_mark}${this.dayTime(this.info.task_cycle_value)}截止`,
+        2:`${this.info.task_cycle_mark}${this.weekList[this.info.task_cycle_value - 1]}截止`,
+        3:`${this.info.task_cycle_mark}${this.info.task_cycle_value}号截止`,
+      }
+      return etMark[this.info.task_cycle] || '--'
+    },
+    pointRemark(){
+      if (!(this.info && this.info.item_info)) return ''
+      return this.info.item_info.range_type === 1 ? `${this.info.item_info.min_point} ${this.$getTypesName(this.info.item_info.pt_id)}` : `${this.info.item_info.min_point} -- ${this.info.item_info.max_point} ${this.$getTypesName(this.info.item_info.pt_id)}`
+    }
+  },
   // 方法
   methods: {
+    isExpire(expire_time){
+      if (!expire_time) return false
+      let now = new Date()
+      let expire_date = new Date(expire_time)
+      return now >= expire_date
+    },
+    dayTime(item){
+      return item > 9 ? item + ':00' : '0' + item + ':00'
+    },
     // 上拉菜单点击
     sheet_select (action) {
       if (action.name == '删除任务') {
@@ -158,7 +354,7 @@ export default {
       let self = this
       self.showLoading()
       this.$axiosUser('get', '/api/pro/integral/schedule', {schedule_id: self.get_id}).then((res) => {
-        if (res.data.code == '1') {
+        if (res.data.code === 1) {
           self.info = res.data.data
         } else {
           self.$toast(res.data.msg)
@@ -171,6 +367,11 @@ export default {
     }
   },
   mounted () {
+    // console.log('mounted')
+    // this.get_data()
+  },
+  activated() {
+    // console.log('activated')
     this.get_data()
   }
 }
@@ -209,4 +410,34 @@ export default {
   .task_content /deep/ .van-grid-item__content{padding:0;}
 .task_content /deep/ .van-cell__value{text-align: left; color:#323233;}
   .task_content_last{padding-bottom:0.32rem;}
+
+
+.align_self{
+  align-self: center;
+}
+.item-title{
+  text-align: center;
+  margin-top: 10px;
+  font-size: 0.25rem;
+  line-height: 0.5rem;
+  color: #969799;
+}
+.sub-title{
+  font-size: 0.25rem;
+  line-height: 0.25rem;
+  color: #969799;
+}
+.align_self{
+  align-self: center;
+}
+
+.task_detail_group .van-cell {
+  padding: 0.1rem 0.32rem 0.1rem;
+}
+.task_detail_group .name {
+  padding-bottom: 0.2rem;
+}
+.task_detail_group {
+  padding: 0.16rem 0;
+}
 </style>

+ 209 - 16
src/point/view/task/short_task.vue

@@ -19,8 +19,64 @@
         </van-cell-group>
 
         <van-cell-group class="point-field">
+          <van-cell title="积分类型" required id="task_types">
+            <template slot="right-icon">
+              <van-radio-group v-model="data.pt_id" direction="horizontal" class="radio_button">
+                <van-radio checked-color class="list" :name="item.id" v-for="(item, index) in point_types" v-if="item.code !== 'JX'" :key="index">{{ item.name }}</van-radio>
+              </van-radio-group>
+              <van-icon class="small_tip" @click="show_small_tip = true" name="question-o" />
+            </template>
+          </van-cell>
+          <van-cell title="指定规则">
+            <template slot="right-icon">
+              <van-radio-group
+                v-model="data.rule_type"
+                direction="horizontal"
+                class="radio_button"
+              >
+                <van-radio class="list" :name="0" >
+                  <span class="rule_type_span">不指定</span>
+                </van-radio>
+                <van-radio class="list" :name="1" >
+                  <span class="rule_type_span">分类</span>
+                </van-radio>
+                <van-radio class="list" :name="2" >
+                  <span class="rule_type_span">规则</span>
+                </van-radio>
+              </van-radio-group>
+            </template>
+          </van-cell>
+
+          <!--     选择分类     -->
+          <CategorySelectorCell
+            v-if="data.rule_type === 1"
+            title="细则分类"
+            v-model="rules"
+            required
+            :pt-id="data.pt_id"
+            :multi="false"
+            scope
+          />
+
+          <!--选择规则  -->
+          <RuleCategorySelectorCell
+            v-if="data.rule_type === 2"
+            :pt-id="data.pt_id"
+            required
+            name="请选择积分规则"
+            title="积分规则"
+            v-model="rule_items"
+            scope
+            :multi="false"
+          >
+            <template slot="label">
+              <span style="color: red">{{ruleItemLabel}}</span>
+            </template>
+          </RuleCategorySelectorCell>
+
+
           <van-cell title="任务积分" style="padding:0 0.32rem; padding-top:0.16rem;" :border="false" required></van-cell>
-          <NumberInput v-model="data.base_point" v-validate="'required'" :chosePoint="false" :min="0" :max="100000"></NumberInput>
+          <NumberInput v-model="data.base_point" v-validate="'required'"  :min="minPoint" :max="maxPoint"></NumberInput>
         </van-cell-group>
 
         <van-cell-group>
@@ -35,14 +91,7 @@
             v-model="executor_name"
           ></EmployeeSelectorCell>
           <EmployeeSelectorCell required title="审批人" iconType="records" :show_manager_only="true" v-model="reviewer" v-validate="'required'" name="审批人" :multi="false"></EmployeeSelectorCell>
-          <van-cell title="任务类型" required id="task_types">
-            <template slot="right-icon">
-              <van-radio-group v-model="data.pt_id" direction="horizontal" class="radio_button">
-                <van-radio checked-color class="list" :name="item.id" v-for="(item, index) in point_types" v-if="item.code != 'JX'" :key="index">{{ item.name }}</van-radio>
-              </van-radio-group>
-              <van-icon class="small_tip" @click="show_small_tip = true" name="question-o" />
-            </template>
-          </van-cell>
+
           <van-cell title="重复周期"  @click="show_task_cycle_popup = true">
               <template>
                 <span v-if="data.task_cycle == 0">不重复</span>
@@ -55,6 +104,12 @@
           <van-cell required :value="'每天' + task_expire_day_text" is-link @click="show_task_expire_day = true" title="截止时间" v-if="data.task_cycle == 1" />
           <van-cell required :value="'每' + task_expire_day_text" is-link @click="show_task_expire_day = true" title="截止时间" v-if="data.task_cycle == 2" />
           <van-cell required :value="'每月' + task_expire_day_text" is-link @click="show_task_expire_day = true" title="截止时间" v-if="data.task_cycle == 3" />
+          <van-cell title="有效日期" v-if="data.task_cycle !== 0"  @click="showScheduleExpireDate = true" :value="data.schedule_expire_date" :center="true" >
+            <template #right-icon>
+              <van-icon color="#A4A5A7" name="arrow" v-if="!data.schedule_expire_date" />
+              <van-icon color="#A4A5A7" name="cross" v-else @click.stop="clearScheduleExpireDate" style="margin-left: 10px" />
+            </template>
+          </van-cell>
           <van-field v-model="data.ahead_award_point" type="digit">
             <template slot="label">
               <div class="flex-box-ce">
@@ -260,11 +315,22 @@
       />
     </van-popup>
     <van-popup v-model="show_small_tip" :get-container="'#task_types'" :overlay-class="'bg_opacity'"><div class="small_tip_popup_content">内容</div></van-popup>
+
+    <van-calendar
+      title="有效日期"
+      color="#26A2FF"
+      v-model="showScheduleExpireDate"
+      :show-confirm="false"
+      :default-date="scheduleExpireDate"
+      @confirm="scheduleExpireDateConfirm"
+    />
+
   </div>
 </template>
 <script>
 import DateTimeCell from '@/components/DateTimeCell';
-
+import RuleCategorySelectorCell from '@/components/RuleCategorySelectorCell1'
+import CategorySelectorCell from '@/components/CategorySelectorCell'
 import NumberInput from '@/components/NumberInput';
 import Vue from 'vue';
 import moment from 'moment'
@@ -283,9 +349,14 @@ export default {
     EmployeeSelectorCell,
     Mtextarea,
     DateTimeCell,
-    NumberInput
+    NumberInput,
+    RuleCategorySelectorCell,
+    CategorySelectorCell
   },
   data() {
+    let pts = this.$getTypes;
+    let ptB = pts.filter(pt => pt.code === 'BF');
+    ptB = ptB ? ptB[0] : null;
     return {
       point: 0,
       exced: 0, // 超预期计算标准
@@ -378,12 +449,30 @@ export default {
       executor_name: [],
       reviewer: [], // 登录员工的信息,
       manage_scope: this.$userInfo().employee_detail.manage_scope,
+      pts:pts,
+      rule_items:[],
+      rules:[],
       data: {
+        rule_type:0,
+        rule_id:0,
+        item_id:0,
+        rule_item:{
+          id:0,
+          remark:"",
+          cycle_type: 0,
+          is_attendance: 0,
+          max_point: 0,
+          min_point: 0,
+          prize_type: 0,
+          pt_id: 0,
+          range_type: 0,
+          rule_id: 0,
+        },
         targets: [],
-        pt_id: 0,
+        pt_id: ptB ? ptB.id : 0,
         task_name: '',
         task_remark: '',
-        base_point: 0,
+        base_point: 1,
         expire_time: '',
         package_id: 0,
         weight: 0,
@@ -399,7 +488,8 @@ export default {
         super_satisfied: 0,
         cate_id: 0,
         task_cycle: 0,
-        task_expire_day: 0
+        task_expire_day: 0,
+        schedule_expire_date:''
       },
       title: '发布指派任务',
       url1: '/api/pro/integral/work/publish',
@@ -417,7 +507,9 @@ export default {
       pointLevel: {},
       employee_map: this.$getEmployeeMap(),
       approver_manage_scope: [],
-      point_types: this.$getTypes
+      point_types: pts,
+      showScheduleExpireDate:false,
+      scheduleExpireDate:null
     };
   },
   watch: {
@@ -436,6 +528,7 @@ export default {
     'data.task_cycle': function(val) {
       this.data.task_expire_day = 1;
       this.task_expire_day = 0;
+      this.scheduleExpireDate = null;
       if (this.data.task_cycle == 1) {
         this.task_expire_day_text = this.columns1[this.data.task_expire_day - 1];
       } else if (this.data.task_cycle == 2) {
@@ -464,9 +557,84 @@ export default {
           arr.push(self.employee_map[val[i].id].employee_detail.superior_list);
         }
       }
+    },
+    scheduleExpireDate(val){
+      // console.log('任务 schedule expire Date',val);
+      this.data.schedule_expire_date = val ? moment(val).format('YYYY-MM-DD') : '';
+      // console.log('任务 ',this.data)
+      if (val) this.toast("重复任务将在" + this.data.schedule_expire_date + "停止自动发布")
+    },
+    'data.rule_type'(val){
+      this.initRuleData()
+    },
+    rules(rules){
+      this.data.rule_id = rules.length <= 0 ? 0 : rules[0].id
+    },
+    rule_items(items){
+      this.data.rule_item = items.length <= 0 ? {
+        id:0,
+        remark:"",
+        cycle_type: 0,
+        is_attendance: 0,
+        max_point: 0,
+        min_point: 0,
+        prize_type: 0,
+        pt_id: 0,
+        range_type: 0,
+        rule_id: 0,
+      } : {
+        id:items[0].id,
+        remark:items[0].remark,
+        cycle_type: items[0].cycle_type,
+        is_attendance: items[0].is_attendance,
+        max_point: items[0].max_point,
+        min_point: items[0].min_point,
+        prize_type: items[0].prize_type,
+        pt_id: items[0].pt_id,
+        range_type: items[0].range_type,
+        rule_id: items[0].rule_id,
+      }
+      this.data.rule_id = this.data.rule_item.rule_id
+      this.data.item_id = this.data.rule_item.id
+      this.data.base_point = this.data.rule_item.min_point !== 0 ? this.data.rule_item.min_point : 1
+    },
+    'data.pt_id'(val){
+      if (this.data.rule_type === 2) this.initRuleData()
+    }
+  },
+  computed:{
+    ruleItemLabel(){
+      if (this.data.rule_item.id <= 0) return ''
+      let pt = this.pts.find( t => t.id === this.data.rule_item.pt_id)
+      return this.data.rule_item.range_type === 1 ? `${this.data.rule_item.min_point} ${pt.name}` : `${this.data.rule_item.min_point} - ${this.data.rule_item.max_point} ${pt.name}`
+    },
+    minPoint(){
+      return this.data.rule_type !== 2 ? 1 : (this.data.rule_item.id <= 0 ? 1 : this.data.rule_item.min_point)
+    },
+    maxPoint(){
+      return this.data.rule_type !== 2 ? 100000 : (this.data.rule_item.id <= 0 ? 1 : this.data.rule_item.max_point)
     }
   },
   methods: {
+    initRuleData(){
+      this.data.rule_id = 0
+      this.data.item_id = 0
+      this.data.rule_item = {
+        id:0,
+        remark:"",
+        cycle_type: 0,
+        is_attendance: 0,
+        max_point: 0,
+        min_point: 0,
+        prize_type: 0,
+        pt_id: 0,
+        range_type: 0,
+        rule_id: 0,
+      }
+      this.data.base_point = 1
+      this.rule_items = []
+      this.rules = []
+    },
     changeunqualified(val) {
       let str = '' + this.data.super_satisfied;
       let str2 = '';
@@ -628,6 +796,7 @@ export default {
     qkData() {
       this.executor_name = [];
       this.reviewer = [];
+      this.scheduleExpireDate = null;
       this.data = {
         targets: [],
         pt_id: 0,
@@ -646,7 +815,7 @@ export default {
         super_satisfied: 0,
         cate_id: 0,
         task_cycle: 0,
-        task_expire_day: 0
+        schedule_expire_date:''
       };
     },
     ahead_timeout(item, arr, codes, code) {
@@ -732,6 +901,9 @@ export default {
       }else if(this.data.task_cycle==3&&this.data.task_expire_day<=moment().format('D')){
       	is=false
       }
+
+      if (!data.schedule_expire_date) delete data.schedule_expire_date;
+
       this.$axiosUser('post', url, data).then(res => {
             if(this.data.task_cycle&&is){
               let str=this.data.task_cycle==1? '您发布的每日重复任务将于明天0点执行自动发布,是否需要立即发布一条任务?':this.data.task_cycle==2? '您发布的每周重复任务将于下周一执行自动发布,是否需要立即发布一条任务?':'您发布的每月重复任务将于下个月1号执行自动发布,是否需要立即发布一条任务?'
@@ -783,6 +955,19 @@ export default {
     	});
     },
     sava_btn() {
+      // console.log('任务 save btn',this.data);return;
+      if (this.data.rule_type === 1 && this.data.rule_id <= 0){
+        this.$toast.fail ("请选择规则分类")
+        return
+      }
+      if (this.data.rule_type === 2 && this.data.item_id <= 0){
+        this.$toast.fail('请选择积分规则')
+        return;
+      }
+      if (this.data.base_point <= 0) {
+        this.$toast.fail('积分必须大于0')
+        return;
+      }
       let self = this;
       if (this.data.base_point === 0) {
         self.$notify({ type: 'danger', message: '任务积分不能为0' });
@@ -795,6 +980,14 @@ export default {
           self.sub();
         }
       });
+    },
+    scheduleExpireDateConfirm(val){
+      this.showScheduleExpireDate = false;
+      this.scheduleExpireDate = val;
+    },
+    clearScheduleExpireDate(){
+      this.showScheduleExpireDate = false;
+      this.scheduleExpireDate = null;
     }
   },
   activated() {

+ 341 - 122
src/point/view/task/taskFile.vue

@@ -8,42 +8,53 @@
 
     <div class="body_com has_header">
       <scroller>
-        <van-cell class="efficiency_list" size="large">
+        <van-cell
+          class="efficiency_list"
+          size="large"
+          :title="info.employee_name"
+        >
           <template slot="icon">
             <userImage :user_name="info.employee_name" :img_url="info.img_url" width="1rem" height="1rem" style="margin-right: 0.12rem;"></userImage>
           </template>
-          <template slot="title">
-            <span>{{ info.employee_name }}</span>
-            <div style="color: #909399;" v-if="info.dept_list.length > 0">
-              <span v-for="(item, index) in info.dept_list" :key="index">
+          <template slot="label">
+            <span v-if="info.dept_list.length > 0" v-for="(item, index) in info.dept_list" :key="index" class="sub-title">
                 <em v-if="index > 0">,</em>
                 {{ item.dept_name }}
               </span>
-            </div>
-            <div style="color: #909399;" v-if="info.dept_list.length == 0">暂无部门</div>
+            <span v-else>暂无部门</span>
           </template>
           <template slot="default">
-            <div style="float: right;text-align: center;padding:0 0.1rem;" v-if="info.status == 4">
+            <div style="float: right;text-align: center;padding:0 0.1rem;" v-if="info.status == 4" class="sub-title">
               <span class="point-span">{{ info.point_config.review_point }}</span>
               <div style="color: #909399;">最终分</div>
             </div>
-
             <div style="float: right;text-align: center;padding:0 0.1rem;">
-              <span class="point-span">{{ info.point_config.base_point }}</span>
-              <div style="color: #909399;">{{ info.pt_name }}</div>
+              <span class="point-span">{{ `${info.point_config.base_point} ${info.pt_name}` }}</span>
             </div>
           </template>
         </van-cell>
-        <van-cell-group :border="false" class="task_detail_group" v-if="info.review_status == 2">
-          <van-cell :border="false">
+        <van-cell-group
+          :border="false"
+          class="task_detail_group"
+          v-if="info.review_status === 2"
+        >
+          <van-cell
+            :border="false"
+            title-class="align_self"
+            value-class="align_self"
+          >
             <template slot="title">
               <div class="time">
                 <span>审批结果</span>
-                <span class="timeExactly red">已驳回</span>
+                <span class="timeExactly red">已拒绝</span>
               </div>
             </template>
           </van-cell>
-          <van-cell :border="false">
+          <van-cell
+            :border="false"
+            title-class="align_self"
+            value-class="align_self"
+          >
             <template slot="title">
               <div class="time">
                 <span>驳回理由</span>
@@ -53,106 +64,283 @@
           </van-cell>
         </van-cell-group>
 
-        <van-cell-group :border="false" class="task_detail_group">
-          <van-cell :border="false">
-            <template slot="title">
-              <div class="time">
-                <span>工作内容</span>
-                <span class="timeExactly" style="white-space: pre-line;">{{ info.task_name }}</span>
-              </div>
-            </template>
-          </van-cell>
-          <van-cell :border="false">
-            <template slot="title">
-              <div class="time">
-                <span>发布时间</span>
-                <span class="timeExactly">{{ info.create_time }}</span>
-              </div>
-            </template>
-          </van-cell>
-          <van-cell :border="false">
-            <template slot="title">
-              <div class="time">
-                <span>截止时间</span>
-                <span class="timeExactly">{{ info.expire_time }}</span>
-                <span style="padding-left: 10px;" class="red" v-show="info.expire_day > 0">逾期{{ info.expire_day }}天</span>
-              </div>
-            </template>
-          </van-cell>
-          <van-cell v-if="info.point_config.ahead_award_point * 1 > 0" :border="false">
-            <template slot="title">
-              <div class="time">
-                <span>提前奖分</span>
-                <span class="timeExactly">{{ info.point_config.ahead_award_point }}分/天</span>
-              </div>
-            </template>
-          </van-cell>
-          <van-cell v-if="info.point_config.timeout_deduction_point * 1 > 0" :border="false">
-            <template slot="title">
-              <div class="time">
-                <span>逾期扣分</span>
-                <span class="timeExactly">{{ info.point_config.timeout_deduction_point }}分/天</span>
-              </div>
-            </template>
-          </van-cell>
-          <van-cell :border="false">
-            <template slot="title">
-              <div class="time">
-                <span>任务备注</span>
-                <span class="timeExactly" style="white-space: pre-line;">{{ info.task_remark }}</span>
-              </div>
+        <van-row justify="space-around" class="item-title">
+          <van-col span="6" >任务信息</van-col>
+        </van-row>
+        <van-cell-group
+          :border="false"
+          class="task_detail_group"
+          inset
+        >
+          <van-cell
+            title-class="align_self"
+            value-class="align_self"
+            :border="false"
+            title="审批人"
+            :value="info.reviewer_name"
+          />
+          <van-cell
+            title-class="align_self"
+            value-class="align_self"
+            :border="false"
+            title="发布人"
+            :value="info.publisher_name"
+          />
+          <van-cell
+            title-class="align_self"
+            value-class="align_self"
+            :border="false"
+            title="任务积分"
+            :value="`${info.point_config.base_point} ${info.pt_name || ''}`"
+          />
+          <van-cell
+            title-class="align_self"
+            value-class="align_self"
+            :border="false"
+            title="内容"
+            :value="info.task_name"
+          />
+          <van-cell
+            title-class="align_self"
+            value-class="align_self"
+            v-if="info.task_remark"
+            :border="false"
+            title="任务备注"
+            :value="info.task_remark"
+          />
+          <van-cell
+            title-class="align_self"
+            value-class="align_self"
+            :border="false"
+            title="发布时间"
+            :value="info.create_time"
+          />
+          <van-cell
+            title-class="align_self"
+            value-class="align_self"
+            v-if="info.point_config.review_point"
+            :border="false"
+            title="最终分"
+            :value="info.point_config.review_point"
+          />
+          <van-cell
+            title-class="align_self"
+            value-class="align_self"
+            :border="false"
+            title="截止时间"
+          >
+            <template slot="default">
+              {{ info.expire_time }} <span style="padding-left: 10px;" class="red" v-show="info.expire_day > 0">逾期{{ info.expire_day }}天</span>
             </template>
           </van-cell>
+          <van-cell
+            title-class="align_self"
+            value-class="align_self"
+            v-if="info.point_config.timeout_deduction_point > 0"
+            :border="false"
+            title="逾期扣分"
+            :value="`${info.point_config.timeout_deduction_point} B分/天`"
+          />
+          <van-cell
+            title-class="align_self"
+            value-class="align_self"
+            v-if="info.point_config.ahead_award_point > 0"
+            :border="false"
+            title="提前奖分"
+            :value="`${info.point_config.ahead_award_point} B分/天`"
+          />
 
-          <van-cell :border="false">
-            <template slot="title">
-              <div class="time">
-                <span>审批人</span>
-                <span class="timeExactly">{{ info.reviewer_name }}</span>
-              </div>
-            </template>
-          </van-cell>
-          <van-cell :border="false" v-if="info.review_remark">
-            <template slot="title">
-              <div class="time">
-                <span>审批意见</span>
-                <span class="timeExactly" style="white-space: pre-line;">{{ info.review_remark }}</span>
-              </div>
-            </template>
-          </van-cell>
 
-          <van-cell :border="false">
-            <template slot="title">
-              <div class="time">
-                <span>发布人</span>
-                <span class="timeExactly">{{ info.publisher_name }}</span>
-              </div>
-            </template>
-          </van-cell>
 
-          <van-cell :border="false">
-            <template slot="title">
-              <div class="time">
-                <span>积分种类</span>
-                <span class="timeExactly">{{ info.pt_name }}</span>
-              </div>
-            </template>
-          </van-cell>
 
-          <van-cell :border="false" v-if="info.task_file_list.length != 0">
-            <template slot="title">
-              <div class="time">
-                <span>任务图片</span>
-                <span>
-                  <van-image v-for="(items, index) in info.task_file_list" :key="index" @click="open_image(info.task_file_list)" width="45" height="45" radius="3" :src="items" />
-                </span>
-              </div>
-            </template>
-          </van-cell>
+<!--          <van-cell :border="false">-->
+<!--            <template slot="title">-->
+<!--              <div class="time">-->
+<!--                <span>发布时间</span>-->
+<!--                <span class="timeExactly">{{ info.create_time }}</span>-->
+<!--              </div>-->
+<!--            </template>-->
+<!--          </van-cell>-->
+<!--          <van-cell :border="false">-->
+<!--            <template slot="title">-->
+<!--              <div class="time">-->
+<!--                <span>截止时间</span>-->
+<!--                <span class="timeExactly">{{ info.expire_time }}</span>-->
+<!--                <span style="padding-left: 10px;" class="red" v-show="info.expire_day > 0">逾期{{ info.expire_day }}天</span>-->
+<!--              </div>-->
+<!--            </template>-->
+<!--          </van-cell>-->
+<!--          <van-cell v-if="info.point_config.ahead_award_point * 1 > 0" :border="false">-->
+<!--            <template slot="title">-->
+<!--              <div class="time">-->
+<!--                <span>提前奖分</span>-->
+<!--                <span class="timeExactly">{{ info.point_config.ahead_award_point }}分/天</span>-->
+<!--              </div>-->
+<!--            </template>-->
+<!--          </van-cell>-->
+<!--          <van-cell v-if="info.point_config.timeout_deduction_point * 1 > 0" :border="false">-->
+<!--            <template slot="title">-->
+<!--              <div class="time">-->
+<!--                <span>逾期扣分</span>-->
+<!--                <span class="timeExactly">{{ info.point_config.timeout_deduction_point }}分/天</span>-->
+<!--              </div>-->
+<!--            </template>-->
+<!--          </van-cell>-->
+<!--          <van-cell :border="false">-->
+<!--            <template slot="title">-->
+<!--              <div class="time">-->
+<!--                <span>任务备注</span>-->
+<!--                <span class="timeExactly" style="white-space: pre-line;">{{ info.task_remark }}</span>-->
+<!--              </div>-->
+<!--            </template>-->
+<!--          </van-cell>-->
+
+<!--          <van-cell :border="false">-->
+<!--            <template slot="title">-->
+<!--              <div class="time">-->
+<!--                <span>审批人</span>-->
+<!--                <span class="timeExactly">{{ info.reviewer_name }}</span>-->
+<!--              </div>-->
+<!--            </template>-->
+<!--          </van-cell>-->
+<!--          <van-cell :border="false" v-if="info.review_remark">-->
+<!--            <template slot="title">-->
+<!--              <div class="time">-->
+<!--                <span>审批意见</span>-->
+<!--                <span class="timeExactly" style="white-space: pre-line;">{{ info.review_remark }}</span>-->
+<!--              </div>-->
+<!--            </template>-->
+<!--          </van-cell>-->
+
+<!--          <van-cell :border="false">-->
+<!--            <template slot="title">-->
+<!--              <div class="time">-->
+<!--                <span>发布人</span>-->
+<!--                <span class="timeExactly">{{ info.publisher_name }}</span>-->
+<!--              </div>-->
+<!--            </template>-->
+<!--          </van-cell>-->
+
+<!--          <van-cell :border="false">-->
+<!--            <template slot="title">-->
+<!--              <div class="time">-->
+<!--                <span>积分种类</span>-->
+<!--                <span class="timeExactly">{{ info.pt_name }}</span>-->
+<!--              </div>-->
+<!--            </template>-->
+<!--          </van-cell>-->
+
+<!--          <van-cell :border="false" v-if="info.task_file_list.length != 0">-->
+<!--            <template slot="title">-->
+<!--              <div class="time">-->
+<!--                <span>任务图片</span>-->
+<!--                <span>-->
+<!--                  <van-image v-for="(items, index) in info.task_file_list" :key="index" @click="open_image(info.task_file_list)" width="45" height="45" radius="3" :src="items" />-->
+<!--                </span>-->
+<!--              </div>-->
+<!--            </template>-->
+<!--          </van-cell>-->
         </van-cell-group>
 
-        <van-cell-group class="point" v-if="info.point_config.standard && info.point_config.standard.super_satisfied * 1 > 0">
-          <van-cell v-if="info.point_config.standard" title="评分标准">
+
+
+        <template v-if="info.item_info">
+          <van-row justify="space-around" class="item-title">
+            <van-col span="6" >规则依据</van-col>
+          </van-row>
+          <van-cell-group
+            :border="false"
+            class="task_detail_group"
+            inset
+          >
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              :border="false"
+              title="规则"
+              :value="info.item_info.remark"
+            />
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              :border="false"
+              title="积分"
+              :value="pointRemark"
+            />
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              v-if="info.item_info.has_delete"
+              :border="false"
+              title="规则状态"
+            >
+              <template slot="default">
+                <van-tag type="warning">规则已删除</van-tag>
+              </template>
+            </van-cell>
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              v-if="info.rule_info"
+              :border="false"
+              title="分类"
+              :value="info.rule_info.name"
+            />
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              v-if="info.rule_info && info.rule_info.has_delete"
+              :border="false"
+              title="分类状态"
+            >
+              <template slot="default">
+                <van-tag type="warning">分类已删除</van-tag>
+              </template>
+            </van-cell>
+          </van-cell-group>
+        </template>
+
+        <template v-else-if="info.rule_info">
+          <van-row justify="space-around" class="item-title">
+            <van-col span="6" >分类依据</van-col>
+          </van-row>
+          <van-cell-group
+            :border="false"
+            class="task_detail_group"
+            inset
+          >
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              :border="false"
+              title="分类"
+              :value="info.rule_info.name"
+            />
+            <van-cell
+              title-class="align_self"
+              value-class="align_self"
+              v-if="info.rule_info.has_delete"
+              :border="false"
+              title="分类状态"
+            >
+              <template slot="default">
+                <van-tag type="warning">分类已删除</van-tag>
+              </template>
+            </van-cell>
+          </van-cell-group>
+        </template>
+
+        <van-cell-group
+          class="point"
+          v-if="info.point_config.standard && info.point_config.standard.super_satisfied * 1 > 0"
+          inset
+        >
+          <van-cell
+            title-class="align_self"
+            value-class="align_self"
+            v-if="info.point_config.standard"
+            title="评分标准"
+          >
             <template slot="label">
               <van-grid slot="label" :border="false">
                 <van-grid-item text="超预期">
@@ -195,6 +383,7 @@
             </van-slider>
           </div>
         </van-panel>
+
         <div class="task">
           <van-row>
             <van-col span="16">
@@ -204,8 +393,8 @@
               </van-tabs>
             </van-col>
             <van-col span="8" style="background:#fff;border-bottom:0.02rem #efefef solid;">
-              <div v-if="active == 0 && info.employee_id == $userInfo().id && info.status < 3" @click="remberOne" class="rember">+记一条</div>
-              <div v-if="active != 0 && isShowJf" @click="noteone" class="rember">记分</div>
+              <div v-if="active === 0 && canUpdate" @click="remberOne" class="rember">+记一条</div>
+              <div v-if="active !== 0 && isShowJf" @click="noteone" class="rember">记分</div>
             </van-col>
           </van-row>
           <div ref="scoringNotice" style="clear: both;">
@@ -217,7 +406,7 @@
           <van-cell-group
             v-if="info.process !== null && info.process.list !== null"
             v-for="(item, index) in info.process.list"
-            :key="index"
+            :key="'record' + index"
             v-show="active == 0 && item.point == 0"
             :border="false"
           >
@@ -257,7 +446,7 @@
           <van-cell-group
             v-if="info.process !== null && info.process.list !== null"
             v-for="(item, index) in info.process.list"
-            :key="index"
+            :key="'point' + index"
             v-show="info.process.list !== null && active != 0 && item.point != 0"
             :border="false"
           >
@@ -297,7 +486,6 @@
           <van-cell-group style="background: none;" v-show="active != 0 && point_list.length == 0">
             <noTask src="static/images/noTask.png" detail_text="还没有记分记录去记一条吧" />
           </van-cell-group>
-
         </div>
 
         <div v-if="text_list.length != 0 || point_list.length != 0" style="height: 2rem;"></div>
@@ -307,7 +495,7 @@
       <div style="padding:0.32rem;width: 90%;position: fixed;bottom: 0;" v-if="info.reviewer_id == $userInfo().id && info.status == 2&&!isShowSp">
         <van-button block type="info" @click="go_approval">去审批</van-button>
       </div>
-      <div style="padding:0.32rem;width: 90%;position: fixed;bottom: 0;" v-if="info.employee_id == $userInfo().id && info.status == 1&&!isShowSp">
+      <div style="padding:0.4rem;width: 90%;position: fixed;bottom: 0; background-color: white;" v-if="canUpdate&&!isShowSp">
         <van-button block type="info" @click="complete_task(info)">完成</van-button>
       </div>
     </div>
@@ -335,11 +523,12 @@ export default {
   // 数据
   data () {
     return {
+      userInfo:this.$userInfo(),
       The_current_account: false,
       active: 0,
       numberslider: 0,
       active1: 'running',
-      title: '工作详情',
+      title: '任务详情',
       filter: {
         page: 1,
         type: 'all',
@@ -369,7 +558,11 @@ export default {
         status_mark: '',
         task_file_list: [],
         task_name: '',
-        task_remark: ''
+        task_remark: '',
+        rule_id:0,
+        rule_info:{},
+        item_id:0,
+        item_info:{}
       },
       process: [],
       checked: false,
@@ -403,6 +596,7 @@ export default {
   },
   activated() {
   	if (this.$route.query.task_id) {
+      this.info.id = this.$route.query.task_id
   	  this.getList()
   	}
     if(this.$route.query.isHome){
@@ -434,7 +628,7 @@ export default {
     },
 
     sheet_select (action, index) {
-      if (action.name == '编辑任务') {
+      if (action.name == '更新任务') {
         if (this.$route.query.isJx) {
           // 编辑 从上一个页面传过来一些参数
           this.$router.push({
@@ -446,7 +640,8 @@ export default {
             }
           })
         } else {
-          this.$router.push({ name: 'compile_task', query: { info: JSON.stringify(this.info) } })
+          this.$router.push({name:'WorkEdit',params:{workId:this.$route.query.task_id.toString()}})
+          // this.$router.push({ name: 'compile_task', query: { info: JSON.stringify(this.info) } })
         }
       }
       if (action.name == '撤销任务') {
@@ -537,10 +732,10 @@ export default {
       // 这里比较复杂,因为团队绩效的工作详情跟我的发布的工作详情都调用这个页面
       if (data.status == 1) {
         if (data.pt_id != 1) {
-          this.actions.push({ name: '编辑任务' })
+          this.actions.push({ name: '更新任务' })
           this.actions.push({ name: '删除任务' })
         } else if (data.pt_id == 1 && this.$route.query.isJx) {
-          this.actions.push({ name: '编辑任务' })
+          this.actions.push({ name: '更新任务' })
           this.actions.push({ name: '删除任务' })
         } else {
           this.actions.push({ name: '删除任务' })
@@ -550,16 +745,16 @@ export default {
       }
     },
     keepTheScore(data){
-      if(data.status > 2){
+      if(![1,2,6].includes(data.status)){
         return false
       }
-      if(this.$userInfo().id == data.reviewer_id){
+      if(this.userInfo.id === data.reviewer_id){
         return true
       }
       let info=this.$getEmployeeMapItem(data.employee_id)
       if(info){
         return info.employee_detail.superior_list.some(x =>{
-          if(this.$userInfo().id == x.id){
+          if(this.userInfo.id === x.id){
             return true
           }
         })
@@ -632,6 +827,15 @@ export default {
       })
     }
   },
+  computed:{
+    canUpdate(){
+      return this.info.employee_id === this.userInfo.id && [1,6].includes(this.info.status)
+    },
+    pointRemark(){
+      if (!(this.info && this.info.item_info)) return ''
+      return this.info.item_info.range_type === 1 ? `${this.info.item_info.min_point} ${this.$getTypesName(this.info.item_info.pt_id)}` : `${this.info.item_info.min_point} -- ${this.info.item_info.max_point} ${this.$getTypesName(this.info.item_info.pt_id)}`
+    }
+  },
   mounted () {
     this.getLocalStorage()
   },
@@ -892,4 +1096,19 @@ export default {
   -webkit-transform: scale(0.5);
   transform: scale(0.5);
 }
+.item-title{
+  text-align: center;
+  margin-top: 10px;
+  font-size: 0.25rem;
+  line-height: 0.5rem;
+  color: #969799;
+}
+.sub-title{
+  font-size: 0.25rem;
+  line-height: 0.25rem;
+  color: #969799;
+}
+.align_self{
+  align-self: center;
+}
 </style>

+ 188 - 43
src/point/view/task/task_detail_a.vue

@@ -10,7 +10,10 @@
     <div class="body_com has_header">
       <scroller v-if="info.point_config">
 
-        <van-cell-group class="task_detail_list_box">
+        <van-cell-group
+          class="task_detail_list_box"
+          inset
+        >
           <van-cell v-show="info.status == 1||info.status == 4" :title="info.owner_name+`悬赏的${$getTypesName(info.pt_id)}任务`">
             <template slot="label">
               <span class="orange">{{info.status_mark}}</span>
@@ -20,52 +23,177 @@
               <userImage v-show="info.receiver_id == 0" class="fl"  :img_url="info.owner_img_url" :user_name="info.owner_name"  style="margin-right: 0.2rem"></userImage>
             </template>
             <template slot="right-icon">
-              <span class="point red" v-if="info.point_config.base_point> 0">+{{info.point_config.base_point}}{{info.pt_name}}</span>
+              <span class="point red" v-if="info.point_config.base_point > 0">+{{info.point_config.base_point}}{{info.pt_name}}</span>
               <span class="point green" v-if="info.point_config.base_point< 0">{{info.point_config.base_point}}{{info.pt_name}}</span>
             </template>
           </van-cell>
 
-          <van-cell v-show="info.status == 2||info.status == 3" :title="info.receiver_name+`领取的${$getTypesName(info.pt_id)}任务`" title-class="head" label-class="sign">
-            <template slot="label">
-              <span class="orange">{{info.status_mark}}</span>
-            </template>
-            <template slot="icon">
-              <userImage v-show="info.receiver_id != 0" class="fl"  :img_url="info.receiver_img_url" :user_name="info.receiver_name"  style="margin-right: 0.2rem"></userImage>
-              <userImage v-show="info.receiver_id == 0" class="fl"  :img_url="info.owner_img_url" :user_name="info.owner_name"  style="margin-right: 0.2rem"></userImage>
-            </template>
-            <template slot="right-icon">
-             <span class="point red" v-if="info.point_config.base_point> 0">+{{info.point_config.base_point}}{{$getTypesName(info.pt_id)}}</span>
-             <span class="point green" v-if="info.point_config.base_point< 0">{{info.point_config.base_point}}{{$getTypesName(info.pt_id)}}</span>
-            </template>
-          </van-cell>
-
-          <van-cell :border="false" :title="info.task_name" title-class="task_name" style="margin-top:0.24rem;"></van-cell>
-          <van-cell :border="false" title="任务备注" v-if="info.task_remark != ''" title-class="title fontColorC task_detail" value-class="text-left" :value="info.task_remark"></van-cell>
-          <van-cell :border="false" title="任务类型" title-class="title fontColorC" value-class="text-left">{{info.type_mark}}</van-cell>
-          <van-cell :border="false" title="积分类型" title-class="title fontColorC" value-class="text-left">{{$getTypesName(info.pt_id)}}</van-cell>
-          <van-cell :border="false" title="发布时间" title-class="title fontColorC" value-class="text-left">{{info.create_time}}</van-cell>
-          <van-cell :border="false" title="截止时间" title-class="title fontColorC" value-class="text-left">{{info.end_time}}</van-cell>
-          <van-cell :border="false" title="审批人" title-class="title fontColorC" value-class="text-left" >{{info.reviewer_name}}</van-cell>
-          <van-cell :border="false" title="发布人" title-class="title fontColorC" value-class="text-left" >{{info.owner_name}}</van-cell>
-
-
-<!--          <van-cell :border="false" title="提前奖分" title-class="title fontColorC task_delayrecord" value-class="text-left" :value="info.point_config.ahead_award_point+'分/天'" v-if="info.point_config.ahead_award_point"></van-cell>
-          <van-cell :border="false" title="逾期扣分" title-class="title fontColorC task_delayrecord" value-class="text-left" :value="info.point_config.timeout_deduction_point+'分/天'" v-if="info.point_config.timeout_deduction_point"></van-cell> -->
-
-
-          <van-cell v-if="info.department_info.length > 0" title="可见范围" title-class="title fontColorC task_delayrecord" value-class="text-left">
-            <template  slot="default">
-               <span v-for="(items,index) in info.department_info" :key="index">
-                  {{items.name}}
+          <van-cell
+            :border="false"
+            title="任务内容"
+            :value="info.task_name"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            :border="false"
+            v-if="info.receiver_id !== 0"
+            :title="info.status === 3 ? '完成人' : '领取人'"
+            :value="info.receiver_name"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            :border="false"
+            v-if="info.task_remark"
+            title="任务备注"
+            :value="info.task_remark"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            :border="false"
+            v-if="info.point_config"
+            title="任务积分"
+            :value="info.point_config.base_point + $getTypesName(info.pt_id)"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            :border="false"
+            title="发布时间"
+            :value="info.create_time"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            :border="false"
+            title="截止时间"
+            :value="info.end_time"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            :border="false"
+            v-if="info.point_config"
+            title="逾期扣分"
+            :value="`${info.point_config.timeout_deduction_point}/分`"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            :border="false"
+            v-if="info.point_config && info.point_config.ahead_award_point"
+            title="提前奖分"
+            :value="`${info.point_config.ahead_award_point}/分`"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            :border="false"
+            v-if="info.department_info"
+            title="可见范围"
+            title-class="align_self"
+            value-class="align_self"
+          >
+            <template slot="default">
+              <template v-if="info.department_info.length > 0">
+                <span
+                  v-for="(item,index) in info.department_info"
+                  :key="index"
+                >
+                  {{item.name}}&nbsp;
                 </span>
+              </template>
+              <span v-else>全公司可见</span>
             </template>
           </van-cell>
-          <van-cell title="图片" title-class="title fontColorC task_img" value-class="text-left" v-show="info.task_file_list.length > 0">
+          <van-cell
+            :border="false"
+            v-if="info.reviewer_name"
+            title="审批人"
+            :value="info.reviewer_name"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            :border="false"
+            title="任务类型"
+            :value="info.source_type_mark"
+            title-class="align_self"
+            value-class="align_self"
+          />
+          <van-cell
+            title="图片"
+            title-class="title fontColorC task_img align_self"
+            value-class="text-left align_self"
+            v-show="info.task_file_list.length > 0"
+          >
             <template slot="default">
               <van-image @click="open_img(index)" style="margin-right: 0.1rem" v-for="(item,index) in info.task_file_list" :key="index" :src="item" width="50" height="50" radius="5" type="contain"  />
             </template>
           </van-cell>
         </van-cell-group>
+
+        <template v-if="info.item_info">
+          <van-row justify="space-around" class="item-title">
+            <van-col span="6" >规则依据</van-col>
+          </van-row>
+          <van-cell-group inset>
+            <van-cell
+              :border="false"
+              title="规则"
+              :value="info.item_info.remark"
+              title-class="align_self"
+              value-class="align_self"
+            >
+              <template slot="default">
+                {{info.item_info.remark}}
+                <van-tag v-if="info.item_info.has_delete" type="warning" size="medium">已删除</van-tag>
+              </template>
+            </van-cell>
+            <van-cell
+              :border="false"
+              title="积分"
+              :value="pointRemark"
+              title-class="align_self"
+              value-class="align_self"
+            />
+            <van-cell
+              v-if="info.rule_info"
+              :border="false"
+              title="分类"
+              :value="info.rule_info.name"
+              title-class="align_self"
+              value-class="align_self"
+            >
+              <template slot="default">
+                {{info.rule_info.name}}
+                <van-tag v-if="info.rule_info.has_delete" type="warning" size="medium">已删除</van-tag>
+              </template>
+            </van-cell>
+          </van-cell-group>
+        </template>
+        <template v-else-if="info.rule_info">
+          <van-row justify="space-around" class="item-title">
+            <van-col span="6" >分类依据</van-col>
+          </van-row>
+          <van-cell-group inset>
+            <van-cell
+              :border="false"
+              title="分类"
+              title-class="align_self"
+              value-class="align_self"
+            >
+              <template slot="default">
+                {{info.rule_info.name}}
+                <van-tag v-if="info.rule_info.has_delete" type="warning" size="medium">已删除</van-tag>
+              </template>
+            </van-cell>
+          </van-cell-group>
+        </template>
+
+
         <div class="confirm_buttom" style="padding: 0.32rem" v-show="info.status == '1' && shoe_btn && user_id != info.owner_id && info.reviewer_id != user_id && !isCreator">
           <van-button type="info" block @click="receive_tasks">领取任务</van-button>
         </div>
@@ -95,7 +223,7 @@ export default {
       The_current_account: false,
       actions: [],
       sheet_show: false,
-      title: '任务详情',
+      title: '悬赏信息',
       info: {
         point_config:{},
         department_info:[],
@@ -108,17 +236,24 @@ export default {
       isCreator: this.$userInfo().is_creator,
     }
   },
+  computed:{
+    pointRemark(){
+      if (!(this.info && this.info.item_info)) return ''
+      return this.info.item_info.range_type === 1 ? `${this.info.item_info.min_point} ${this.$getTypesName(this.info.item_info.pt_id)}` : `${this.info.item_info.min_point} -- ${this.info.item_info.max_point} ${this.$getTypesName(this.info.item_info.pt_id)}`
+    }
+  },
   // 方法
   methods: {
     // 删除
     sheet_select (action) {
-      if (action.name == '编辑任务') {
-        this.$router.push({name: 'compile_temp_task', query: {info: JSON.stringify(this.info)}})
+      if (action.name == '更新悬赏') {
+        // this.$router.push({name: 'compile_temp_task', query: {info: JSON.stringify(this.info)}})
+        this.$router.push({name: 'TaskEdit', params: {taskId: this.$route.query.task_id.toString()}})
       }
-      if (action.name == '删除任务') {
+      if (action.name == '删除悬赏') {
         this.$dialog.confirm({
-          title: '删除任务',
-          message: '删除此任务将会删除其相关记录和积分数据,确认删除吗?'
+          title: '删除悬赏',
+          message: '删除此悬赏将会删除其相关记录和积分数据,确认删除吗?'
         }).then(() => {
           this.delete_task()
         })
@@ -170,9 +305,9 @@ export default {
           self.info = res.data.data
           self.shoe_btn = moment(this.time) < moment(this.info.expire_time)
           if (self.info.status == 1 && self.info.status_mark == '待领取') {
-            self.actions = [{name: '编辑任务'}, { name: '删除任务' }]
+            self.actions = [{name: '更新悬赏'}, { name: '删除悬赏' }]
           } else {
-            self.actions = [{ name: '删除任务' }]
+            self.actions = [{ name: '删除悬赏' }]
           }
         } else {
           self.$toast(res.data.msg)
@@ -258,4 +393,14 @@ export default {
 .task_detail_box .task_detail_list_box{
   padding:0.32rem 0;
 }
+.item-title{
+  text-align: center;
+  margin-top: 10px;
+  font-size: 0.25rem;
+  line-height: 0.5rem;
+  color: #969799;
+}
+.align_self{
+  align-self: center;
+}
 </style>

+ 225 - 30
src/point/view/task/temp_task.vue

@@ -15,12 +15,73 @@
               :imgs_max="3"
               images
               :imgs.sync="data.file_list"
-            ></Mtextarea>
+            />
           </van-cell>
         </van-cell-group>
         <van-cell-group class="point-field">
+          <van-cell title="积分类型" required>
+            <template slot="right-icon">
+              <van-radio-group v-model="data.pt_id" direction="horizontal" class="radio_button">
+                <van-radio class="list" :class="{ changeRadio: item.id === data.pt_id }" v-if="item.code !== 'JX'" :name="item.id" v-for="(item, index) in pts" :key="index">
+                  {{ item.name }}
+                </van-radio>
+              </van-radio-group>
+<!--              <smallTip icon="question-o" position="30%">-->
+<!--                <p style="margin: 0; line-height: 0.6rem">A分:物质分,与钱直接挂钩</p>-->
+<!--                <p style="margin: 0; line-height: 0.6rem">B分:福利分,与福利待遇挂钩</p>-->
+<!--                <p style="margin: 0; line-height: 0.6rem">绩效分:工作分,与绩效考核挂钩</p>-->
+<!--              </smallTip>-->
+            </template>
+          </van-cell>
+          <van-cell title="指定规则">
+            <template slot="right-icon">
+              <van-radio-group
+                v-model="data.rule_type"
+                direction="horizontal"
+                class="radio_button"
+              >
+                <van-radio class="list" :name="0" >
+                  <span class="rule_type_span">不指定</span>
+                </van-radio>
+                <van-radio class="list" :name="1" >
+                  <span class="rule_type_span">分类</span>
+                </van-radio>
+                <van-radio class="list" :name="2" >
+                  <span class="rule_type_span">规则</span>
+                </van-radio>
+              </van-radio-group>
+            </template>
+          </van-cell>
+<!--     选择分类     -->
+          <CategorySelectorCell
+            v-if="data.rule_type === 1"
+            title="细则分类"
+            v-model="rules"
+            required
+            :pt-id="data.pt_id"
+            :multi="false"
+            scope
+          />
+
+
+          <!--选择规则  -->
+          <RuleCategorySelectorCell
+            v-if="data.rule_type === 2"
+            :pt-id="data.pt_id"
+            required
+            name="请选择积分规则"
+            title="积分规则"
+            v-model="rule_items"
+            scope
+            :multi="false"
+          >
+            <template slot="label">
+              <span style="color: red">{{ruleItemLabel}}</span>
+            </template>
+          </RuleCategorySelectorCell>
+
           <van-cell title="任务积分" style="padding:0 0.32rem; padding-top:0.16rem;" :border="false" required />
-          <NumberInput v-model="data.base_point" v-validate="'required'" :chosePoint="false" :min="0" :max="100000"></NumberInput>
+          <NumberInput v-model="data.base_point" v-validate="'required'" :min="minPoint" :max="maxPoint"/>
         </van-cell-group>
 
         <van-cell-group>
@@ -34,20 +95,6 @@
             v-model="reviewer"
             :multi="false"
           ></EmployeeSelectorCell>
-          <van-cell title="任务类型" required>
-            <template slot="right-icon">
-              <van-radio-group v-model="data.pt_id" direction="horizontal" class="radio_button">
-                <van-radio class="list" :class="{ changeRadio: item.id === data.pt_id }" v-if="item.code != 'JX'" :name="item.id" v-for="(item, index) in $getTypes" :key="index">
-                  {{ item.name }}
-                </van-radio>
-              </van-radio-group>
-              <smallTip icon="question-o" position="30%">
-                <p style="margin: 0; line-height: 0.6rem">A分:物质分,与钱直接挂钩</p>
-                <p style="margin: 0; line-height: 0.6rem">B分:福利分,与福利待遇挂钩</p>
-                <p style="margin: 0; line-height: 0.6rem">绩效分:工作分,与绩效考核挂钩</p>
-              </smallTip>
-            </template>
-          </van-cell>
           <van-cell title="重复周期"  @click="show_task_cycle_popup = true">
               <template>
                 <span v-if="data.task_cycle == 0">不重复</span>
@@ -60,6 +107,13 @@
           <van-cell :value="'每天' + task_expire_day_text" is-link @click="show_task_expire_day = true" title="截止时间" v-if="data.task_cycle == 1" />
           <van-cell :value="'每' + task_expire_day_text" is-link @click="show_task_expire_day = true" title="截止时间" v-if="data.task_cycle == 2" />
           <van-cell :value="'每月' + task_expire_day_text" is-link @click="show_task_expire_day = true" title="截止时间" v-if="data.task_cycle == 3" />
+          <van-cell title="有效日期" v-if="data.task_cycle !== 0" @click="showScheduleExpireDate = true" :value="data.schedule_expire_date" :center="true">
+            <template #right-icon >
+              <van-icon color="#A4A5A7"  name="arrow" v-if="!data.schedule_expire_date" />
+              <van-icon color="#A4A5A7"  name="close" v-else @click.stop="clearScheduleExpireDate" style="margin-left: 10px" />
+            </template>
+          </van-cell>
+
           <van-field v-model="data.ahead_award_point" type="digit">
             <template slot="label">
               <div class="flex-box-ce">
@@ -254,12 +308,25 @@
         @confirm="task_expire_dayonChange"
       />
     </van-popup>
+
+
+    <van-calendar
+      title="有效日期"
+      color="#26A2FF"
+      v-model="showScheduleExpireDate"
+      :show-confirm="false"
+      :default-date="scheduleExpireDate"
+      @confirm="scheduleExpireDateConfirm"
+    />
+
+
   </div>
 </template>
 <script>
 import DeptSelectorCell from '@/components/DeptSelectorCell';
 import DateTimeCell from '@/components/DateTimeCell';
-
+import RuleCategorySelectorCell from '@/components/RuleCategorySelectorCell1'
+import CategorySelectorCell from '@/components/CategorySelectorCell'
 import NumberInput from '@/components/NumberInput';
 import Vue from 'vue';
 import moment from 'moment'
@@ -277,6 +344,10 @@ Vue.use(calendar)
 export default {
   data() {
     const reviewer = [this.$userInfo()];
+    let pts = this.$getTypes;
+    let ptB = pts.filter(pt => pt.code === 'BF');
+    ptB = ptB ? ptB[0] : null;
+
     return {
       isNeed: !this.$getCache('isAndroid'),
       bar_height: 0,
@@ -344,12 +415,30 @@ export default {
         '31号'
       ],
       reviewer: reviewer,
+      pts: pts,
+      rule_items:[],
+      rules:[],
       data: {
+        rule_type:0,
+        rule_id:0,
+        item_id:0,
+        rule_item:{
+          id:0,
+          remark:"",
+          cycle_type: 0,
+          is_attendance: 0,
+          max_point: 0,
+          min_point: 0,
+          prize_type: 0,
+          pt_id: 0,
+          range_type: 0,
+          rule_id: 0,
+        },
         task_type: 1,
-        pt_id: 0,
+        pt_id: ptB ? ptB.id : 0,
         task_name: '',
         task_remark: '',
-        base_point: 0,
+        base_point: 1,
         expire_time: '',
         file_list: [],
         reviewer_id: this.$userInfo().id,
@@ -359,7 +448,8 @@ export default {
         ahead_award_point_limit: '',
         dept_ids: [],
         task_cycle: 0,
-        task_expire_day: 1
+        task_expire_day: 1,
+        schedule_expire_date:''
       },
       title: '发布悬赏任务',
       post_data: {},
@@ -373,6 +463,8 @@ export default {
       show_timeout_deduction_point_popup: false,
       show_task_remark_popup: false,
       flexDialog:false,
+      showScheduleExpireDate:false,
+      scheduleExpireDate:null
     };
   },
   components: {
@@ -381,12 +473,15 @@ export default {
     DateTimeCell,
     DeptSelectorCell,
     smallTip,
-    NumberInput
+    NumberInput,
+    RuleCategorySelectorCell,
+    CategorySelectorCell,
   },
   watch: {
     'data.task_cycle': function(val) {
       this.data.task_expire_day = 1;
       this.task_expire_day = 0;
+      this.scheduleExpireDate = null;
       if (this.data.task_cycle == 1) {
         this.task_expire_day_text = this.columns1[this.data.task_expire_day - 1];
       } else if (this.data.task_cycle == 2) {
@@ -412,6 +507,62 @@ export default {
           this.data.dept_ids.push(val[i].dept_id);
         }
       }
+    },
+    scheduleExpireDate(val){
+      // console.log('悬赏 schedule expire date',val);
+      this.data.schedule_expire_date = val ? moment(val).format('YYYY-MM-DD') : '';
+      // console.log('悬赏',this.data);
+      if (val) this.$toast("重复悬赏将在" + this.data.schedule_expire_date + "停止自动发布")
+    },
+    'data.rule_type'(val){
+      this.initRuleData()
+    },
+    rules(rules){
+      this.data.rule_id = rules.length <= 0 ? 0 : rules[0].id
+    },
+    rule_items(items){
+      this.data.rule_item = items.length <= 0 ? {
+        id:0,
+        remark:"",
+        cycle_type: 0,
+        is_attendance: 0,
+        max_point: 0,
+        min_point: 0,
+        prize_type: 0,
+        pt_id: 0,
+        range_type: 0,
+        rule_id: 0,
+      } : {
+        id:items[0].id,
+        remark:items[0].remark,
+        cycle_type: items[0].cycle_type,
+        is_attendance: items[0].is_attendance,
+        max_point: items[0].max_point,
+        min_point: items[0].min_point,
+        prize_type: items[0].prize_type,
+        pt_id: items[0].pt_id,
+        range_type: items[0].range_type,
+        rule_id: items[0].rule_id,
+      }
+      this.data.rule_id = this.data.rule_item.rule_id
+      this.data.item_id = this.data.rule_item.id
+      this.data.base_point = this.data.rule_item.min_point !== 0 ? this.data.rule_item.min_point : 1
+    },
+    'data.pt_id'(val){
+      if (this.data.rule_type === 2) this.initRuleData()
+    }
+  },
+  computed:{
+    ruleItemLabel(){
+      if (this.data.rule_item.id <= 0) return ''
+      let pt = this.pts.find( t => t.id === this.data.rule_item.pt_id)
+      return this.data.rule_item.range_type === 1 ? `${this.data.rule_item.min_point} ${pt.name}` : `${this.data.rule_item.min_point} - ${this.data.rule_item.max_point} ${pt.name}`
+    },
+    minPoint(){
+      return this.data.rule_type !== 2 ? 1 : (this.data.rule_item.id <= 0 ? 1 : this.data.rule_item.min_point)
+    },
+    maxPoint(){
+      return this.data.rule_type !== 2 ? 100000 : (this.data.rule_item.id <= 0 ? 1 : this.data.rule_item.max_point)
     }
   },
   methods: {
@@ -553,6 +704,9 @@ export default {
       }else if(this.data.task_cycle==3&&this.data.task_expire_day<=moment().format('D')){
       	is=false
       }
+
+      if (!data.schedule_expire_date) delete data.schedule_expire_date;
+
       this.$axiosUser('post', url, data).then(res => {
         if(this.data.task_cycle&&is){
           let str=this.data.task_cycle==1? '您发布的每日重复任务将于明天0点执行自动发布,是否需要立即发布一条任务?':this.data.task_cycle==2? '您发布的每周重复任务将于下周一执行自动发布,是否需要立即发布一条任务?':'您发布的每月重复任务将于下个月1号执行自动发布,是否需要立即发布一条任务?'
@@ -587,6 +741,25 @@ export default {
         this.$toast.clear();
       });
     },
+    initRuleData(){
+      this.data.rule_id = 0
+      this.data.item_id = 0
+      this.data.rule_item = {
+        id:0,
+        remark:"",
+        cycle_type: 0,
+        is_attendance: 0,
+        max_point: 0,
+        min_point: 0,
+        prize_type: 0,
+        pt_id: 0,
+        range_type: 0,
+        rule_id: 0,
+      }
+      this.data.base_point = 1
+      this.rule_items = []
+      this.rules = []
+    },
     initData(){
       this.reviewer = [];
       this.data = {
@@ -594,7 +767,7 @@ export default {
         pt_id: 0,
         task_name: '',
         task_remark: '',
-        base_point: 0,
+        base_point: 1,
         expire_time: '',
         file_list: [],
         reviewer_id: 0,
@@ -604,7 +777,8 @@ export default {
         ahead_award_point_limit: '',
         dept_ids: [],
         task_cycle: 0,
-        task_expire_day: 1
+        task_expire_day: 1,
+        schedule_expire_date: ''
       };
     },
     //执行周期任务
@@ -623,26 +797,43 @@ export default {
     	});
     },
     sava_btn() {
+      // console.log('悬赏 sava_btn',this.data);return;
+      if (this.data.rule_type === 1 && this.data.rule_id <= 0){
+        this.$toast.fail ("请选择规则分类")
+        return
+      }
+      if (this.data.rule_type === 2 && this.data.item_id <= 0){
+        this.$toast.fail('请选择积分规则')
+        return;
+      }
+      if (this.data.base_point <= 0) {
+        this.$toast.fail('积分必须大于0')
+        return;
+      }
       let self = this;
       self.$validator.validate().then(result => {
         if (!result) {
           self.$notify({ type: 'danger', message: self.$validator.errors.items[0].msg });
         } else {
-          if (self.data.base_point == 0) {
-            self.$notify({ type: 'danger', message: '任务积分必须大约0' });
+          if (self.data.base_point === 0) {
+            self.$notify({ type: 'danger', message: '任务积分不能为0' });
           } else {
             self.sub();
           }
         }
+
       });
+    },
+    scheduleExpireDateConfirm(val) {
+      this.showScheduleExpireDate = false;
+      this.scheduleExpireDate = val;
+    },
+    clearScheduleExpireDate() {
+      this.showScheduleExpireDate = false;
+      this.scheduleExpireDate = null;
     }
   },
   created() {
-    for (let i in this.$getTypes) {
-      if (this.$getTypes[i].code == 'BF') {
-        this.data.pt_id = this.$getTypes[i].id;
-      }
-    }
     if (window.plus) {
       this.bar_height = window.plus.navigator.getStatusbarHeight();
       if(!this.$getCache('flexDialog')){
@@ -785,4 +976,8 @@ export default {
 .temp_task_box .small_tip_content p:nth-child(3) {
   display: none;
 }
+.rule_type_span {
+  font-size: 0.25rem;
+  line-height: 0.5rem;
+}
 </style>

+ 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]

+ 37 - 0
src/router/pointRoute.js

@@ -351,6 +351,13 @@ const routes = [
     label: '管理者奖扣',
     need_login: true
   },
+  {
+    path: '/reward_deduction_search',
+    name: 'reward_deduction_search',
+    component: () => import('@/point/view/integral/reward_deduction_search'),
+    label: '奖扣数据查询',
+    need_login: true
+  },
   {
     path: '/reward_deduction_statistics',
     name: 'reward_deduction_statistics',
@@ -471,5 +478,35 @@ const routes = [
     label: '申请结果',
     need_login: true
   },
+  {
+    path: '/dept_rank',
+    name: 'dept_rank',
+    component: () => import('@/point/view/integral/deptRank'),
+    label: '部门排行',
+    need_login: true
+  },
+  {
+    path: '/appeal',
+    name: 'appeal',
+    component: () => import('@/point/view/integral/appealList'),
+    label: '申诉列表',
+    need_login: true
+  },
+  {
+    path:'/work/edit/:workId',
+    name:'WorkEdit',
+    component: () => import('@/point/view/task/WorkEdit'),
+    label: '任务编辑',
+    need_login: true,
+    props:true
+  },
+  {
+    path: '/task/edit/:taskId',
+    name: 'TaskEdit',
+    component: () => import("@/point/view/task/TaskEdit"),
+    label: '悬赏编辑',
+    need_login: true,
+    props: true
+  }
 ]
 export default routes

+ 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

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

@@ -5,6 +5,7 @@ import moment from 'moment'
 
 const user = {
   state: {
+    wxid:11770,
     token: '',
     user_info: {},
     account_info: {},
@@ -219,7 +220,7 @@ const user = {
           account_info = JSON.parse(localStorage.getItem('account_info'))
         }
         let nowDate = moment().format("YYYY-MM-DD HH:mm:ss");
-        if(account_info &&account_info.data.localStorageExpire&&moment(nowDate).isBefore(account_info.data.localStorageExpire)){
+        if(account_info && account_info.data && account_info.data.localStorageExpire&&moment(nowDate).isBefore(account_info.data.localStorageExpire)){
           commit('SET_ACCOUNTINFO', account_info.data)
           resolve(account_info)
         }else{

+ 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);

+ 3 - 0
src/utils/helper.js

@@ -0,0 +1,3 @@
+export function specialFilter(inputStr){
+  return inputStr.replace(/[^(\w\d\s\u4e00-\u9fa5+:、,.!@$#%*={}:,。!()【】《》;¥??’”\-\(\)\[\])]/g,"")
+}

+ 3 - 1
src/utils/validator.js

@@ -15,7 +15,9 @@ Vue.use(VeeValidate, {
   events: 'change',
   dictionary: {
     zh_CN
-  }
+  },
+  errorBagName: 'errorBags',      //解决The computed property "fields" is already defined in data的问题
+  fieldsBagName: 'fieldBags',     //解决The computed property "fields" is already defined in data的问题
 })
 
 const dictionary = {

+ 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>

+ 4 - 2
src/view/system/about.vue

@@ -33,9 +33,11 @@ Vue.use(Cell).use(CellGroup).use(Notify)
 export default {
   name: 'about',
   data () {
+    let verTag = process.env.NODE_ENV === 'development' ? 'beta' : '';
     return {
+      verTag : verTag,
       info: {},
-      app_ver: '8.0',
+      app_ver: '8.0' + verTag,
     }
   },
   created () {
@@ -43,7 +45,7 @@ export default {
     let self = this
     if (window.plus) {
       plus.runtime.getProperty(plus.runtime.appid, function (inf) {
-        self.app_ver = inf.version
+        self.app_ver = inf.version + self.verTag
       })
     }
   },

+ 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>

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