tremble 6 år sedan
förälder
incheckning
b58776825b
84 ändrade filer med 4230 tillägg och 658 borttagningar
  1. 1 1
      build/webpack.dev.conf.js
  2. 6 2
      index.html
  3. 1 0
      package.json
  4. 22 13
      src/App.vue
  5. BIN
      src/assets/images/404.png
  6. BIN
      src/assets/images/btn_leftArrow_hover.png
  7. BIN
      src/assets/images/btn_leftArrow_normal.png
  8. BIN
      src/assets/images/btn_rightArrow_hover.png
  9. BIN
      src/assets/images/btn_rightArrow_normal.png
  10. BIN
      src/assets/images/icon-huiyuan.png
  11. BIN
      src/assets/images/introduce-bg.png
  12. BIN
      src/assets/images/introduce-line.png
  13. BIN
      src/assets/images/logo-en.png
  14. BIN
      src/assets/images/payicon1.png
  15. BIN
      src/assets/images/payicon2.png
  16. BIN
      src/assets/images/payicon3.png
  17. BIN
      src/assets/images/payicon4.png
  18. BIN
      src/assets/images/scene_error.png
  19. 57 0
      src/assets/style/public.scss
  20. 6 4
      src/components/Paging/index.vue
  21. 7 8
      src/components/aboutBg/index.vue
  22. 1 1
      src/components/card/index.vue
  23. 3 3
      src/components/table/index.vue
  24. 4 5
      src/components/table/style.scss
  25. 162 0
      src/components/tablePaging/index.vue
  26. 105 0
      src/components/toast/binding.vue
  27. 277 0
      src/components/toast/capacityRecharge.vue
  28. 104 0
      src/components/toast/editInvoice.vue
  29. 64 0
      src/components/toast/extendtoast.vue
  30. 27 106
      src/components/toast/index.vue
  31. 263 0
      src/components/toast/pointRecharge.vue
  32. 453 0
      src/components/toast/style.scss
  33. 20 0
      src/components/toast/toast.js
  34. 2 2
      src/components/touch/index.vue
  35. 6 2
      src/main.js
  36. 43 0
      src/page/404/index.vue
  37. 13 0
      src/page/about/style.scss
  38. 8 76
      src/page/binocular/index.vue
  39. 0 3
      src/page/binocular/style.scss
  40. 4 3
      src/page/cases/index.vue
  41. 3 5
      src/page/eight/index.vue
  42. 0 3
      src/page/eight/style.scss
  43. 2 3
      src/page/home2/index.vue
  44. 23 1
      src/page/home2/style.scss
  45. 192 0
      src/page/introduce/index.vue
  46. 204 0
      src/page/introduce/style.scss
  47. 121 0
      src/page/introtow/index.vue
  48. 181 0
      src/page/introtow/style.scss
  49. 5 3
      src/page/layout/aside/temp/ctemp/detail.vue
  50. 1 0
      src/page/layout/aside/temp/login.vue
  51. 29 3
      src/page/layout/aside/temp/ltemp/forget.vue
  52. 1 1
      src/page/layout/aside/temp/ltemp/login.vue
  53. 34 1
      src/page/layout/aside/temp/ltemp/register.vue
  54. 7 2
      src/page/layout/header/index.vue
  55. 18 0
      src/page/location/style.scss
  56. 36 24
      src/page/manage/index.vue
  57. 17 31
      src/page/manage/style.scss
  58. 39 13
      src/page/manage/temp/change.vue
  59. 291 144
      src/page/manage/temp/consumption.vue
  60. 341 14
      src/page/manage/temp/device.vue
  61. 41 12
      src/page/manage/temp/iconsumption.js
  62. 44 29
      src/page/manage/temp/information.vue
  63. 1 1
      src/page/manage/temp/order.vue
  64. 35 8
      src/page/manage/temp/scene.vue
  65. 1 1
      src/page/pay/index.vue
  66. 482 0
      src/page/payrecharge/index.vue
  67. 1 1
      src/page/purchase/index.vue
  68. 1 1
      src/page/purchase/style.scss
  69. 1 1
      src/page/purchasetow/index.vue
  70. 1 1
      src/page/purchasetow/style.scss
  71. 20 0
      src/router/index.js
  72. 56 0
      src/store/language/cn/binocular.js
  73. 1 1
      src/store/language/cn/coreTech.js
  74. 11 17
      src/store/language/cn/eight.js
  75. 29 16
      src/store/language/cn/purchase.js
  76. 25 20
      src/store/language/cn/purchasetow.js
  77. 56 0
      src/store/language/en/binocular.js
  78. 20 29
      src/store/language/en/eight.js
  79. 29 16
      src/store/language/en/purchase.js
  80. 25 20
      src/store/language/en/purchasetow.js
  81. 1 1
      src/store/language/home_cn.js
  82. 130 3
      src/store/user.js
  83. 3 3
      src/util/http.js
  84. 12 0
      src/util/index.js

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

@@ -10,7 +10,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin')
 const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
 const portfinder = require('portfinder')
 
-const HOST = '192.168.0.133'
+const HOST = '192.168.0.22'
 const PORT = process.env.PORT && Number(process.env.PORT)
 
 const devWebpackConfig = merge(baseWebpackConfig, {

+ 6 - 2
index.html

@@ -1,11 +1,15 @@
 <!DOCTYPE html>
 <html>
   <head>
-    <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <meta charset="UTF-8">
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <meta http-equiv="Cache-Control" content="max-age=7200" />
-    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
     <meta content="telephone=no" name="format-detection">
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
+    <meta name="apple-mobile-web-app-capable" content="yes">
+    <meta name="browsermode" content="application">
+    <meta name="full-screen" content="yes">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <meta name="description" content="世界上首款消费级3D相机—四维看看(4DKanKan)。技术核心三要素:易操作;自动化;高精度。主要应用领域为数字文博、数字地产、数字电商、数字餐饮、数字家居等。">
     <link rel="shortcut icon" href="//4dkk.4dage.com/FDKKIMG/icon/kankan_icon.ico">

+ 1 - 0
package.json

@@ -16,6 +16,7 @@
   "dependencies": {
     "axios": "^0.18.0",
     "gsap": "^2.1.2",
+    "js-cookie": "^2.2.0",
     "luxy.js": "^0.1.0",
     "three": "^0.102.1",
     "vue": "^2.5.2",

+ 22 - 13
src/App.vue

@@ -39,6 +39,7 @@ export default {
       scale: '',
       isNotChorme: browser.firefox || browser.edge,
       isIE: browser.trident,
+      isPad: browser.iPad,
       gre150: false
     }
   },
@@ -111,24 +112,32 @@ export default {
     }
   },
   mounted () {
+    // this.$store.dispatch('checkToken')
     let reZoom = () => {
-      let zoom = Math.round(devicePixelRatio * 100)
-      let realWidth = document.documentElement.clientWidth || document.body.clientWidth
-      this.scale = (100 / zoom) || 1
-      this.gre150 = zoom > 150
+      if (!this.isPad) {
+        let zoom = Math.round(devicePixelRatio * 100)
+        let realWidth = document.documentElement.clientWidth || document.body.clientWidth
+        this.scale = (100 / zoom) || 1
+        this.gre150 = zoom > 150
 
-      if (zoom !== 100 && this.gre150) {
-        this.$toast.show('warn', `您当前浏览器的缩放比例是${zoom}%,可能会影响某些功能的正常<br/>使用,请尝试调整浏览器比例为100%以获得更佳的浏览体验。`)
-        document.querySelector('html').style.width = realWidth / this.scale + 'px'
-      } else {
-        this.$toast.hideShow()
-        document.querySelector('html').style.width = '100%'
+        if (zoom !== 100 && this.gre150) {
+          this.$toast.show('warn', `您当前浏览器的缩放比例是${zoom}%,可能会影响某些功能的正常<br/>使用,请尝试调整浏览器比例为100%以获得更佳的浏览体验。`)
+          document.querySelector('html').style.width = realWidth / this.scale + 'px'
+          setTimeout(() => {
+            this.$bus.$emit('hadload', true)
+          }, 300)
+        } else {
+          this.$toast.hideShow()
+          document.querySelector('html').style.width = '100%'
+        }
+        this.fixHeight()
       }
-      this.fixHeight()
     }
 
-    window.onload = function () {
-      reZoom()
+    window.onload = () => {
+      if (!this.isPad) {
+        reZoom()
+      }
     }
 
     window.addEventListener('resize', () => {

BIN
src/assets/images/404.png


BIN
src/assets/images/btn_leftArrow_hover.png


BIN
src/assets/images/btn_leftArrow_normal.png


BIN
src/assets/images/btn_rightArrow_hover.png


BIN
src/assets/images/btn_rightArrow_normal.png


BIN
src/assets/images/icon-huiyuan.png


BIN
src/assets/images/introduce-bg.png


BIN
src/assets/images/introduce-line.png


BIN
src/assets/images/logo-en.png


BIN
src/assets/images/payicon1.png


BIN
src/assets/images/payicon2.png


BIN
src/assets/images/payicon3.png


BIN
src/assets/images/payicon4.png


BIN
src/assets/images/scene_error.png


+ 57 - 0
src/assets/style/public.scss

@@ -109,6 +109,55 @@ body{
   display: block;
   clear: both;
 }
+.loading-hover{
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  transform: translate(-50%,-50%);
+  top: 50%;
+  left: 50%;
+  background-color: rgba(0, 0, 0, 0.5);
+  text-align: center;
+}
+
+.loading-hover p{
+ color: #fff;
+ margin-top: 10px;
+}
+
+.loading-hover  .loading-icon{
+  transform: translate(-50%,-50%);
+  top: 50%;
+  left: 50%;
+  position: absolute;
+}
+
+.refreshing-loader{
+  animation: refreshing-loader 1000ms infinite linear;
+  border-radius: 25px;
+  border: 5px solid #fff;
+  border-left-color: transparent;
+  color: transparent;
+  display: inline-block;
+  font-size: 10px;
+  line-height: 1.2;
+  width: 50px;
+  height: 50px;
+  text-indent: 100%;
+}
+
+.refreshing-loader::after{
+  display: block;
+  border: 8px solid transparent;
+  border-top-color: #fff;
+  border-left-color: #fff;
+  content: '';
+  width: 0;
+  height: 0;
+  overflow: hidden;
+  margin-left: -2px;
+  margin-top: 30px;
+}
 
 @keyframes fadeUp {
   from {
@@ -327,4 +376,12 @@ $padding:20px;
   to {
       transform: rotate(1turn)
   }
+}
+@keyframes refreshing-loader {
+  0% {
+    transform: rotate(0deg);
+  }
+  100% {
+    transform: rotate(360deg);
+  }
 }

+ 6 - 4
src/components/Paging/index.vue

@@ -1,8 +1,8 @@
 <template>
   <div class="layout">
     <a @click="clickHandle(index - 1)" ></a>
-    <a
-      v-if="page !== maxPage"
+    <a @click="clickHandle(1)" :class="{active: index === 1}"  v-if="current>=5">1</a><a class="more" @click="clickHandle(current - 3)" v-if="current>=5" >...</a><a
+      v-if="page!==maxPage"
       v-for="page in pages"
       :key="page"
       @click="clickHandle(page)"
@@ -62,7 +62,7 @@ export default {
       default: 10
     },
     length: {
-      default: 4
+      default: 5
     },
     value: {
       default: 1
@@ -84,7 +84,9 @@ export default {
       return val
     },
     pages () {
-      return getPageNumArr(this.length, this.index, this.maxPage)
+      let temp = getPageNumArr(this.length, this.index, this.maxPage)
+
+      return temp
     }
   },
   methods: {

+ 7 - 8
src/components/aboutBg/index.vue

@@ -5,7 +5,6 @@
 </template>
 
 <script>
-// const {THREE, TweenMax, Cubic, TweenLite, TimelineMax} = global
 
 import * as THREE from 'three'
 import {TweenMax, TweenLite, TimelineMax} from 'gsap'
@@ -29,10 +28,10 @@ export default {
       window.addEventListener('scroll', function () {
         sctop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop
         if (sctop > winH / 3) {
-          if (!sctopSw) document.querySelector('#bg_box').style.opacity = 0.5
+          if (!sctopSw && document.querySelector('#bg_box')) document.querySelector('#bg_box').style.opacity = 0.5
           sctopSw = true
         } else {
-          if (sctopSw) document.querySelector('#bg_box').style.opacity = 1
+          if (sctopSw && document.querySelector('#bg_box')) document.querySelector('#bg_box').style.opacity = 1
           sctopSw = false
         }
       })
@@ -70,11 +69,11 @@ export default {
       init3d()
       makeParticles()
       loop_frame()
-      setTimeout(function () {
-        TweenLite.to(document.querySelector('canvas'), 4.5, {
-          opacity: 0.99
-        })
-      }, optime)
+      // setTimeout(function () {
+      //   TweenLite.to(document.querySelector('canvas'), 4.5, {
+      //     opacity: 0.99
+      //   })
+      // }, optime)
     }
 
     var camera,

+ 1 - 1
src/components/card/index.vue

@@ -18,7 +18,7 @@
       </div>
       <div class="u-r">
         <img src="@/assets/images/eye.png" alt>
-        <span>{{data.sceneScheme===4?'Pro':'Lite'}}</span>
+        <span>{{data.sceneScheme>=4?'Pro':'Lite'}}</span>
       </div>
     </div>
     <div class="viewcount">

+ 3 - 3
src/components/table/index.vue

@@ -1,14 +1,14 @@
 <template>
   <div class="table-layout">
     <ul class="t-header">
-      <li v-for="(item,i) in header" :key="i">
+      <li v-for="(item,i) in header" :key="i" :style="{width:item.width?item.width+'px':(100/header.length)+'%'}">
         <slot :data='item' name='header'></slot>
       </li>
     </ul>
     <div class="t-con">
       <ul class="t-item" v-for="(item,i) in data" :key="i">
-        <li v-for="(sub,j) in header" :key='j'>
-          <slot :data='item[sub.key]'  name='item'></slot>
+        <li v-for="(sub,j) in header" :key='j' :style="{width:sub.width?sub.width+'px':(100/header.length)+'%'}">
+          <slot :data='item[sub.key]' :item='item' :canclick='sub.canclick' name='item'></slot>
         </li>
       </ul>
     </div>

+ 4 - 5
src/components/table/style.scss

@@ -1,14 +1,14 @@
 .table-layout{
   width: 100%;
+  color: #777;
+  font-size: 12px;
   .t-header{
     display: flex;
     justify-content: space-around;
     align-items: center;
-    background: #eee;
     width: 100%;
-    padding: 10px 0;
+    padding: 0 0 15px;
     li{
-      flex: 1;
       text-align: center;
       display: inline-block;
     }
@@ -19,9 +19,8 @@
       justify-content: space-around;
       align-items: center;
       width: 100%;
-      padding: 10px 0;
+      padding: 5px 0;
       li{
-        flex: 1;
         text-align: center;
         display: inline-block;
       }

+ 162 - 0
src/components/tablePaging/index.vue

@@ -0,0 +1,162 @@
+<template>
+  <div class="layout">
+    <p class="page-pre" @click="clickHandle(index - 1)" ></p>
+    <div class="page-current">
+      第<input class="input-area"  @keyup.enter='clickHandle(index)' v-model="index" type="text">页
+    </div>
+    <p class="page-total">共 {{maxPage}} 页</p>
+    <p class="page-next" @click="clickHandle(index + 1)"></p>
+  </div>
+</template>
+
+<script>
+/**
+ * 取得页码数组
+ * @param showPageMaxCount 允许显示的页码最大数量
+ * @param pageNow 当前页码
+ * @param pageCount 总页数
+ * @return 页码数组(整数数组)
+ */
+function getPageNumArr (showPageMaxCount, pageNow, pageCount) {
+  let pageNumArr = []
+  let pageNumBegin, pageNumEnd
+
+  if (pageCount <= showPageMaxCount) {
+    pageNumBegin = 1
+    pageNumEnd = pageCount
+  } else {
+    if (pageNow <= Math.floor(showPageMaxCount / 2)) {
+      pageNumBegin = 1
+      pageNumEnd = showPageMaxCount
+    } else if (pageCount - pageNow <= Math.floor(showPageMaxCount / 2)) {
+      pageNumBegin = pageCount - showPageMaxCount
+      pageNumEnd = pageCount
+      pageNumEnd - pageNumBegin >= showPageMaxCount && pageNumBegin++
+    } else {
+      pageNumBegin = Math.ceil(pageNow - showPageMaxCount / 2)
+      pageNumEnd = Math.floor(pageNow + showPageMaxCount / 2)
+      pageNumEnd - pageNumBegin >= showPageMaxCount && pageNumBegin++
+    }
+  }
+  for (let i = pageNumBegin; i <= pageNumEnd; i++) {
+    pageNumArr.push(i)
+  }
+
+  return pageNumArr
+}
+
+export default {
+  props: {
+    current: {
+      default: 1
+    },
+    reindex: {
+      default: 1
+    },
+    total: {
+      default: 10
+    },
+    equable: {
+      default: 10
+    },
+    length: {
+      default: 4
+    },
+    value: {
+      default: 1
+    },
+    color: {
+      default: '#2d2d2d'
+    }
+  },
+  data () {
+    return { index: this.value }
+  },
+  mounted () {
+    this.$emit('maxPage', this.maxPage)
+  },
+  computed: {
+    maxPage () {
+      let val = Math.ceil(this.total / this.equable)
+      this.$emit('maxPage', val)
+      return val
+    },
+    pages () {
+      return getPageNumArr(this.length, this.index, this.maxPage)
+    }
+  },
+  methods: {
+    clickHandle (index) {
+      let numIndex = Number(index)
+      if (numIndex > this.maxPage) {
+        return false
+      }
+      if (numIndex > 0 && numIndex <= this.maxPage) {
+        this.index = numIndex
+      }
+      this.$emit('clickHandle', this.index)
+    }
+  },
+  watch: {
+
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.layout{
+  font-size: 12px;
+  color: #666;
+  margin: 30px auto 0;
+  width: 250px;
+  overflow: hidden;
+  .page-pre{
+    float: left;
+    width: 20px;
+    height: 20px;
+    margin-right: 22px;
+    cursor: pointer;
+    background-image: url(https://4dscene.4dage.com/new4dkk/images/btn_leftArrow_normal.png);
+    background-image: image-set(url(https://4dscene.4dage.com/new4dkk/images/btn_leftArrow_normal.png) 1x);
+    background-repeat: no-repeat;
+    background-position: 0 2px;
+    // &:hover{
+    // background-image: url(https://4dscene.4dage.com/new4dkk/images/btn_leftArrow_hover.png);
+    // background-image: image-set(url(https://4dscene.4dage.com/new4dkk/images/btn_leftArrow_hover.png) 1x);
+    // }
+  }
+  .page-current{
+    float: left;
+    height: 20px;
+    line-height: 20px;
+    margin-right: 20px;
+    .input-area{
+      padding: 0;
+      width: 40px;
+      text-align: center;
+      margin: 0 10px;
+      display: inline-block;
+      line-height:1.2;
+    }
+  }
+  .page-total{
+    float: left;
+    width: 56px;
+    height: 20px;
+    line-height: 20px;
+    text-align: center;
+  }
+  .page-next{
+    float: left;
+    width: 20px;
+    height: 20px;
+    margin-left: 22px;
+    cursor: pointer;
+    background-image: url(https://4dscene.4dage.com/new4dkk/images/btn_rightArrow_normal.png);
+    background-image: image-set(url(https://4dscene.4dage.com/new4dkk/images/btn_rightArrow_normal.png) 1x);
+    background-repeat: no-repeat;
+    background-position: 0 2px;
+  }
+}
+
+</style>

+ 105 - 0
src/components/toast/binding.vue

@@ -0,0 +1,105 @@
+<template>
+  <div
+    class="toast-layout"
+    :style="{background:false?'none':'rgba(0, 0, 0, 0.3)'}"
+    :class="{'toast-active':visible}"
+  >
+    <div class="toast-con bind-con" :style="{minWidth:'705px'}">
+      <div class="t-header ">
+        <span>添加新设备</span>
+        <i class="iconfont icon-cuowu" @click="handleClick"></i>
+      </div>
+      <div class="binding-con" :style="{height:!bindingSuccess?'295px':'200px'}">
+        <div class="binding-body" v-if="!bindingSuccess">
+          <div class="b-input">
+            <input :class="{notbing:hasBind}" v-model="SN" placeholder="请输入产品包装盒上的S/N码" type="text">
+          </div>
+          <div class="bind-error">{{hasBind?errorMsg:''}}</div>
+          <p v-for="(item,i) in binginfo" :key="i">{{item}}</p>
+        </div>
+        <div class="binding-success" v-else>
+          <img src="@/assets/images/icon/success.png" alt="">
+          <p>绑定成功</p>
+          <p>{{successName}}</p>
+        </div>
+      </div>
+
+      <div class="bind-btn" >
+        <span v-if="!bindingSuccess" @click="binding">绑定设备</span>
+        <span v-else @click="bindingSuccess=false">继续绑定</span>
+      </div>
+    </div>
+
+  </div>
+</template>
+
+<script>
+
+let binginfo = [
+  '1、绑定设备后,可进行充值、查看消费记录和解绑等保管操作',
+  '2、同一台设备只能被一个账号绑定,已经被绑定的设备需要解绑才可以被再次绑定',
+  '3、设备被绑定后,设备仍可无需登录个人账号完成上传、编辑和删除场景等操作'
+]
+export default {
+  props: ['visible', 'btype'],
+  data () {
+    return {
+      binginfo,
+      SN: '',
+      hasBind: false,
+      errorMsg: '该序列号已被绑定',
+      bindingSuccess: false,
+      successName: ''
+    }
+  },
+  watch: {
+    SN () {
+      this.hasBind = false
+    }
+  },
+  methods: {
+    handleClick () {
+      this.SN = ''
+      this.$emit('closePoint')
+    },
+    async binding () {
+      if (!this.SN) {
+        this.errorMsg = '序列号不能为空'
+        this.hasBind = true
+        return false
+      }
+      let params = {
+        childName: this.SN,
+        cameraType: this.btype
+      }
+
+      let token = localStorage.getItem('token')
+      let result = await this.$http({
+        method: 'post',
+        data: params,
+        headers: {
+          token
+        },
+        url: '/user/camera/add'
+      })
+      let data = result.data
+      if (data.code === 0) {
+        this.successName = this.SN
+        this.SN = ''
+        this.bindingSuccess = true
+      } else if (data.code === 4010) {
+        this.$toast.show('error', '绑定的相机不存在')
+      } else if (data.code === 6010) {
+        this.hasBind = true
+        this.errorMsg = '该序列号已被绑定'
+      } else {
+        this.$toast.show('error', data.msg)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "./style.scss";
+</style>

+ 277 - 0
src/components/toast/capacityRecharge.vue

@@ -0,0 +1,277 @@
+<template>
+  <div
+    class="toast-layout"
+    :style="{background:false?'none':'rgba(0, 0, 0, 0.3)'}"
+    :class="{'toast-active':visible}"
+  >
+    <div class="toast-con recharge-con" :style="{minWidth:'868px'}">
+      <div class="t-header">
+        <span>容量套餐</span>
+        <i class="iconfont icon-cuowu" @click="handleClick"></i>
+      </div>
+      <div class="pay-con">
+        <div class="device">
+          <div class="attr">开通设备:</div>
+          <div class="val">{{capacitychildName}}</div>
+        </div>
+        <div class="capacity">
+          <div class="attr">选择容量:</div>
+          <div class="val">
+            <div class="tag" v-for="(item,i) in capacityType" :key="i" :class="{'tag-active':activeItem.unit===item.unit}" @click="activeItem=item">
+              <span class="year">{{item.unit}}</span>
+              <span class="price">
+                <i style="font-size:12px">¥</i>{{item.price||''}}
+                <span class="per">元/年</span>
+              </span>
+              <img v-if="activeItem.unit===item.unit" src="@/assets/images/tag-icon.png" alt />
+            </div>
+          </div>
+        </div>
+        <div class="mid">
+          <div class="attr">支付方式:</div>
+          <div class="body">
+            <div
+              class="pay-tag"
+              :class="{'tag-active':paytype==='alipay'}"
+              @click="paytype='alipay'"
+            >
+              <img src="@/assets/images/ali-pay.png" class="t-icon" alt />
+              <span>支付宝</span>
+              <img src="@/assets/images/tag-icon.png" class="t-click" alt />
+            </div>
+            <div
+              class="pay-tag"
+              :class="{'tag-active':paytype==='wechatPay'}"
+              @click="paytype='wechatPay'"
+            >
+              <img src="@/assets/images/wechat-pay.png" class="t-icon" alt />
+              <span>微信支付</span>
+              <img src="@/assets/images/tag-icon.png" class="t-click" alt />
+            </div>
+            <div
+              class="pay-tag paypal-con"
+              :class="{'tag-active':paytype==='paypal'}"
+              @click="paytype='paypal'"
+            >
+              <img src="@/assets/images/paypal.png" class="t-icon" alt />
+              <span>paypal</span>
+              <img src="@/assets/images/tag-icon.png" class="t-click" alt />
+              <form
+                class="form-con"
+                method="post"
+                :action="`api/order/pay/paypal`"
+              >
+                <input v-model="currentId" type="text" name="orderId" />
+                <input v-model="currentType" type="text" name="orderType" />
+                <input type="submit" value="提交" />
+              </form>
+            </div>
+          </div>
+        </div>
+        <div class="validity">
+          <div class="attr">容量期限:</div>
+          <div class="val">
+            <p class="time">{{deadLine}}</p>
+          </div>
+        </div>
+        <div class="amount">
+          <div class="attr">应付金额:</div>
+          <div class="val">
+            <p class="a-price">¥{{activeItem.price}}</p>
+            <img class="price-img" :src="response.src" alt="">
+            <div class="dec">使用<span style="color:#ff0000">{{payZH}}</span>app扫码完成支付</div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+
+let payTypes = {
+  wechatPay: '微信',
+  alipay: '支付宝',
+  paypal: 'paypal'
+}
+
+let PAYSID = {
+  'wechatPay': 0,
+  'alipay': 1,
+  'paypal': 2
+}
+
+let PAYSSTR = {
+  0: 'wechatPay',
+  1: 'alipay',
+  2: 'paypal'
+}
+
+export default {
+  props: ['visible', 'capacityitem', 'capacityid', 'capacitychildName'],
+  computed: {
+    payZH () {
+      return payTypes[this.paytype]
+    }
+  },
+  watch: {
+    visible (newVal) {
+      if (newVal) {
+        this.getPrice()
+      } else {
+        clearInterval(this.t1)
+        this.t1 = null
+      }
+    },
+    activeItem (newVal) {
+      console.log(newVal)
+      this.pay()
+    },
+    paytype () {
+      this.pay()
+    }
+  },
+  data () {
+    return {
+      privilege: 'year',
+      response: '',
+      capacityType: [],
+      activeItem: '',
+      t1: null,
+      paytype: 'wechatPay',
+      total: 0,
+      deadLine: '',
+      currentId: '',
+      currentType: 2,
+      language: localStorage.getItem('language'),
+      token: localStorage.getItem('token'),
+      orderSn: ''
+    }
+  },
+  methods: {
+    handleClick () {
+      this.$emit('closePoint')
+    },
+    inverRequest () {
+      clearInterval(this.t1)
+      this.t1 = null
+      this.t1 = setInterval(() => {
+        this.queryOrderStatus()
+      }, 5000)
+    },
+    async queryOrderStatus () {
+      if (this.t1) {
+        let params = {
+          orderSn: this.orderSn,
+          orderType: 2,
+          payType: PAYSID[this.paytype]
+        }
+        let res = await this.$http
+          .post('/user/order/queryOrderStatus', params, {
+            headers: {
+              token: this.token
+            }
+          })
+        let response = res.data
+        if (response.code === 0 && response.data) {
+          this.t1 = null
+          this.t1 && clearInterval(this.t1)
+          this.$router.replace({
+            name: 'payresult',
+            params: {
+              isSuccess: 'success'
+            }
+          })
+        }
+      }
+    },
+    async pay () {
+      let {unit, skuSn} = this.activeItem
+
+      let params = {
+        cameraId: this.capacityid,
+        payType: PAYSID[this.paytype],
+        unit: unit.substr(1),
+        unitSize: 1,
+        years: 1,
+        skuSn,
+        abroad: this.language === 'en' ? 1 : 0
+      }
+
+      let res = await this.$http
+        .post('user/order/expansionOrder', params, {
+          headers: {
+            token: this.token
+          }
+        })
+
+      let data = res.data
+      if (data.code !== 0) {
+        return this.$toast.show('error', '获取订单信息失败')
+      }
+      let {id, payType, orderSn} = data.data
+      this.currentId = id
+      this.orderSn = orderSn
+      this.getCode(id, payType)
+    },
+    async getCode (id, payType) {
+      if (payType !== 2) {
+        let params = {
+          orderId: id,
+          orderType: 2
+        }
+        let res = await this.$http
+          .post(`/order/pay/${PAYSSTR[payType]}`, params, {
+            headers: {
+              token: this.token
+            }
+          })
+        let response = res.data
+        if (response.code !== 0) {
+          return this.$toast.show('error', '获取支付二维码失败', () => {
+            this.t1 = null
+            this.t1 && clearInterval(this.t1)
+          })
+        }
+        this.response = response.data
+        this.inverRequest()
+      } else {
+        this.$toast.show('warn', '正在跳转至paypal支付链接,请稍等')
+      }
+    },
+    async getPrice () {
+      let params = {
+        childName: this.capacitychildName || ''
+      }
+
+      let res = await this.$http
+        .post('/user/order/getExpansionPrice', params, {
+          headers: {
+            token: this.token
+          }
+        })
+      let data = res.data
+      if (data.code !== 0) {
+        return false
+      }
+      this.capacityType = data.data.skuList
+      this.deadLine = data.data.deadLine
+      this.capacityType.forEach(item => {
+        if (item.unit === this.capacityitem.unit) {
+          this.activeItem = this.capacityitem
+        }
+      })
+    }
+  },
+  beforeDestroy () {
+    clearInterval(this.t1)
+    this.t1 = null
+  },
+  mounted () {
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "./style.scss";
+</style>

+ 104 - 0
src/components/toast/editInvoice.vue

@@ -0,0 +1,104 @@
+<template>
+  <div
+    class="toast-layout"
+    :style="{background:false?'none':'rgba(0, 0, 0, 0.3)'}"
+    :class="{'toast-active':visible}"
+  >
+    <div class="toast-con recharge-con" :style="{minWidth:'868px'}">
+      <div class="t-header">
+        <span>开具发票</span>
+        <i class="iconfont icon-cuowu" @click="handleClick"></i>
+      </div>
+      <div class="invoice-con">
+        <div class="invoice edit-invoice">
+        <div class="select-con">
+          <div :class="{'tag-active':cInvoice==='normal'}" @click="cInvoice='normal'">
+            <span>增值税普通发票</span>
+            <img src="@/assets/images/tag-icon.png" alt>
+          </div>
+          <div :class="{'tag-active':cInvoice==='zengzhi'}" @click="cInvoice='zengzhi'">
+            <span>增值税专用发票</span>
+            <i></i>
+            <img src="@/assets/images/tag-icon.png" alt>
+          </div>
+        </div>
+        <div v-if="cInvoice==='normal'">
+          <div class="input-con">
+            <input type="text" placeholder="请输入发票抬头" v-model="invoice3.title">
+            <input type="text" placeholder="请输入税务登记号(个人用户可不填)" v-model="invoice3.code">
+          </div>
+        </div>
+        <div v-else>
+          <div class="input-con">
+            <input type="text" v-model="invoice3.title" placeholder="请输入发票抬头">
+            <input type="text" v-model="invoice3.code" placeholder="请输入税务登记号(个人用户可不填)">
+          </div>
+          <div class="input-con">
+            <input type="text" v-model="invoice3.organizedAddress" placeholder="注册地址">
+            <input type="text" v-model="invoice3.registerPhone" placeholder="注册电话">
+          </div>
+          <div class="input-con">
+            <input type="text" v-model="invoice3.bankName" placeholder="开户银行">
+            <input type="text" v-model="invoice3.bankAccount" placeholder="银行账户">
+          </div>
+        </div>
+      </div>
+      <div class="address edit-address">
+        <div class="input-con">
+          <input type="text" v-model="editAdd.shipName" :placeholder="address.shipName||'姓名'">
+          <input type="text" v-model="editAdd.shipMobile" :placeholder="address.shipMobile||'电话'">
+        </div>
+        <div class="input-con">
+          <citySelect :areaPath="editAdd.shipAreaPath" @currentVal="getCurrentSelect"/>
+        </div>
+        <div class="input-con address-input">
+          <input
+            type="text"
+            v-model="editAdd.shipAddress"
+            :placeholder="editAdd.shipAddress||'详细地址'"
+          >
+        </div>
+        <div class="btn parmary" @click="saveInvoice">保存</div>
+      </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import citySelect from '@/components/citySelect'
+
+export default {
+  props: ['visible', 'edititem'],
+  components: {
+    citySelect
+  },
+  data () {
+    return {
+      cInvoice: 'normal',
+      invoice3: {},
+      editAdd: {},
+      address: {},
+      tempSelect: ''
+    }
+  },
+  watch: {
+
+  },
+  methods: {
+    handleClick () {
+      this.$emit('closePoint')
+    },
+    saveInvoice () {
+
+    },
+    getCurrentSelect (data) {
+      this.tempSelect = data
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "./style.scss";
+</style>

+ 64 - 0
src/components/toast/extendtoast.vue

@@ -0,0 +1,64 @@
+<template>
+  <div></div>
+</template>
+
+<script>
+import Toast from './index.vue'
+let imgs = {
+  success: require('@/assets/images/icon/success.png'),
+  warn: require('@/assets/images/icon/warn.png'),
+  error: require('@/assets/images/icon/error.png')
+}
+export default {
+  extend: Toast,
+  methods: {
+    showConfirm: (type, msg, callback) => {
+      this.img = imgs[type] || require('@/assets/images/icon/success.png')
+      this.message = msg
+      this.type = type
+      this.visible = true
+      this.toastType = 'comfirm'
+      this.callback = callback || function () {
+      }
+    },
+    showLoading: () => {
+      this.isLoaing = true
+    },
+    show: (type, msg, callback) => {
+      this.img = imgs[type] || require('@/assets/images/icon/success.png')
+      this.message = msg
+      this.type = type
+      this.visible = true
+      this.toastType = 'show'
+      this.callback = callback || function () {
+      }
+    },
+    showCapacityRecharge: (item, childName, id) => {
+      this.capacityvisible = true
+      this.capacityitem = item
+      this.capacitychildName = childName
+      this.capacityid = id
+    },
+    showPointRecharge: (item, childName, id) => {
+      this.ponintVisible = true
+      this.pointitem = item
+      this.pointchildName = childName
+      this.pointid = id
+    },
+    showBinding: val => {
+      this.bindingVisible = true
+      this.bindingType = val
+    },
+    hideLoading: () => {
+      this.isLoaing = false
+    },
+    hideShow: () => {
+      this.visible = false
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 27 - 106
src/components/toast/index.vue

@@ -1,5 +1,9 @@
 <template>
   <div>
+    <pointRecharge :pointid='pointid' :pointitem='pointitem' :pointchildName='pointchildName' :visible='ponintVisible' @closePoint="()=>{ponintVisible = false}"/>
+    <capacityRecharge :capacityid='capacityid' :capacityitem='capacityitem' :capacitychildName='capacitychildName' :visible='capacityvisible' @closePoint="()=>{capacityvisible = false}"/>
+    <editInvoice :edititem=editItem :visible='editVisible' @closePoint="()=>{editVisible = false}"/>
+    <binding :btype="bindingType" :visible='bindingVisible' @closePoint="()=>{bindingVisible = false}"/>
     <div
       class="toast-layout"
       :style="{background:isLoaing?'none':'rgba(0, 0, 0, 0.3)'}"
@@ -46,15 +50,34 @@
 </template>
 
 <script>
+import pointRecharge from './pointRecharge'
+import capacityRecharge from './capacityRecharge'
+import editInvoice from './editInvoice'
+import binding from './binding'
+import { mapState } from 'vuex'
+
 let types = {
   warn: '提示',
   error: '错误',
   success: '成功'
 }
 export default {
+  components: {pointRecharge, binding, capacityRecharge, editInvoice},
   data () {
     return {
       visible: false,
+      bindingType: 1,
+      capacityvisible: false,
+      ponintVisible: false,
+      editVisible: false,
+      bindingVisible: false,
+      editItem: '',
+      capacityid: '',
+      capacityitem: '',
+      capacitychildName: '',
+      pointid: '',
+      pointitem: '',
+      pointchildName: '',
       message: '',
       type: 'warn',
       toastType: 'show',
@@ -64,6 +87,9 @@ export default {
     }
   },
   computed: {
+    ...mapState({
+      info: state => state.user.info
+    }),
     typeTxt () {
       return types[this.type]
     }
@@ -81,110 +107,5 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-$theme-color: #1fe4dc;
-$anima-time:0.2s;
-$anima-delay:0.15s;
-
-.btn {
-  width: 88px;
-  color: #2d2d2d;
-  display: inline-block;
-  font-size: 14px;
-  text-align: center;
-  border-radius: 2px;
-  width: 88px;
-  height: 34px;
-  line-height: 34px;
-  cursor: pointer;
-}
-.primary {
-  background: $theme-color;
-}
-.cancel {
-  background: #e6e6e6;
-  margin-left: 10px;
-}
-.toast-layout {
-  display: none;
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  overflow: hidden;
-  margin: 0;
-  opacity:0;
-  z-index: 88888888;
-  transition: all $anima-time linear;
-  .loading {
-    svg {
-      position: absolute;
-      top: calc(50% - 14px);
-      left: calc(50% - 14px);
-      transform: translate(-50%, -50%);
-      height: 28px;
-      width: 28px;
-      max-height: 28px;
-      max-width: 28px;
-      animation: rotateLoader 1s;
-      animation-iteration-count: infinite;
-    }
-  }
-  .toast-con {
-    position: absolute;
-    padding: 20px 0;
-    top: 40%;
-    left: 50%;
-    transform: translate(-50%, -50%);
-    background: #fff;
-    border-radius: 6px;
-    box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
-    .t-line {
-      width: 100%;
-      background: #e4e4e4;
-      height: 1px;
-      margin: 20px 0;
-    }
-    .top {
-      padding: 0 36px;
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      color: #969696;
-      span {
-        font-size: 16px;
-      }
-      .iconfont {
-        cursor: pointer;
-      }
-    }
-    .detail {
-      padding: 0 36px;
-      img {
-        width: 30px;
-        display: inline-block;
-        vertical-align: middle;
-      }
-      span {
-        margin-left: 10px;
-        font-size: 16px;
-        color: #2d2d2d;
-        display: inline-block;
-        vertical-align: middle;
-      }
-    }
-    .bottom {
-      padding: 0 36px;
-      float: right;
-    }
-    .mid-bottom {
-      float: none;
-      text-align: center;
-    }
-  }
-}
-.toast-active{
-  display: block!important;
-  opacity: 1!important;
-}
+@import './style.scss';
 </style>

+ 263 - 0
src/components/toast/pointRecharge.vue

@@ -0,0 +1,263 @@
+<template>
+  <div
+    class="toast-layout"
+    :style="{background:false?'none':'rgba(0, 0, 0, 0.3)'}"
+    :class="{'toast-active':visible}"
+  >
+    <div class="toast-con recharge-con" :style="{minWidth:'868px'}">
+      <div class="t-header">
+        <span>点数充值</span>
+        <i class="iconfont icon-cuowu" @click="handleClick"></i>
+      </div>
+      <div class="pay-con">
+        <div class="device">
+          <div class="attr">开通设备:</div>
+          <div class="val">{{pointchildName}}</div>
+        </div>
+        <div class="capacity">
+          <div class="attr">选择容量:</div>
+          <div class="val">
+            <div
+              class="tag"
+              v-for="(item,i) in pointType"
+              :key="i"
+              :class="{'tag-active':activeItem.capacity===item.capacity}"
+              @click="activeItem=item"
+            >
+              <span class="year">{{item.capacity}}</span>
+              <span class="price">
+                <i style="font-size:12px">¥</i>{{item.price}}
+                <span class="per">元</span>
+              </span>
+              <img v-if="activeItem.capacity===item.capacity" src="@/assets/images/tag-icon.png" alt />
+            </div>
+          </div>
+        </div>
+        <div class="mid">
+          <div class="attr">支付方式:</div>
+          <div class="body">
+            <div
+              class="pay-tag"
+              :class="{'tag-active':paytype==='alipay'}"
+              @click="paytype='alipay'"
+            >
+              <img src="@/assets/images/ali-pay.png" class="t-icon" alt />
+              <span>支付宝</span>
+              <img src="@/assets/images/tag-icon.png" class="t-click" alt />
+            </div>
+            <div
+              class="pay-tag"
+              :class="{'tag-active':paytype==='wechatPay'}"
+              @click="paytype='wechatPay'"
+            >
+              <img src="@/assets/images/wechat-pay.png" class="t-icon" alt />
+              <span>微信支付</span>
+              <img src="@/assets/images/tag-icon.png" class="t-click" alt />
+            </div>
+            <div
+              class="pay-tag paypal-con"
+              :class="{'tag-active':paytype==='paypal'}"
+              @click="paytype='paypal'"
+            >
+              <img src="@/assets/images/paypal.png" class="t-icon" alt />
+              <span>paypal</span>
+              <img src="@/assets/images/tag-icon.png" class="t-click" alt />
+              <form
+                class="form-con"
+                method="post"
+                :action="`api/order/pay/paypal`"
+              >
+                <input v-model="currentId" type="text" name="orderId" />
+                <input v-model="currentType" type="text" name="orderType" />
+                <input type="submit" value="提交" />
+              </form>
+            </div>
+          </div>
+        </div>
+        <div class="amount">
+          <div class="attr">应付金额:</div>
+          <div class="val">
+            <p class="a-price">¥{{activeItem.price}}</p>
+            <img class="price-img" :src="response.src" alt="">
+            <div class="dec">
+              使用
+              <span style="color:#ff0000">{{payZH}}</span>app扫码完成支付
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+
+let payTypes = {
+  wechatPay: '微信',
+  alipay: '支付宝',
+  paypal: 'paypal'
+}
+
+let PAYSID = {
+  'wechatPay': 0,
+  'alipay': 1,
+  'paypal': 2
+}
+
+let PAYSSTR = {
+  0: 'wechatPay',
+  1: 'alipay',
+  2: 'paypal'
+}
+
+export default {
+  props: ['visible', 'pointitem', 'pointid', 'pointchildName'],
+  computed: {
+    payZH () {
+      return payTypes[this.paytype]
+    }
+  },
+  data () {
+    let pointType = [
+      {
+        capacity: '600点',
+        price: '600'
+      },
+      {
+        capacity: '800点',
+        price: '800'
+      },
+      {
+        capacity: '1000点',
+        price: '1000'
+      }
+    ]
+    return {
+      privilege: 'year',
+      response: '',
+      t1: null,
+      paytype: 'wechatPay',
+      pointType,
+      activeItem: '',
+      currentId: '',
+      currentType: 1,
+      language: localStorage.getItem('language'),
+      token: localStorage.getItem('token')
+    }
+  },
+  watch: {
+    visible (newVal) {
+      if (newVal) {
+        this.pointType.forEach(item => {
+          if (item.capacity === this.pointitem.capacity) {
+            this.activeItem = this.pointitem
+          }
+        })
+        this.pay()
+      } else {
+        clearInterval(this.t1)
+        this.t1 = null
+      }
+    },
+    activeItem () {
+      this.pay()
+    },
+    paytype () {
+      this.pay()
+    }
+  },
+  methods: {
+    handleClick () {
+      this.$emit('closePoint')
+    },
+    inverRequest () {
+      clearInterval(this.t1)
+      this.t1 = null
+      this.t1 = setInterval(() => {
+        this.queryOrderStatus()
+      }, 5000)
+    },
+    async queryOrderStatus () {
+      if (this.t1) {
+        let params = {
+          orderSn: this.orderSn,
+          orderType: 2,
+          payType: PAYSID[this.paytype]
+        }
+        let res = await this.$http
+          .post('/user/order/queryOrderStatus', params, {
+            headers: {
+              token: this.token
+            }
+          })
+        let response = res.data
+        if (response.code === 0 && response.data) {
+          this.t1 = null
+          this.t1 && clearInterval(this.t1)
+          this.$router.replace({
+            name: 'payresult',
+            params: {
+              isSuccess: 'success'
+            }
+          })
+        }
+      }
+    },
+    async pay () {
+      let {price} = this.activeItem
+
+      let params = {
+        cameraId: this.pointid,
+        points: price,
+        payType: PAYSID[this.paytype],
+        abroad: this.language === 'en' ? 1 : 0
+      }
+
+      let res = await this.$http
+        .post('user/order/rechargeOrder', params, {
+          headers: {
+            token: this.token
+          }
+        })
+
+      let data = res.data
+      if (data.code !== 0) {
+        return this.$toast.show('error', `获取订单信息失败,${data.msg}`)
+      }
+      let {id, payType, orderSn} = data.data
+      this.currentId = id
+      this.orderSn = orderSn
+      this.getCode(id, payType)
+    },
+    async getCode (id, payType) {
+      if (payType !== 2) {
+        let params = {
+          orderId: id,
+          orderType: 1
+        }
+        let res = await this.$http
+          .post(`/order/pay/${PAYSSTR[payType]}`, params, {
+            headers: {
+              token: this.token
+            }
+          })
+        let response = res.data
+        if (response.code !== 0) {
+          return this.$toast.show('error', '获取支付二维码失败', () => {
+            this.t1 = null
+            this.t1 && clearInterval(this.t1)
+          })
+        }
+        this.response = response.data
+        this.inverRequest()
+      } else {
+        this.$toast.show('warn', '正在跳转至paypal支付链接,请稍等')
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "./style.scss";
+</style>

+ 453 - 0
src/components/toast/style.scss

@@ -0,0 +1,453 @@
+$theme-color: #1fe4dc;
+$font-color: #2d2d2d;
+$anima-time:0.2s;
+$anima-delay:0.15s;
+$border-color: #e7e7e7;
+
+
+.btn {
+  width: 88px;
+  color: #2d2d2d;
+  display: inline-block;
+  font-size: 14px;
+  text-align: center;
+  border-radius: 2px;
+  width: 88px;
+  height: 34px;
+  line-height: 34px;
+  cursor: pointer;
+}
+.primary {
+  background: $theme-color;
+}
+.cancel {
+  background: #e6e6e6;
+  margin-left: 10px;
+}
+.toast-layout {
+  display: none;
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+  margin: 0;
+  opacity:0;
+  z-index: 88888888;
+  transition: all $anima-time linear;
+  .loading {
+    svg {
+      position: absolute;
+      top: calc(50% - 14px);
+      left: calc(50% - 14px);
+      transform: translate(-50%, -50%);
+      height: 28px;
+      width: 28px;
+      max-height: 28px;
+      max-width: 28px;
+      animation: rotateLoader 1s;
+      animation-iteration-count: infinite;
+    }
+  }
+  .toast-con {
+    position: absolute;
+    padding: 20px 0;
+    top: 40%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    background: #fff;
+    border-radius: 6px;
+    box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
+    .t-line {
+      width: 100%;
+      background: #e4e4e4;
+      height: 1px;
+      margin: 20px 0;
+    }
+    .iconfont {
+      cursor: pointer;
+    }
+    .t-header{
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      color: #969696;
+      background: #f4f4f4;
+      height: 54px;
+      padding: 0 30px;
+    }
+    .pay-con {
+      background: #fff;
+      padding: 24px 30px;
+      
+      .capacity,
+      .device,
+      .mid,
+      .validity,
+      .amount {
+        display: flex;
+        padding-bottom: 32px;
+        .attr {
+          font-size: 14px;
+          color: $font-color;
+        }
+        .val {
+          display: flex;
+          align-items: center;
+          margin-left: 20px;
+          .time{
+            color: #f9082a;
+            font-size: 14px;
+
+          }
+          .a-price{
+            color: #ff0000;
+            font-size: 32px;
+          }
+          .dec{
+            color: #2d2d2d;
+            font-size: 12px;
+            margin-top: 10px;
+          }
+          .tag {
+            height: 100%;
+            font-size: 0;
+            margin-right: 20px;
+            display: flex;
+            align-items: center;
+            border: 1px solid #f4f4f4;
+            position: relative;
+            cursor: pointer;
+            .year {
+              width: 52px;
+              height: 48px;
+              line-height: 48px;
+              text-align: center;
+              display: inline-block;
+              background: #ededed;
+              color: #777777;
+              font-size: 14px;
+              flex-shrink: 0;
+            }
+            .price {
+              background: #fff;
+              height: 48px;
+              width: 134px;
+              line-height: 48px;
+              display: inline-block;
+              font-size: 18px;
+              color: #ff0000;
+              text-align: center;
+              .per {
+                font-size: 12px;
+                color: #777777;
+              }
+            }
+            img {
+              position: absolute;
+              bottom: 0;
+              right: 0;
+              width: 14px;
+            }
+          }
+          .tag-active {
+            border: 1px solid $theme-color;
+            box-sizing: border-box;
+          }
+        }
+        .body {
+          margin-left: 20px;
+          .pay-tag {
+            cursor: pointer;
+            border: 1px solid #e7e7e7;
+            width: 200px;
+            line-height: 36px;
+            height: 36px;
+            margin-bottom: 20px;
+            position: relative;
+            &:last-of-type{
+              margin-bottom: 0;
+            }
+            span {
+              margin-left: 36px;
+              display: inline-block;
+              text-align: center;
+              padding-left: 60px;
+            }
+            img {
+              position: absolute;
+            }
+            .t-icon {
+              width: 36px;
+              height: 36px;
+              padding: 6px;
+              left: 0;
+              border-right: 1px solid #e7e7e7;
+            }
+            .t-click {
+              right: 0;
+              bottom: 0;
+              display: none;
+            }
+          }
+          .paypal-con{
+            position: relative;
+            .form-con{
+              opacity: 0;
+              input[type='text']{
+                width: 1px;
+                height: 1px;
+                position: absolute;
+                top: 0;
+                left: 0;
+              }
+               input[type='submit']{
+                 width: 100%;
+                 position: absolute;
+                 top: 0;
+                 left: 0;
+                 height: 100%;
+               }
+            }
+          }
+          .tag-active {
+            border: 1px solid $theme-color;
+            span {
+              color: #000;
+            }
+            .t-icon {
+              border-right: 1px solid $theme-color;
+            }
+            .t-click {
+              display: inline-block;
+            }
+          }
+        }
+      }
+      .amount{
+        .val{
+          display: block;
+          position: relative;
+          top: -16px;
+          .price-img{
+            width: 180px;
+          }
+        }
+      }
+    }
+    .binding-con{
+      position: relative;
+      height: 295px;
+      border-top: 1px solid #e4e4e4;
+      border-bottom: 1px solid #e4e4e4;
+      .binding-body{
+        position: absolute;
+        top: 32px;
+        left: 50%;
+        transform: translateX(-50%);
+        width: 420px;
+        .b-input{
+          width: 100%;
+          input{
+            width: 100%;
+            color: #969696;
+            height: 40px;
+            padding: 0 20px 0 10px;
+            line-height: 40px;
+            font-size: 14px;
+            border: solid 1px #e7e7e7;
+          }
+          .notbing{
+            border: 1px solid #ff0000;
+          }
+        }
+        .bind-error{
+          color: #ff0000;
+          font-size: 14px;
+          text-align: center;
+          height: 30px;
+          margin-top: 5px;
+        }
+        p{
+          color: $font-color;
+          font-size: 14px;
+          line-height: 2;
+        }
+      }
+      .binding-success{
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%, -50%);
+        width: 420px;
+        text-align: center;
+        img{
+          width: 64px;
+        }
+        p{
+          font-size: 16px;
+          &:first-of-type{
+            margin-bottom: 10px;
+          }
+        }
+      }
+    }
+    .bind-btn{
+      text-align: center;
+      span{
+        display: inline-block;
+        margin: 18px auto;
+        background: $theme-color;
+        width: 100px;
+        height: 34px;
+        line-height: 34px;
+        font-size: 14px;
+        cursor: pointer;
+      }
+    }
+    .invoice-con{
+      background: #fff;
+      padding: 30px;
+      input {
+        appearance: none;
+        line-height: 36px;
+        height: 36px;
+        border: solid 1px $border-color;
+        padding-left: 10px;
+        &:focus {
+          border: solid 1px $theme-color;
+        }
+      }
+      .btn {
+        text-align: center;
+        cursor: pointer;
+      }
+      .parmary {
+        background-color: $theme-color;
+        width: 126px;
+        height: 36px;
+        line-height: 36px;
+        margin-top: 20px;
+      }
+      .choose {
+        background-color: #ddd;
+        color: #fff;
+        width: 100px;
+        line-height: 26px;
+        height: 26px;
+        font-size: 12px;
+        margin: 12px 0 20px;
+      }
+      .edit-invoice {
+        .select-con {
+          div {
+            position: relative;
+            cursor: pointer;
+            width: 200px;
+            line-height: 36px;
+            height: 36px;
+            margin: 10px 25px 10px 0;
+            border: solid 1px $border-color;
+            color: #a0a0a0;
+            padding: 0 10px;
+            display: inline-block;
+            img {
+              display: none;
+              position: absolute;
+              bottom: 0;
+              right: 0;
+            }
+          }
+          .tag-active {
+            border: solid 1px $theme-color;
+            color: #000;
+            img {
+              display: inline-block;
+            }
+          }
+        }
+        .input-con {
+          input {
+            width: 316px;
+            line-height: 36px;
+            height: 36px;
+            margin: 10px 25px 10px 0;
+          }
+        }
+      }
+    }
+    .edit-address {
+      .input-con {
+        input {
+          width: 200px;
+          line-height: 36px;
+          height: 36px;
+          margin: 10px 25px 10px 0;
+        }
+      }
+      .address-input {
+        input {
+          width: 660px;
+        }
+      }
+    }
+    .t-line {
+      width: 100%;
+      background: #e4e4e4;
+      height: 1px;
+      margin: 20px 0;
+    }
+    .top {
+      padding: 0 36px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      color: #969696;
+      span {
+        font-size: 16px;
+      }
+      .iconfont {
+        cursor: pointer;
+      }
+    }
+    .detail {
+      padding: 0 36px;
+      img {
+        width: 30px;
+        display: inline-block;
+        vertical-align: middle;
+      }
+      span {
+        margin-left: 10px;
+        font-size: 16px;
+        color: #2d2d2d;
+        display: inline-block;
+        vertical-align: middle;
+      }
+    }
+    .bottom {
+      padding: 0 36px;
+      float: right;
+    }
+    .mid-bottom {
+      float: none;
+      text-align: center;
+    }
+  }
+  .recharge-con,.bind-con{
+    padding: 0;
+    border-radius: 4px;
+    overflow: hidden;
+    top: 50%;
+  }
+  .bind-con{
+    .t-header{
+      background: #fff;
+    }
+  }
+}
+.toast-active{
+  display: block!important;
+  opacity: 1!important;
+}

+ 20 - 0
src/components/toast/toast.js

@@ -40,6 +40,26 @@ Toast.install = function (Vue) {
       instance.callback = callback || function () {
       }
     },
+    showCapacityRecharge: (item, childName, id) => {
+      instance.capacityvisible = true
+      instance.capacityitem = item
+      instance.capacitychildName = childName
+      instance.capacityid = id
+    },
+    showPointRecharge: (item, childName, id) => {
+      instance.ponintVisible = true
+      instance.pointitem = item
+      instance.pointchildName = childName
+      instance.pointid = id
+    },
+    showBinding: val => {
+      instance.bindingVisible = true
+      instance.bindingType = val
+    },
+    showInvoice: item => {
+      instance.editVisible = true
+      instance.editItem = item
+    },
     hideLoading: () => {
       instance.isLoaing = false
     },

+ 2 - 2
src/components/touch/index.vue

@@ -6,7 +6,7 @@
           width: contentWidth + 'px',
           transform: 'translateX(' + (left + activeLeft) + 'px)'
         }">
-      <div class="slide-item" :style="{width:itemWidth + 'px'}" v-for="(item, i) in slideItems" :key="i">
+      <div class="slide-item" :style="{width:itemWidth || 0 + 'px'}" v-for="(item, i) in slideItems" :key="i">
         <slot :item='item' name="item"></slot>
       </div>
     </div>
@@ -212,7 +212,7 @@ export default {
 }
 
 .slide-item {
-  /* width: 100%; */
+  width: 100%;
   max-width: 100%;
 }
 

+ 6 - 2
src/main.js

@@ -4,6 +4,10 @@ import App from './App'
 import vuex from 'vuex'
 import Toast from '@/components/toast/toast'
 
+// if (!~location.href.indexOf('index.html')) {
+//   location.href = '/index.html'
+// }
+
 // import axios from './util/http.js'
 // import router from './router'
 Vue.prototype.$cdn = 'https://4dscene.4dage.com/new4dkk/'
@@ -17,9 +21,9 @@ let router = require('./router').default
 
 Vue.prototype.$http = axios
 // Vue.prototype.$serverName = 'http://192.168.0.10:8080/'
-Vue.prototype.$serverName = 'http://pro.4dkankan.com/'
+// Vue.prototype.$serverName = 'http://pro.4dkankan.com/'
 
-// Vue.prototype.$serverName = ''
+Vue.prototype.$serverName = ''
 
 Vue.config.productionTip = false
 

+ 43 - 0
src/page/404/index.vue

@@ -0,0 +1,43 @@
+<template>
+  <div class="layout-404">
+    <div class="_404">
+      <img :src="`${$cdn}images/404.png`" alt="">
+      <p>抱歉,您访问的页面出现了错误,请重新加载</p>
+      <div @click="$router.push({name:'home'})">返回首页</div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+
+}
+</script>
+
+<style lang="scss" scoped>
+.layout-404{
+  position: relative;
+  min-height: 90vh;
+  ._404{
+    top: 50%;
+    left: 50%;
+    position: absolute;
+    transform: translate(-50%,-50%);
+    text-align: center;
+    font-size: 16px;
+    color: #2d2d2d;
+    p{
+      margin: 30px 0;
+    }
+    div{
+      border: 1px solid #2d2d2d;
+      border-radius: 8px;
+      width: 120px;
+      line-height: 40px;
+      height: 40px;
+      margin: 0 auto;
+      cursor: pointer;
+    }
+  }
+}
+</style>

+ 13 - 0
src/page/about/style.scss

@@ -243,3 +243,16 @@ $txt_delay: 0.2s;
     }
   }
 }
+
+@media screen and (max-width: 1200px) {
+  .about-layout {
+    .plate01{
+      width: 900px; 
+    }
+    .plate03{
+      width: 900px; 
+      margin: 120px auto!important;
+
+    }
+  }
+}

+ 8 - 76
src/page/binocular/index.vue

@@ -119,24 +119,22 @@
         <img :src="`${$cdn}images/product_img_content_binocular.png`" alt>
         <div class="standard-layout">
           <div class="standard-xinghao">
-            <h3 class="s-title b-label">{{standardGroup.label}}</h3>
-            <div class="s-value b-label">{{standardGroup.name}}</div>
-            <p v-for="(standard,i) in standardGroup.info" :key="i">
-              <span class="s-value b-label">{{standard.label}} :</span>
+            <h3 class="s-title b-label">{{langBinocular.standardGroup.label}}</h3>
+            <div class="s-value b-label">{{langBinocular.standardGroup.name}}</div>
+            <p v-for="(standard,i) in langBinocular.standardGroup.info" :key="i">
+              <span class="s-value b-label">{{standard.label}}:</span>
               <span class="s-value b-label">{{standard.value}}</span>
             </p>
           </div>
           <div class="standard-params">
             <div class="s-params1">
-              <div class="s1-con" v-for="(item,idx) in standardGroup.params1" :key="idx">
+              <div class="s1-con" v-for="(item,idx) in langBinocular.standardGroup.params1" :key="idx">
                 <h3 class="s-title b-label">{{item.label}}</h3>
-                <p class="s-value b-label" v-for="(sub,i) in item.value" :key="i">
-                  {{sub}}
-                </p>
+                <p class="s-value b-label" v-for="(sub,i) in item.value" :key="i">{{sub}}</p>
               </div>
             </div>
             <div class="s-params2">
-              <div class="s2-con" v-for="(item,idx) in standardGroup.params2" :key="idx">
+              <div class="s2-con" v-for="(item,idx) in langBinocular.standardGroup.params2" :key="idx">
                 <h3 class="s-title b-label">{{item.label}}</h3>
                 <p class="s-value b-label" v-for="(sub,i) in item.value" :key="i">
                   {{sub}}
@@ -179,75 +177,9 @@ export default {
       }
     ]
 
-    let standardGroup = {
-      label: '型号',
-      name: '四维看看 Lite',
-      info: [
-        {
-          label: '高度',
-          value: '130mm'
-        },
-        {
-          label: '宽度',
-          value: '47mm'
-        },
-        {
-          label: '厚度',
-          value: '18mm'
-        },
-        {
-          label: '重量',
-          value: '115g'
-        }
-      ],
-      params1: [
-        {
-          label: '材质',
-          value: ['钛金属', '磨砂背']
-        },
-        {
-          label: '摄像头',
-          value: [
-            'f / 2.0 大光圈镜头',
-            '3200万像素SONY sensor',
-            '220°双鱼眼镜头',
-            '9片8组光学镜头',
-            '3K视频录制速度为30fps'
-          ]
-        },
-        {
-          label: '连接',
-          value: ['蓝牙:5.0', 'WiFi:802.11a / b / g / n / ac']
-        },
-        {
-          label: '',
-          value: []
-        }
-      ],
-      params2: [
-        {
-          label: '电池',
-          value: ['3040mAh', '通过USB快速充电']
-        },
-        {
-          label: '存储',
-          value: ['支持128G TF卡', '3K视频 录制120分钟']
-        },
-        {
-          label: '端口',
-          value: ['microUSB', '三脚架固定孔']
-        },
-        {
-          label: '防水防尘',
-          value: ['IP54']
-        }
-      ]
-    }
-
     return {
       showGroup,
-      ismobile: browser.mobile,
-      standardGroup
+      ismobile: browser.mobile
     }
   },
   computed: {

+ 0 - 3
src/page/binocular/style.scss

@@ -575,9 +575,6 @@ $txt_delay: 0.2s;
       .s-value:first-of-type {
         margin-bottom: 13px;
       }
-      .s-value {
-        margin-right: 7px;
-      }
     }
 
     .standard-params {

+ 4 - 3
src/page/cases/index.vue

@@ -102,7 +102,7 @@ export default {
       currentPage: 1,
       sortActive: 1,
       scene: [],
-      isWide: Math.round(devicePixelRatio * 100) === 100 && devicePixelRatio > 1.5 ? window.innerWidth > 1697 : true,
+      isWide: Math.round(devicePixelRatio * 100) === 100 ? window.innerWidth > 1697 : !(Math.round(devicePixelRatio * 100) >= 120),
       selected: '筛选设备',
       caseType: null
     }
@@ -185,7 +185,6 @@ export default {
   },
   // 生命周期 - 挂载完成(可以访问DOM元素)
   mounted () {
-    this.getData()
     document.addEventListener('click', (e) => {
       if (this.$refs.mbMenu) {
         if (!this.$refs.mbMenu.contains(e.target)) {
@@ -194,7 +193,9 @@ export default {
       }
     })
     window.addEventListener('resize', () => {
-      this.isWide = Math.round(devicePixelRatio * 100) === 100 ? window.innerWidth > 1697 : true
+      let DPR = Math.round(devicePixelRatio * 100)
+      let grt120 = DPR >= 120
+      this.isWide = DPR === 100 ? window.innerWidth > 1697 : !grt120
     })
   }
 }

+ 3 - 5
src/page/eight/index.vue

@@ -153,7 +153,7 @@
             <h3 class="s-title b-label">{{langEight.standardGroup.label}}</h3>
             <div class="s-value b-label">{{langEight.standardGroup.name}}</div>
             <p v-for="(standard,i) in langEight.standardGroup.info" :key="i">
-              <span class="s-value b-label">{{standard.label}} :</span>
+              <span class="s-value b-label">{{standard.label}}:</span>
               <span class="s-value b-label">{{standard.value}}</span>
             </p>
           </div>
@@ -161,16 +161,14 @@
             <div class="s-params1">
               <div class="s1-con" v-for="(item,idx) in langEight.standardGroup.params1" :key="idx">
                 <h3 class="s-title b-label">{{item.label}}</h3>
-                <p class="s-value b-label" v-for="(sub,i) in item.value" :key="i">
-                  {{sub}}
+                <p v-html="sub" class="s-value b-label" v-for="(sub,i) in item.value" :key="i">
                 </p>
               </div>
             </div>
             <div class="s-params2">
               <div class="s2-con" v-for="(item,idx) in langEight.standardGroup.params2" :key="idx">
                 <h3 class="s-title b-label">{{item.label}}</h3>
-                <p class="s-value b-label" v-for="(sub,i) in item.value" :key="i">
-                  {{sub}}
+                <p v-html="sub" class="s-value b-label" v-for="(sub,i) in item.value" :key="i">
                 </p>
               </div>
             </div>

+ 0 - 3
src/page/eight/style.scss

@@ -678,9 +678,6 @@ $num_time: 0.6s;
       .s-value:first-of-type {
         margin-bottom: 13px;
       }
-      .s-value {
-        margin-right: 7px;
-      }
     }
 
     .standard-params {

+ 2 - 3
src/page/home2/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="home-layout">
     <div class="plate01">
-      <div class="my-video" :style="{height:isWide?`${innerH - 128}px`:`${innerH - 88}px`}">
+      <div class="my-video">
         <video :src="language==='en'?`${$cdn}video/banner1.mp4`:`${$cdn}video/4dkkPRO_zh.mp4`" autoplay muted loop></video>
       </div>
     </div>
@@ -147,7 +147,6 @@
 <script>
 import slide from '@/components/slide'
 import vcenter from '@/components/vcenter'
-import tabs from '@/components/tabs'
 import number from '@/components/number'
 import { getPosition } from '@/util'
 import {mapState} from 'vuex'
@@ -210,7 +209,7 @@ export default {
   destroyed () {
     window.removeEventListener('scroll', this.sizeHandle)
   },
-  components: {tabs, vcenter, slide, number}
+  components: {vcenter, slide, number}
 }
 </script>
 

+ 23 - 1
src/page/home2/style.scss

@@ -647,4 +647,26 @@
       }
     }
   }
-}
+}
+
+@media screen and (max-width: 1200px) {
+  .home-layout{
+    .plate01 {
+      .my-video{
+        height: auto;
+        video{
+          top: 0;
+        }
+      }
+    }
+    .plate05{
+      .count-group{
+        width: 1024px;
+        margin: 0 auto;
+      }
+      .b-label{
+        margin-bottom: 10px;
+      }
+    }
+  }
+}

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 192 - 0
src/page/introduce/index.vue


+ 204 - 0
src/page/introduce/style.scss

@@ -0,0 +1,204 @@
+.introduce-layout{
+  $font-color:#2d2d2d;
+  $theme-color:#1fe4dc;
+
+  .introduce-bg{
+    background: url('~@/assets/images/person-bg.png') no-repeat top center;
+    background-size: cover;
+    .introduce-con{
+      padding: 55px 0 50px;
+      .info{
+        width: 680px;
+        font-size: 28px;
+        color: #fff;
+      }
+      .capacity{
+        margin-top: 30px;
+        width: 680px;
+        .c-line{
+          width: 100%;
+          margin: 15px 0;
+          height: 8px;
+          background-color: #ccc;
+          .active{
+            background-color: $theme-color;
+            height: 100%;
+          }
+        }
+        .c-dec{
+          font-size: 16px;
+          color: #fff;
+        }
+        .c-detail{
+          color: #fff;
+          display: flex;
+          justify-content: space-between;
+          span{
+            font-size: 14px;
+            color: #cfcfcf;
+            &:last-child{
+              color: $theme-color;
+              cursor: pointer;
+            }
+          }
+        }
+      }
+    }
+    .introduce-con{
+
+    }
+  }
+  .plate02{
+    width: 1200px;
+    margin: 38px auto;
+    .intro-card{
+      width: 870px;
+      margin: 0 auto;
+      text-align: center;
+      color: #fff;
+      position: relative;
+      .intro-txt{
+        position: absolute;
+        right: 0;
+        top: 0;
+        width: 50%;
+        text-align: left;
+        padding: 35px 0 45px;
+        p{
+          font-size: 28px;
+          &:last-of-type{
+            font-size: 14px;
+            color: #969696;
+            margin-top: 22px;
+          }
+        }
+        div{
+          margin-top: 45px;
+          height: 48px;
+          span{
+            display: inline-block;
+            vertical-align: top;
+            font-size: 18px;
+            line-height: 1;
+            i{
+              font-size: 46px;
+              color: #efc574;
+              margin-right: 15px;
+            }
+            &:last-of-type{
+              width: 146px;
+              border-radius: 5px;
+              background: #efc574;
+              color: $font-color;
+              line-height: 48px;
+              height: 48px;
+              display: inline-block;
+              text-align: center;
+              margin-left: 45px;
+              cursor: pointer;
+            }
+          }
+        }
+      }
+      img{
+        box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
+        border-radius: 10px;
+      }
+    }
+    .intro-title{
+      margin: 40px auto 20px;
+      text-align: center;
+      position: relative;
+      p{
+        position: absolute;
+        left: 50%;
+        top: 50%;
+        transform: translate(-50%,-50%);
+        font-size: 28px;
+        color: $font-color;
+      }
+    }
+    .intro-sub{
+      font-size: 14px;
+      color: #969696;
+      text-align: center;
+    }
+    .intro-type{
+      width: 868px;
+      margin: 66px auto;
+      display: flex;
+      justify-content: space-between;
+      li{
+        width: 260px;
+        height: 240px;
+        text-align: center;
+        display: inline-block;
+        box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);
+        border-radius: 4px;
+        .price{
+          font-size: 14px;
+          color: #969696;
+          span{
+            font-size: 24px;
+            color: $theme-color;
+            margin-right: 4px;
+          }
+          i{
+            position: relative;
+            top: -7px;
+            left: -6px;
+            text-decoration:line-through;
+          }     
+        }
+        .btn{
+          cursor: pointer;
+          font-size: 14px;
+          border: 2px solid $theme-color;
+          display: inline-block;
+          width: 146px;
+          border-radius: 8px;
+          line-height: 44px;
+          height: 44px;
+          color: $theme-color;
+        }
+        p{
+          font-size: 36px;
+          color: $font-color;
+          line-height: 1;
+          &:first-of-type{
+            margin: 36px 0; 
+            font-weight: bold;
+          }
+          &:last-of-type{
+            font-size: 14px;
+            min-height: 14px;
+            color: $theme-color;
+            margin: 12px 0;
+          }
+        }
+      }
+    }
+    .qa-con{
+      li{
+        margin-bottom: 30px;
+        &:first-of-type,&:nth-child(2){
+          display: inline-block;
+          width: 40%;
+        }
+        &:nth-child(2){
+          margin-left: 15%;
+        }
+        p{
+          font-size: 14px;
+          color: #555;
+          &:first-of-type{
+            font-size: 24px;
+            color: $font-color;
+            font-weight: bold;
+            margin-bottom: 20px;
+          }
+        }
+      }
+    }
+  }
+}

+ 121 - 0
src/page/introtow/index.vue

@@ -0,0 +1,121 @@
+<template>
+  <div class="introduce-layout">
+    <div class="introduce-bg">
+      <div class="introduce-con" :style="{marginLeft:(split + 37)+'px'}">
+        <div class="info">
+          <p>设备ID:{{detail.childName}}</p>
+        </div>
+        <div class="c-dec">
+          剩余点数:<span>{{detail.balance}}</span>
+        </div>
+        <div class="c-detail">
+          <span>点数构成:{{detail.spaceContent}}</span>
+        </div>
+      </div>
+    </div>
+    <div class="plate02">
+      <div>
+        <div class="intro-title">
+          <img src="@/assets/images/introduce-line.png" alt="">
+          <p>点数充值,记录您的美好空间</p>
+        </div>
+        <p class="intro-sub">购买立即生效,拍摄安心存放</p>
+        <ul class="intro-type">
+          <li v-for="(item,i) in type" :key="i">
+            <p class="point">{{item.capacity}}</p>
+            <p class="price"><i>¥</i><span>{{item.price}}</span></p>
+            <div class="btn" @click="buy(item)">立即购买</div>
+          </li>
+        </ul>
+        <ul class="qa-con">
+          <li v-for="(item,i) in qa" :key="i">
+            <p>{{item.q}}</p>
+            <p v-html="item.a"></p>
+          </li>
+        </ul>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import {mapState} from 'vuex'
+
+export default {
+  data () {
+    let type = [
+      {
+        capacity: '600点',
+        price: '600'
+      },
+      {
+        capacity: '800点',
+        price: '800'
+      },
+      {
+        capacity: '1000点',
+        price: '1000'
+      }
+    ]
+
+    let qa = [
+      {
+        q: '为什么需要点数充值?',
+        a: '当您的基础点数不足99点时,最新拍摄的场景将无法生成,通过购买点数则可以计算存储更多场景。'
+      }, {
+        q: '点数充值之后还可以退款吗?',
+        a: '不可以,因为点数充值之后,相应点数会立即到账生效,所以不接受中途退款,敬请谅解。'
+      }, {
+        q: '删除场景后会返还点数吗?',
+        a: '点数充值没有有效期,所以消费后代表永久记录您的美好空间,删除场景后不会返还。'
+      }, {
+        q: '点数不足还可继续拍摄上传吗?',
+        a: '点数不足时,不影响设备正常的拍摄,但会无法上传计算,这时只能进行删除操作;直到您的点数满足消费,此时您才可以将拍摄的场景上传计算,随之可查看、编辑和分享。'
+      }
+    ]
+    return {
+      type,
+      qa,
+      detail: ''
+    }
+  },
+  computed: {
+    ...mapState({
+      split: state => state.ui.navDivision,
+      info: state => state.user.info,
+      token: state => state.user.token
+    })
+  },
+  mounted () {
+    this.getDetail()
+  },
+  methods: {
+    buy (item) {
+      this.$toast.showPointRecharge(item, this.detail.childName, this.detail.id)
+    },
+    async getDetail () {
+      let {id} = this.$route.params
+      let params = {
+        childName: id
+      }
+      let result = await this.$http({
+        method: 'post',
+        data: params,
+        headers: {
+          token: this.token
+        },
+        url: '/user/camera/detail'
+      })
+      let data = result.data
+      if (data.code !== 0) {
+        return this.$toast.show('error', '获取设备详情失败')
+      }
+      this.detail = data.data
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import './style.scss';
+</style>

+ 181 - 0
src/page/introtow/style.scss

@@ -0,0 +1,181 @@
+.introduce-layout{
+  $font-color:#2d2d2d;
+  $theme-color:#1fe4dc;
+
+  .introduce-bg{
+    background: url('~@/assets/images/person-bg.png') no-repeat top center;
+    background-size: cover;
+    .introduce-con{
+      padding: 55px 0 50px;
+      .info{
+        width: 680px;
+        font-size: 28px;
+        color: #fff;
+      }
+      .c-dec{
+        font-size: 16px;
+        color: #fff;
+        margin: 38px 0;
+        line-height: 1;
+        span{
+          font-size: 28px;
+          color: $theme-color;
+          font-weight: bold;
+          position: relative;
+          top: 1px;
+        }
+      }
+      .c-detail{
+        color: #fff;
+        span{
+          font-size: 14px;
+          color: #cfcfcf;
+        }
+      }
+    }
+  }
+  .plate02{
+    width: 1100px;
+    margin: 70px auto;
+    .intro-card{
+      width: 870px;
+      margin: 0 auto;
+      text-align: center;
+      color: #fff;
+      position: relative;
+      .intro-txt{
+        position: absolute;
+        right: 0;
+        top: 0;
+        width: 50%;
+        text-align: left;
+        padding: 35px 0 45px;
+        p{
+          font-size: 28px;
+          &:last-of-type{
+            font-size: 14px;
+            color: #969696;
+            margin-top: 22px;
+          }
+        }
+        div{
+          margin-top: 45px;
+          height: 48px;
+          span{
+            display: inline-block;
+            vertical-align: top;
+            font-size: 18px;
+            line-height: 1;
+            i{
+              font-size: 46px;
+              color: #efc574;
+              margin-right: 15px;
+            }
+            &:last-of-type{
+              width: 146px;
+              border-radius: 5px;
+              background: #efc574;
+              color: $font-color;
+              line-height: 48px;
+              height: 48px;
+              display: inline-block;
+              text-align: center;
+              margin-left: 45px;
+              cursor: pointer;
+            }
+          }
+        }
+      }
+      img{
+        box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
+        border-radius: 10px;
+      }
+    }
+    .intro-title{
+      margin: 40px auto 20px;
+      text-align: center;
+      position: relative;
+      p{
+        position: absolute;
+        left: 50%;
+        top: 50%;
+        transform: translate(-50%,-50%);
+        font-size: 28px;
+        color: $font-color;
+      }
+    }
+    .intro-sub{
+      font-size: 14px;
+      color: #969696;
+      text-align: center;
+    }
+    .intro-type{
+      width: 868px;
+      margin: 66px auto;
+      display: flex;
+      justify-content: space-between;
+      li{
+        width: 260px;
+        height: 240px;
+        text-align: center;
+        display: inline-block;
+        box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);
+        border-radius: 4px;
+        .point{
+          margin: 30px 0 36px;
+          font-weight: bold;
+          font-size: 36px;
+          color: $font-color;
+          line-height: 1;
+        }
+        .price{
+          font-size: 14px;
+          min-height: 14px;
+          color: $theme-color;
+          line-height: 1;
+          span{
+            font-size: 24px;
+            color: $theme-color;
+            margin-right: 4px;
+          }
+          i{
+            position: relative;
+            top: -1px;
+          }     
+        }
+        .btn{
+          font-size: 14px;
+          border: 2px solid $theme-color;
+          display: inline-block;
+          width: 146px;
+          border-radius: 8px;
+          line-height: 44px;
+          height: 44px;
+          color: $theme-color;
+          margin-top: 36px;
+          cursor: pointer;
+        }
+      }
+    }
+    .qa-con{
+      li{
+        margin-bottom: 30px;
+        display: inline-block;
+        width: 40%;
+        &:nth-child(2n){
+          margin-left: 15%;
+        }
+        p{
+          font-size: 14px;
+          color: #555;
+          &:first-of-type{
+            font-size: 24px;
+            color: $font-color;
+            font-weight: bold;
+            margin-bottom: 20px;
+          }
+        }
+      }
+    }
+  }
+}

+ 5 - 3
src/page/layout/aside/temp/ctemp/detail.vue

@@ -196,7 +196,7 @@ var cloneObj = function (obj) {
     newObj = []
   }
   for (var key in obj) {
-    var val = obj[key]
+    var val = obj[key] || ''
     newObj[key] = typeof val === 'object' ? cloneObj(val) : val
   }
   return newObj
@@ -255,7 +255,8 @@ export default {
       },
       token: state => state.user.token,
       address: state => state.user.address || {},
-      editAdd: state => cloneObj(state.user.address) || {}
+      editAdd: state => cloneObj(state.user.address) || {},
+      language: state => state.language.current
 
     })
   },
@@ -328,7 +329,8 @@ export default {
         goods: this.sku,
         receiver: this.address,
         invoice: invoice,
-        payType: this.paytype
+        payType: this.paytype,
+        abroad: this.language === 'en' ? 1 : 0
       }
       let res = await this.$http
         .post('user/order/placeOrder', params, {

+ 1 - 0
src/page/layout/aside/temp/login.vue

@@ -63,6 +63,7 @@ export default {
   },
   mounted () {
     this.$bus.$on('currentActive', data => {
+      console.log(data)
       this.tabActive = data || 'ilogin'
     })
   }

+ 29 - 3
src/page/layout/aside/temp/ltemp/forget.vue

@@ -49,8 +49,34 @@ export default {
       }
     },
     async submit () {
-      if (!this.password) {
-        return this.$toast.show('warn', '密码格式不正确')
+      let check = value => {
+        for (let i = 0, len = value.length; i < len; i++) {
+          if (!value[i].val) {
+            return this.$toast.show('warn', value[i].name + '不能为空')
+          }
+        }
+        return true
+      }
+      let checkStr = [
+        {
+          name: '手机',
+          val: this.phone
+        },
+        {
+          name: '验证码',
+          val: this.authCode
+        },
+        {
+          name: '密码',
+          val: this.password
+        },
+        {
+          name: '确认密码',
+          val: this.confirmpass
+        }
+      ]
+      if (!check(checkStr)) {
+        return
       }
       let params = {
         password: this.password,
@@ -71,7 +97,7 @@ export default {
         return this.$toast.show('warn', response.msg)
       }
       this.$toast.show('warn', '密码修改成功', () => {
-        this.$emit('currentActive', 'ilogin')
+        this.$bus.$emit('currentActive', 'ilogin')
       })
     }
   }

+ 1 - 1
src/page/layout/aside/temp/ltemp/login.vue

@@ -15,7 +15,7 @@
       </div>
     </div>
     <div class="qrcode">
-      <img v-if="codeImg" :src="`${$serverName}${codeImg}`" alt="">
+      <img v-if="codeImg" :src="codeImg?`${$serverName}${codeImg}`:''" alt="">
       <div class="qrcode-con">
         <img class="scan-img" src="@/assets/images/icon-qrcode.png" alt="">
         <div class="login-dec">打开四维看看app扫一扫登录</div>

+ 34 - 1
src/page/layout/aside/temp/ltemp/register.vue

@@ -46,6 +46,39 @@ export default {
       }
     },
     async submit () {
+      let check = value => {
+        for (let i = 0, len = value.length; i < len; i++) {
+          if (!value[i].val) {
+            return this.$toast.show('warn', value[i].name + '不能为空')
+          }
+        }
+        return true
+      }
+      let checkStr = [
+        {
+          name: '昵称',
+          val: this.nickname
+        },
+        {
+          name: '手机',
+          val: this.phone
+        },
+        {
+          name: '验证码',
+          val: this.authCode
+        },
+        {
+          name: '密码',
+          val: this.password
+        },
+        {
+          name: '确认密码',
+          val: this.confirmPass
+        }
+      ]
+      if (!check(checkStr)) {
+        return
+      }
       let params = {
         password: this.password,
         phoneNum: this.phone,
@@ -64,7 +97,7 @@ export default {
         return this.$toast.show('warn', response.msg)
       }
       this.$toast.show('warn', '注册成功', () => {
-        this.$emit('currentActive', 'ilogin')
+        this.$bus.$emit('currentActive', 'ilogin')
       })
     }
   }

+ 7 - 2
src/page/layout/header/index.vue

@@ -3,7 +3,7 @@
     <div class="logo-layout">
       <router-link :to="{name: 'home'}" class="logo">
         <vcenter>
-          <img :src="`${$cdn}images/logo.png`" alt>
+          <img :src="language === 'en'?`${$cdn}images/logo-en.png`:`${$cdn}images/logo.png`" alt>
         </vcenter>
       </router-link>
     </div>
@@ -134,6 +134,9 @@ export default {
       })
       this.count = count
     }
+    this.$bus.$on('hadload', data => {
+      this.$store.commit('change_nav_division', getPosition(this.$refs.list).x)
+    })
     this.$bus.$on('updateCart', data => {
       this.count = data
     })
@@ -146,7 +149,9 @@ export default {
     })
     this.sizeHandle = () => {
       this.isWide = Math.round(devicePixelRatio * 100) === 100 ? window.innerWidth > 1600 : true
-      this.$store.commit('change_nav_division', getPosition(this.$refs.list).x)
+      this.$nextTick(() => {
+        this.$store.commit('change_nav_division', getPosition(this.$refs.list).x)
+      })
     }
     window.addEventListener('resize', this.sizeHandle)
     setTimeout(this.sizeHandle, 300)

+ 18 - 0
src/page/location/style.scss

@@ -216,4 +216,22 @@ $loca-ani:0.5s;
       }
     }
   }
+}
+
+@media screen and (max-width: 1200px) {
+  .location-layout {
+    .plate03{
+      .info{
+        width: 1024px;
+        .txt{
+          margin-left: 20px;
+        }
+      }
+      .bottom,.top{
+        .intro{
+          margin-left: 30px; 
+        }
+      }
+    }
+  }
 }

+ 36 - 24
src/page/manage/index.vue

@@ -5,21 +5,11 @@
         <div class="info">
         <img class="avatar" :src="info.head" alt>
         <div class="member">
-          <p>尚未开通任何会员</p>
+          <p>{{content.content||'尚未开通任何会员'}}</p>
           <p>{{info.userName}}</p>
         </div>
-        <div class="open-btn">立即开通</div>
-        <!-- <router-link :to="{path:'/capacity'}">去扩容</router-link> -->
-      </div>
-      <div class="capacity">
-        <div class="c-line">
-          <div class="active" :style="{width:'32%'}"></div>
-        </div>
-        <div class="c-detail">
-          <span>已使用:15G / 36G (32%)</span>
-          <span>查看特权介绍</span>
-        </div>
       </div>
+      <div class="open-btn" @click="$router.push({path:'/privilege'})">立即升级</div>
       </div>
     </div>
     <div class="manage-body">
@@ -68,14 +58,14 @@ export default {
         }, {
           name: '我的订单',
           to: {name: 'order'}
+        },
+        {
+          name: '我的设备',
+          to: {name: 'device'}
+        }, {
+          name: '消费记录',
+          to: {name: 'consumption'}
         }
-        // {
-        //   name: '我的设备',
-        //   to: {name: 'device'}
-        // }, {
-        //   name: '消费记录',
-        //   to: {name: 'consumption'}
-        // }
         ]
       },
       // {
@@ -101,13 +91,12 @@ export default {
     ]
     return {
       settings,
-      active: {
-        name: nameArr[this.$route.name],
-        to: {name: this.$route.name}
-      }
+      nameArr,
+      content: ''
     }
   },
   mounted () {
+    // this.getInfo()
   },
   methods: {
     tabHandle (sub) {
@@ -122,13 +111,36 @@ export default {
           this.$router.push(sub.to)
           break
       }
+    },
+    async getInfo () {
+      let res = await this.$http
+        .post('/user/camera/deadline', {}, {
+          headers: {
+            token: this.token
+          }
+        })
+      let data = res.data
+      if (data.code !== 0) {
+        return false
+      }
+      this.content = data.data
     }
   },
   computed: {
     ...mapState({
       split: state => state.ui.navDivision,
+      token: state => state.user.token,
       info: state => state.user.info
-    })
+    }),
+    active: {
+      get () {
+        return {
+          name: this.nameArr[this.$route.name] || '',
+          to: {name: this.$route.name} || ''
+        }
+      },
+      set () {}
+    }
   }
 }
 </script>

+ 17 - 31
src/page/manage/style.scss

@@ -20,48 +20,34 @@
           flex-direction: column;
           justify-content: space-between;
           height: 64px;
-          padding: 6px 14px;
+          padding: 2px 14px;
           p{
+            line-height: 1;
+            color: #cfcfcf;
+            font-size: 16px;
             &:first-child{
-              font-size: 18px;
+              font-size: 28px;
+              color: #fff;
             }
           }
         }
-        .open-btn{
-          position: absolute;
-          right: 0;
-          color: #010101;
-          line-height: 40px;
-          height: 40px;
-          width: 170px;
-          text-align: center;
-          background-color: #1fe4dc;
-          cursor: pointer;
-        }
+        
       }
-      .capacity{
+      .open-btn{
+        color: #010101;
+        line-height: 40px;
+        height: 40px;
         margin-top: 30px;
-        width: 680px;
-        .c-line{
-          width: 100%;
-          height: 8px;
-          background-color: #ccc;
-          .active{
-            background-color: #1fe4dc;
-            height: 100%;
-          }
-        }
-        .c-detail{
-          margin-top: 20px;
-          color: #fff;
-          display: flex;
-          justify-content: space-between;
-        }
+        width: 170px;
+        font-size: 16px;
+        text-align: center;
+        background-color: #1fe4dc;
+        cursor: pointer;
       }
     }
   }
   .manage-body{
-    min-height: 900px;
+    min-height: 550px;
     display: flex;
     .mc-left{
       flex-shrink: 0;

+ 39 - 13
src/page/manage/temp/change.vue

@@ -2,15 +2,15 @@
   <div class="change-layout">
     <div class="change-con">
       <div class="input">
-        <input class="" v-model="phone" type="text" placeholder="手机号码">
+        <input readonly onfocus="this.removeAttribute('readonly')"  autocomplete="off"  oninput="value=value.replace(/[^\d]/g,'')" maxlength='11' v-model="phone" type="text" placeholder="手机号码">
       </div>
       <div class="input yanzhengma">
-        <input class="" v-model="code" type="text" placeholder="验证码">
+        <input readonly onfocus="this.removeAttribute('readonly')"  autocomplete="off" v-model="code" type="text" placeholder="验证码">
         <div v-if="!jishi" @click="getAuthCode" class="code btn parmary">获取验证码</div>
         <div v-else class="code btn parmary">{{interTime}}s后重新发送</div>
       </div>
       <div class="input">
-        <input class="" maxlength="12" v-model="password" type="password" placeholder="新密码">
+        <input readonly onfocus="this.removeAttribute('readonly')"  autocomplete="off" maxlength="12" v-model="password" type="password" placeholder="新密码">
       </div>
       <div @click="submit" class="btn parmary">
         提交
@@ -55,29 +55,55 @@ export default {
         }, 1000)
       }
     },
-    submit () {
-      if (!this.password) {
-        return this.$toast.show('warn', '密码格式不正确')
+    async submit () {
+      let check = value => {
+        for (let i = 0, len = value.length; i < len; i++) {
+          if (!value[i].val) {
+            return this.$toast.show('warn', value[i].name + '不能为空')
+          }
+        }
+        return true
       }
+
+      let checkStr = [
+        {
+          name: '手机号码',
+          val: this.phone
+        },
+        {
+          name: '验证码',
+          val: this.code
+        },
+        {
+          name: '密码',
+          val: this.password
+        }
+      ]
+      if (!check(checkStr)) {
+        return
+      }
+
       let params = {
         password: this.password,
         phoneNum: this.phone,
         msgAuthCode: this.code
       }
-      this.$http({
+
+      let res = await this.$http({
         method: 'post',
         headers: {
           token: this.token
         },
         data: params,
         url: 'user/changePassword'
-      }, res => {
-        let data = res.data
-        if (data.code === 0) {
-          this.$toast.show('success', '密码修改成功,请重新登录')
-          this.$store.commit('logout')
-        }
       })
+      let data = res.data
+      if (data.code === 0) {
+        this.$toast.show('success', '密码修改成功,请重新登录')
+        this.$store.commit('logout')
+      } else {
+        this.$toast.show('warn', `修改失败,${data.msg}`)
+      }
     }
   }
 }

+ 291 - 144
src/page/manage/temp/consumption.vue

@@ -2,39 +2,76 @@
   <div class="consump-layout">
     <div class="c-header">
       <ul class="tab-list">
-        <li :class="{active:i===0}" v-for="(item,i) in tabList" :key="i">
+        <li @click="active = i" :class="{active:i===active}" v-for="(item,i) in tabList" :key="i">
           {{item.name}}
         </li>
       </ul>
-      <div class="tab-select">
+      <div class="tab-select" ref="invoiceMenu" @click="tabActive=!tabActive" :class="{'tab-active':tabActive}">
         全部
         <ul>
           <li>全部</li>
-          <li>子选项</li>
+          <li v-for="(item,i) in cameraList" :key="i">{{item.name}}</li>
         </ul>
       </div>
     </div>
-    <tableList :header='capacity' :data='data' class="table-list" >
+    <div class="invoices" v-if="active===2">
+      <span>设备</span>
+      <div class="tab-select" ref="deviceMenu" @click="deviceActive=!deviceActive" :class="{'tab-active':deviceActive}">
+        全部
+        <ul>
+          <li>全部</li>
+          <li v-for="(item,i) in invoicedevice" @click="selectInId(item)" :key="i" >{{item.childName}}</li>
+        </ul>
+      </div>
+      <span>可开票额度(元){{max}}</span>
+      <div class="btn parmary">开票</div>
+    </div>
+    <tableList :header='tabHeader' :data='data' class="table-list" >
       <div slot-scope="{data}" slot="header">
         {{data.name}}
       </div>
-      <div slot-scope="{data}" slot="item">
-        {{data}}
+      <div slot-scope="{data,canclick,item}" slot="item">
+        <span class="edit" v-if="canclick" @click="showDetail(item)">{{data}}</span>
+        <span v-else>{{data}}</span>
       </div>
     </tableList>
     <div class="paging" v-if="total">
       <vcenter>
-          <Paging @clickHandle="pageChange" :current="currentPage" :total="total" :equable="pageSize" />
+        <Paging @clickHandle="pageChange" :current="currentPage" :total="total" :equable="pageSize" />
       </vcenter>
     </div>
   </div>
 </template>
 
 <script>
+import { mapState } from 'vuex'
+
 import tableList from '@/components/table'
-import {capacity} from './iconsumption'
-import Paging from '@/components/Paging'
+import {capacity, recharge, invoice} from './iconsumption'
+import Paging from '@/components/tablePaging'
 import vcenter from '@/components/vcenter'
+let PAYSSTR = {
+  0: '微信',
+  1: '支付宝',
+  2: 'paypal'
+}
+
+let methodStr = {
+  0: 'getConsumpList',
+  1: 'getChargeList',
+  2: 'getInvoiceList'
+}
+let rechargeType = {
+  0: '系统赠送',
+  '-1': '支出',
+  1: '充值',
+  2: '系统退充值'
+}
+
+let invoceStatusType = {
+  0: '未开票',
+  1: '已开票'
+}
 
 export default {
   components: {
@@ -52,190 +89,300 @@ export default {
         name: '增值发票'
       }
     ]
-    let data = [{
-      orderSn: 'KR180928ac',
-      channel: '官方预售活动赠送',
-      size: '100G',
-      paytype: '支付宝',
-      bill: '9800元',
-      validity: '终生有效',
-      status: '使用中',
-      date: '2018-09-28 16:14:23'
-    }, {
-      orderSn: 'KR180928ac',
-      channel: '官方预售活动赠送',
-      size: '100G',
-      paytype: '支付宝',
-      bill: '9800元',
-      validity: '终生有效',
-      status: '使用中',
-      date: '2018-09-28 16:14:23'
-    }, {
-      orderSn: 'KR180928ac',
-      channel: '官方预售活动赠送',
-      size: '100G',
-      paytype: '支付宝',
-      bill: '9800元',
-      validity: '终生有效',
-      status: '使用中',
-      date: '2018-09-28 16:14:23'
-    }, {
-      orderSn: 'KR180928ac',
-      channel: '官方预售活动赠送',
-      size: '100G',
-      paytype: '支付宝',
-      bill: '9800元',
-      validity: '终生有效',
-      status: '使用中',
-      date: '2018-09-28 16:14:23'
-    }, {
-      orderSn: 'KR180928ac',
-      channel: '官方预售活动赠送',
-      size: '100G',
-      paytype: '支付宝',
-      bill: '9800元',
-      validity: '终生有效',
-      status: '使用中',
-      date: '2018-09-28 16:14:23'
-    }, {
-      orderSn: 'KR180928ac',
-      channel: '官方预售活动赠送',
-      size: '100G',
-      paytype: '支付宝',
-      bill: '9800元',
-      validity: '终生有效',
-      status: '使用中',
-      date: '2018-09-28 16:14:23'
-    }, {
-      orderSn: 'KR180928ac',
-      channel: '官方预售活动赠送',
-      size: '100G',
-      paytype: '支付宝',
-      bill: '9800元',
-      validity: '终生有效',
-      status: '使用中',
-      date: '2018-09-28 16:14:23'
-    } ]
 
+    let cameraList = [
+      {
+        name: '二目充值',
+        id: 0
+      },
+      {
+        name: '八目扩容',
+        id: 4
+      }
+    ]
     return {
-      data,
+      tabHeader: capacity,
+      data: [],
+      cameraList,
       tabList,
-      capacity,
-      total: 10,
+      active: 0,
+      recharge,
+      total: 30,
       pageSize: 10,
-      currentPage: 1
+      currentPage: 1,
+      searchKey: '',
+      tabActive: false,
+      deviceActive: false,
+      max: 0,
+      activeId: ''
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token,
+      myexpansion: state => {
+        let type = Object.prototype.toString.call(state.user.myexpansion)
+        if (type === '[object Object]') {
+          return state.user.myexpansion
+        }
+        let condition = state.user.myexpansion && state.user.myexpansion !== 'null' && type !== '[object Array]'
+        return (condition ? JSON.parse(state.user.myexpansion) : {})
+      },
+      mycharge: state => {
+        let type = Object.prototype.toString.call(state.user.mycharge)
+        if (type === '[object Object]') {
+          return state.user.mycharge
+        }
+        let condition = state.user.mycharge && state.user.mycharge !== 'null' && type !== '[object Array]'
+        return (condition ? JSON.parse(state.user.mycharge) : {})
+      },
+      myinvoicelist: state => {
+        let type = Object.prototype.toString.call(state.user.myinvoicelist)
+        if (type === '[object Object]') {
+          return state.user.myinvoicelist
+        }
+        let condition = state.user.myinvoicelist && state.user.myinvoicelist !== 'null' && type !== '[object Array]'
+        return (condition ? JSON.parse(state.user.myinvoicelist) : {})
+      },
+      invoicedevice: state => {
+        let type = Object.prototype.toString.call(state.user.invoicedevice)
+        if (type === '[object Object]') {
+          return state.user.invoicedevice
+        }
+        let condition = state.user.invoicedevice && state.user.invoicedevice !== 'null'
+        return (condition ? state.user.invoicedevice : [])
+      }
+    })
+  },
+  watch: {
+    currentPage (newVal) {
+      this.getList()
+    },
+    activeId (newVal) {
+      this.getInvoiceMax()
+      if (this.active === 2) {
+        this.getList()
+      }
+    },
+    active (newVal) {
+      switch (newVal) {
+        case 1:
+          this.tabHeader = recharge
+          break
+        case 2:
+          this.getAllDevice()
+          this.tabHeader = invoice
+          break
+        default:
+          this.tabHeader = capacity
+          break
+      }
+      this.currentPage === 1 ? this.getList() : this.currentPage = 1
     }
   },
   methods: {
     pageChange (data) {
       this.currentPage = data
+    },
+    selectInId (item) {
+      this.activeId = item.id
+    },
+    showDetail (item) {
+      this.$toast.showInvoice(item)
+    },
+    getList () {
+      let str = methodStr[this.active]
+      this[str]()
+    },
+    async getAllDevice (searchKey = '') {
+      let params = {
+        cameraType: ''
+      }
+      await this.$store.dispatch('getInvoiceDevice', params)
+    },
+    async getConsumpList (searchKey = '') {
+      let params = {
+        cameraId: searchKey,
+        pageNum: searchKey ? 1 : this.currentPage,
+        pageSize: this.pageSize
+      }
+      await this.$store.dispatch('getUserExpansion', params)
+      this.pageSize = this.myexpansion.pageSize
+      this.total = this.myexpansion.total || 0
+      this.data = this.myexpansion.list
+      this.data.forEach(item => {
+        item['unitSize'] = item['unitSize'] + item['unit']
+        item['channel'] = '扩充容量购买'
+        item['payType'] = PAYSSTR[item['payType']]
+      })
+    },
+    async getInvoiceMax () {
+      let res = await this.$http({
+        method: 'post',
+        data: {
+          cameraId: this.activeId
+        },
+        headers: {
+          token: this.token
+        },
+        url: '/user/invoice/max'
+      })
+
+      let data = res.data
+      if (data.code !== 0) return
+      this.max = data.data.maxInvoice
+    },
+    async getChargeList (searchKey = '') {
+      let params = {
+        cameraId: searchKey,
+        pageNum: searchKey ? 1 : this.currentPage,
+        pageSize: this.pageSize
+      }
+      await this.$store.dispatch('getChargeList', params)
+      this.pageSize = this.mycharge.pageSize
+      this.total = this.mycharge.total || 0
+      this.data = this.mycharge.list
+      this.data.forEach(item => {
+        item['status'] = rechargeType[item['status']]
+      })
+    },
+    async getInvoiceList () {
+      let params = {
+        cameraId: this.activeId,
+        pageNum: this.currentPage,
+        pageSize: this.pageSize
+      }
+      await this.$store.dispatch('getInvoiceList', params)
+      this.pageSize = this.myinvoicelist.pageSize
+      this.total = this.myinvoicelist.total || 0
+      this.data = this.myinvoicelist.list
+      this.data.forEach(item => {
+        item['detail'] = '详细'
+        item['finish'] = invoceStatusType[item['finish']]
+      })
     }
+  },
+  mounted () {
+    this.getList()
+    document.addEventListener('click', (e) => {
+      if (this.$refs.invoiceMenu) {
+        if (!this.$refs.invoiceMenu.contains(e.target)) {
+          this.tabActive = false
+        }
+      }
+      if (this.$refs.deviceMenu) {
+        if (!this.$refs.deviceMenu.contains(e.target)) {
+          this.deviceActive = false
+        }
+      }
+    })
   }
 }
 </script>
 
 <style lang="scss" scoped>
 $theme-color: #1fe4dc;
+$font-color: #2d2d2d;
+$border-color: #d9d9d9;
+.btn {
+    text-align: center;
+    cursor: pointer;
+  }
+  .parmary {
+    background-color: $theme-color;
+    width: 99px;
+    height: 36px;
+    line-height: 36px;
+  }
 .consump-layout{
   margin: 30px 0 30px 40px;
-  width: 90%;
+  padding: 38px 60px 20px 45px;
+  width: 1024px;
+  border: 1px solid $border-color;
   .c-header{
     .tab-list{
       display: inline-block;
       li{
         display: inline-block;
         margin-right: 40px;
+        line-height: 1.5;
         cursor: pointer;
+        font-size: 14px;
       }
       .active{
         color: $theme-color;
-        border-bottom: 2px solid $theme-color;
-        font-weight: bold;
+        border-bottom: 1px solid $theme-color;
       }
     }
+
+  }
+  .invoices{
+    display: flex;
+    align-items: center;
+    margin-top: 38px;
+    span{
+      font-size: 14px;
+      margin-right: 20px;
+    }
     .tab-select{
+      margin-right: 20px;
+    }
+  }
+  .tab-select{
       float: right;
       position: relative;
       width: 200px;
+      height: 28px;
+      line-height: 28px;
       padding-left: 10px;
-      border: 1px solid #ccc;
-      border-radius: 5px;
+      border: 1px solid $border-color;
+      font-size: 14px;
+      color: #969696;
+      cursor: pointer;
+      &::after{
+        position: absolute;
+        right: 10px;
+        top: 50%;
+        transform: translateY(calc(-50% + 3px));
+        content: '';
+        width: 0;
+        height: 0;
+        border: 5px solid;
+        display: inline-block;
+        border-color: #828282 transparent transparent;
+      }
       ul{
         position: absolute;
-        // max-height: 0;
+        max-height: 0;
         left: 0;
-        top: 24px;
+        top: 34px;
         padding-left: 10px;
         background: #fff;
         overflow: hidden;
         width: 100%;
-        box-shadow: 0 0 10px rgba($color: #000000, $alpha: 0.5);
+        transition:all 0.3s ease;
+        box-shadow: 0 0 10px rgba($color: #000000, $alpha: 0.4);
+      }
+    }
+    .tab-active{
+      ul{
+        max-height: 220px;
+        overflow: auto;
       }
     }
-  }
   .table-list{
-    margin-top: 40px;
-  }
-  .paging {
-  // border-left: #e5e5e5 1px solid;
-    height: 100%;
-    margin-bottom: 40px;
-    & /deep/ .layout {
-      text-align: center;
-      margin-top: 10px;
+    margin-top: 38px;
+    div{
+      width: 100%;
     }
-    & /deep/ .layout a:not(:last-child) {
-      margin: 10px 8px;
-      font-size: 16px;
-      display: inline-block;
-      font-weight: 500;
+    .edit{
+      color: $theme-color;
       cursor: pointer;
-      user-select: none;
-      color: #999;
-      position: relative;
-      transition: color 0.3s;
-    }
-    & /deep/ .layout a:last-child {
-      position: relative;
-      top: -5px;
-      display: -ms-inline-flexbox;
-      display: inline-flex;
-      -ms-flex-align: center;
-      align-items: center;
-      height: 22px;
-      padding: 0 9.6px;
-      padding: 0 0.6rem;
-    }
-    & /deep/ .layout a:last-child::before,
-    & /deep/ .layout a:last-child::after {
-      content: "";
-      display: inline-block;
-      will-change: transform;
-      transition: transform 0.3s;
-    }
-
-    & /deep/ .layout a:not(:last-child).active::after,
-    & /deep/ .layout a:not(:last-child).active,
-    & /deep/ .layout a:not(:last-child):hover,
-    & /deep/ .layout a:not(:last-child):hover::after {
-      color: #111111;
-      transform: scaleX(1);
-    }
-
-    & /deep/ .layout a:not(:last-child)::after {
-      content: "";
-      height: 3px;
-      width: 140%;
-      background-color: #111;
-      display: block;
-      margin-left: -20%;
-      margin-top: 3px;
-      transform-origin: 50% 50%;
-      transform: scaleX(0);
-      will-change: transform;
-      transition: transform 0.3s;
     }
   }
+  .paging {
+    height: 100%;
+  }
 }
 
 </style>

+ 341 - 14
src/page/manage/temp/device.vue

@@ -2,32 +2,172 @@
   <div class="device-layout">
     <div class="d-header">
       <ul class="tab-list">
-        <li :class="{active:i===0}" v-for="(item,i) in tabList" :key="i">
+        <li @click="tabActive = item.id" :class="{active:tabActive === item.id}" v-for="(item,i) in tabList" :key="i">
           {{item.name}}
         </li>
       </ul>
       <div class="tab-search">
-        <input type="text">
+        <input v-model="searchKey" @keyup.enter="getList(searchKey)" type="text" placeholder="搜索设备ID">
+        <i class="iconfont icon-sousuo" @click="getList(searchKey)"></i>
       </div>
     </div>
-    <div class="d-con">
-
+    <div class="d-con" v-if="total">
+      <div class="edit-item item" @click="addDevice">
+        <div class="plus-con">
+          <div class="iconplus">
+            <span></span>
+            <span></span>
+          </div>
+          <p>添加新设备</p>
+        </div>
+      </div>
+      <div class="d-item item" v-for="(item,i) in mydevice.list" :key="i">
+        <div class="i-left" :style="{marginTop:tabActive===4?'15px':'25px'}">
+          <template v-if="tabActive===4">
+            <p class="d-id">ID:{{item.childName}}</p>
+            <p class="p-sub">{{item.spaceEndTime||'云存储空间'}}</p>
+            <div class="capacity">
+              <div class="c-line">
+                <div class="active" :style="{width:getBar(item.usedSpace,item.totalSpace)}"></div>
+              </div>
+            </div>
+            <p class="p-sub">{{item.usedSpaceStr}} / {{item.totalSpaceStr}}</p>
+            <div class="d-edit">
+              <span @click="$router.push({path:'/privilege'})">升级</span>
+              <span @click="$router.push({name:'introduce',params:{id:item.childName}})">扩容</span>
+              <span @click="unbind(item)">解绑</span>
+            </div>
+          </template>
+          <template v-else>
+            <p class="d-id">ID:{{item.childName}}</p>
+            <p class="p-sub">剩余点数:{{item.balance}}</p>
+            <div class="d-edit">
+              <span @click="$router.push({name:'introtow',params:{id:item.childName}})">充值</span>
+              <span @click="unbind(item)">解绑</span>
+            </div>
+          </template>
+        </div>
+        <div class="i-right">
+          <img :src="tabActive===4?`${$cdn}images/banner_pro.png`:`${$cdn}images/t_product.png`" alt="">
+          <img v-if="item.spaceEndTime" class="king" :src="`${$cdn}images/icon-huiyuan.png`" alt="">
+        </div>
+      </div>
+    </div>
+    <div class="scene-nothing" v-else>
+      <img src="@/assets/images/nothing.png">
+      <div>居然还没有新时代空间建模神器<br/>赶紧入手吧</div>
+    </div>
+    <div class="paging" v-if="total">
+      <Paging @clickHandle="pageChange" :current="currentPage" :total="total" :equable="pageSize" />
     </div>
   </div>
 </template>
 
 <script>
+import { mapState } from 'vuex'
+import Paging from '@/components/Paging'
+
 export default {
+  components: {Paging},
   data () {
     let tabList = [
       {
-        name: '四维看看Pro'
+        name: '四维看看Pro',
+        id: 4
       }, {
-        name: '四维看看Lite'
+        name: '四维看看Lite',
+        id: 0
       }
     ]
     return {
-      tabList
+      tabList,
+      tabActive: 4,
+      currentPage: 1,
+      total: 0,
+      searchKey: '',
+      pageSize: 8
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token,
+      mydevice: state => {
+        let type = Object.prototype.toString.call(state.user.mydevice)
+        if (type === '[object Object]') {
+          return state.user.mydevice
+        }
+        let condition = state.user.mydevice && state.user.mydevice !== 'null' && type !== '[object Array]'
+        return (condition ? JSON.parse(state.user.mydevice) : {})
+      }
+    })
+  },
+  watch: {
+    currentPage () {
+      this.getList()
+    },
+    tabActive (newVal) {
+      this.currentPage === 1 ? this.getList() : this.currentPage = 1
+    }
+  },
+  mounted () {
+    this.getList()
+  },
+  methods: {
+    getPercent (a, b) {
+      let temp = a / b
+      if (temp < 1) {
+        return '<1'
+      }
+      return Math.round(temp)
+    },
+    getBar (a, b) {
+      let temp = a / b
+      if (temp < 1) {
+        return '1%'
+      }
+      return Math.round(temp) + '%'
+    },
+    async unbind (item) {
+      this.$toast.showConfirm('warn', '确定要解绑当前设备吗?', async () => {
+        let params = {
+          cameraId: item.id
+        }
+        let res = await this.$http({
+          method: 'post',
+          data: params,
+          headers: {
+            token: this.token
+          },
+          url: '/user/unbindCamera'
+        })
+        let data = res.data
+        if (data.code === 0) {
+          return this.$toast.show('warn', '解绑成功', () => {
+            this.getList()
+          })
+        }
+        return this.$toast.show('error', `解绑失败,${data.msg}`)
+      })
+    },
+    pageChange (data) {
+      this.currentPage = data
+    },
+    addDevice () {
+      let val = this.tabActive === 4 ? 1 : 0
+      this.$toast.showBinding(val)
+    },
+    async getList (searchKey = '') {
+      window.scrollTo(0, 0)
+
+      let params = {
+        cameraType: this.tabActive,
+        childName: searchKey,
+        pageNum: searchKey ? 1 : this.currentPage,
+        pageSize: this.pageSize
+      }
+      await this.$store.dispatch('getUserDevice', params)
+      this.pageSize = this.mydevice.pageSize
+      this.total = this.mydevice.total || 0
     }
   }
 }
@@ -35,22 +175,27 @@ export default {
 
 <style lang="scss" scoped>
 $theme-color: #1fe4dc;
+$font-color: #2d2d2d;
 
 .device-layout{
-  margin: 30px 0 30px 40px;
-  width: 90%;
+  margin: 30px 0 30px 0;
+  width: 995px;
+  color: $font-color;
   .d-header{
+    margin-left: 40px;
+    height: 30px;
     .tab-list{
       display: inline-block;
       li{
         display: inline-block;
         margin-right: 40px;
         cursor: pointer;
+        font-size: 14px;
+        line-height: 1.5;
       }
       .active{
         color: $theme-color;
-        border-bottom: 2px solid $theme-color;
-        font-weight: bold;
+        border-bottom: 1px solid $theme-color;
       }
     }
     .tab-search{
@@ -58,15 +203,197 @@ $theme-color: #1fe4dc;
       position: relative;
       width: 200px;
       padding-left: 10px;
+      margin-right: 35px;
       border: 1px solid #ccc;
-      border-radius: 5px;
+      display: flex;
+      .iconfont{
+        width: 28px;
+        height: 28px;
+        padding: 6px;
+        background: #e4e4e4;
+      }
       input{
+        width: 100%;
+        font-size: 14px;
         appearance: none;
-        line-height: 24px;
-        height: 24px;
+        line-height: 28px;
+        height: 28px;
         border: 0;
       }
     }
   }
+  .d-con{
+    margin-left: 40px;
+    display: inline-block;
+    .item{
+      display: inline-block;
+      box-shadow: 0 4px 4px rgba($color: #000000, $alpha: 0.1);
+      position: relative;
+      width: 280px;
+      height: 180px;
+      margin: 36px 36px 0 0;
+    }
+    .edit-item{
+      cursor: pointer;
+      vertical-align: top;
+      .plus-con{
+        position: absolute;
+        text-align: center;
+        transform: translate(-50%,-50%);
+        top: 50%;
+        left: 50%;
+        .iconplus{
+          position: relative;
+          width: 50px;
+          height: 50px;
+          margin: 0 auto;
+          span{
+            position: absolute;
+            transform: translate(-50%,-50%);
+            top: 50%;
+            left: 50%;
+            display: inline-block;
+            width: 50px;
+            height: 6px;
+            background: $font-color;
+            &:last-child{
+              transform: translate(-50%,-50%) rotate(90deg)
+            }
+          }
+        }
+        p{
+          margin-top: 28px;
+        }
+      }
+    }
+    .d-item{
+      padding: 10px 24px 10px 30px;
+      .i-left{
+        display: inline-block;
+        vertical-align: top;
+        width: 145px;
+        margin-top: 25px;
+        .d-id{
+          color: 16px;
+          font-weight: bold;
+          margin-bottom: 5px;
+        }
+        .capacity{
+          margin: 5px 0;
+          .c-line{
+            width: 100%;
+            height: 10px;
+            background-color: #ccc;
+            .active{
+              background-color:$theme-color;
+              height: 100%;
+            }
+          }
+        }
+        .p-sub{
+          color: #969696;
+          font-size: 14px;
+        }
+        .d-edit{
+          margin-top: 10px;
+          font-size: 14px;
+          position: absolute;
+          bottom: 30px;
+          span{
+            cursor: pointer;
+          }
+        }
+      }
+      .i-right{
+        vertical-align: top;
+        float: right;
+        height: 100%;
+        position: relative;
+        img{
+          height:100%;
+        }
+        .king{
+          position: absolute;
+          top: -17px;
+          right: -22px;
+          width: 44px;
+          height: 34px;
+        }
+      }
+    }
+  }
+  .scene-nothing{
+    padding: 42px 0 0 40px;
+    img{
+      padding-bottom: 22px;
+    }
+    div{
+      font-size: 16px;
+      color: #969696;
+      text-align: center;
+      width: 230px;
+    }
+  }
+   .paging {
+    // border-left: #e5e5e5 1px solid;
+    height: 100%;
+    margin: 40px 0;
+    & /deep/ .layout {
+      text-align: left;
+      margin-top: 0;
+      margin-left: 15px;
+    }
+    & /deep/ .layout a:not(:last-child) {
+      margin: 10px 8px;
+      font-size: 16px;
+      display: inline-block;
+      font-weight: 500;
+      cursor: pointer;
+      user-select: none;
+      color: #999;
+      position: relative;
+      transition: color 0.3s;
+    }
+    & /deep/ .layout a:last-child {
+      position: relative;
+      top: -5px;
+      display: -ms-inline-flexbox;
+      display: inline-flex;
+      -ms-flex-align: center;
+      align-items: center;
+      height: 22px;
+      padding: 0 9.6px;
+      padding: 0 0.6rem;
+    }
+    & /deep/ .layout a:last-child::before,
+    & /deep/ .layout a:last-child::after {
+      content: "";
+      display: inline-block;
+      will-change: transform;
+      transition: transform 0.3s;
+    }
+
+    & /deep/ .layout a:not(:last-child).active::after,
+    & /deep/ .layout a:not(:last-child).active,
+    & /deep/ .layout a:not(:last-child):hover,
+    & /deep/ .layout a:not(:last-child):hover::after {
+      color: #111111;
+      transform: scaleX(1);
+    }
+
+    & /deep/ .layout a:not(:last-child)::after {
+      content: "";
+      height: 3px;
+      width: 140%;
+      background-color: #111;
+      display: block;
+      margin-left: -20%;
+      margin-top: 3px;
+      transform-origin: 50% 50%;
+      transform: scaleX(0);
+      will-change: transform;
+      transition: transform 0.3s;
+    }
+  }
 }
 </style>

+ 41 - 12
src/page/manage/temp/iconsumption.js

@@ -1,50 +1,79 @@
 let capacity = [
   {
+    key: 'childName',
+    name: '设备',
+    width: 120
+  }, {
     key: 'orderSn',
-    name: '扩容单号'
+    name: '扩容单号',
+    width: 200
   }, {
     key: 'channel',
     name: '获得渠道'
   }, {
-    key: 'size',
+    key: 'unitSize',
     name: '容量大小'
   }, {
-    key: 'paytype',
+    key: 'payType',
     name: '支付类型'
   }, {
-    key: 'bill',
+    key: 'amount',
     name: '实付金额'
   }, {
-    key: 'validity',
+    key: 'validDate',
     name: '有效期'
   }, {
     key: 'status',
     name: '状态'
   }, {
-    key: 'date',
+    key: 'tradeTime',
     name: '消费时间'
   }
 ]
 
 let recharge = [
   {
-    key: 'rechargeType',
+    key: 'status',
     name: '充值类型'
   }, {
-    key: 'name',
+    key: 'body',
     name: '充值名称'
   }, {
-    key: 'point',
+    key: 'points',
     name: '点数'
   }, {
-    key: 'device',
+    key: 'childName',
     name: '设备'
   }, {
-    key: 'date',
+    key: 'tradeTime',
     name: '消费时间'
   }
 ]
+
+let invoice = [
+  {
+    key: 'createTime',
+    name: '申请时间'
+  }, {
+    key: 'consumeType',
+    name: '发票类型'
+  }, {
+    key: 'title',
+    name: '发票抬头'
+  }, {
+    key: 'money',
+    name: '开票金额'
+  }, {
+    key: 'finish',
+    name: '状态'
+  }, {
+    key: 'detail',
+    name: '操作',
+    canclick: true
+  }
+]
 export {
   capacity,
-  recharge
+  recharge,
+  invoice
 }

+ 44 - 29
src/page/manage/temp/information.vue

@@ -19,10 +19,10 @@
           <p>昵称</p>
           <input
             autofocus
-            v-model="nickName"
+            v-model="editinfo.nickName"
+            placeholder="输入昵称"
             class="nickname"
             type="text"
-            :placeholder="info.nickName"
           >
           <div @click="saveNickName" class="btn parmary">保存</div>
         </div>
@@ -33,7 +33,7 @@
           </div>
           <p class="p-desc">请选择一张新照片进行上传</p>
           <p class="p-desc">支持图片格式为:JPG/PNG</p>
-          <p class="p-desc">推荐分辨率为:512*512px,大小不于1MB</p>
+          <p class="p-desc">推荐分辨率为:512*512px,大小不于1MB</p>
         </div>
       </div>
     </edit>
@@ -132,7 +132,7 @@ var cloneObj = function (obj) {
     newObj = []
   }
   for (var key in obj) {
-    var val = obj[key]
+    var val = obj[key] || ''
     newObj[key] = typeof val === 'object' ? cloneObj(val) : val
   }
   return newObj
@@ -142,6 +142,7 @@ export default {
   computed: {
     ...mapState({
       info: state => state.user.info,
+      editinfo: state => cloneObj(state.user.info),
       token: state => state.user.token,
       invoice2: state => {
         let type = Object.prototype.toString.call(state.user.invoice2)
@@ -185,7 +186,6 @@ export default {
       addressStatus: true,
       invoiceStatus: true,
       cInvoice: 'normal',
-      nickName: '',
       tempSelect: '',
       addre: []
     }
@@ -197,46 +197,55 @@ export default {
     getCurrentSelect (data) {
       this.tempSelect = data
     },
-    saveNickName () {
-      this.$http
-        .post(
-          '/user/updateNickName',
-          { nickName: this.nickName },
-          {
-            headers: {
-              token: this.token
+    async saveNickName () {
+      if (this.editinfo.nickName.trim()) {
+        let res = await this.$http
+          .post(
+            '/user/updateNickName',
+            { nickName: this.editinfo.nickName },
+            {
+              headers: {
+                token: this.token
+              }
             }
-          }
-        )
-        .then(data => {
+          )
+
+        let data = res.data
+        if (data.code === 0) {
           this.infoStatus = true
-          this.info.nickName = data.data.msg
-          this.nickName = ''
-          localStorage.setItem('info', JSON.stringify(this.info))
-        })
+          this.$store.dispatch('getInfo', {url: '/user/getUserInfo', name: 'info'})
+        } else {
+          this.$toast.show('warn', '修改失败')
+        }
+      } else {
+        return this.$toast.show('warn', '昵称不能为空')
+      }
     },
 
     saveInvoice (cInvoice) {
+      let isObject = function (obj) {
+        return JSON.stringify(obj) === '{}' ? '' : obj
+      }
       let params = {}
       let invoiceType = ''
       if (cInvoice === 'normal') {
         invoiceType = 2
         params = {
           invoiceType,
-          title: this.editInvoice2.title,
-          code: this.editInvoice2.code
+          title: isObject(this.editInvoice2.title),
+          code: isObject(this.editInvoice2.code)
         }
       } else {
         let {title, code, organizedAddress, registerPhone, bankName, bankAccount} = this.editInvoice3
         invoiceType = 3
         params = {
-          invoiceType,
-          title,
-          code,
-          organizedAddress,
-          registerPhone,
-          bankName,
-          bankAccount
+          invoiceType: isObject(invoiceType),
+          title: isObject(title),
+          code: isObject(code),
+          organizedAddress: isObject(organizedAddress),
+          registerPhone: isObject(registerPhone),
+          bankName: isObject(bankName),
+          bankAccount: isObject(bankAccount)
         }
       }
       this.$http
@@ -291,6 +300,11 @@ export default {
     },
     update (e) {
       let file = e.target.files[0]
+      let type = file.type.toLowerCase()
+      if (type !== 'image/jpeg' && type !== 'image/png') {
+        return this.$toast.show('warn', '上传的图片类型不正确,请重新上传')
+      }
+
       let token = this.token
       let config = {
         headers: {
@@ -335,6 +349,7 @@ export default {
   $theme-color: #1fe4dc;
   $border-color: #e7e7e7;
   width: 90%;
+  padding-bottom: 100px;
   input {
     appearance: none;
     line-height: 36px;

+ 1 - 1
src/page/manage/temp/order.vue

@@ -243,7 +243,7 @@ $border-color: #e7e7e7;
         align-items: center;
         flex: 5;
         .thumbnail {
-          width: 20px;
+          width: 55px;
           margin-left: 3px;
           margin-right: 60px;
         }

+ 35 - 8
src/page/manage/temp/scene.vue

@@ -2,20 +2,27 @@
   <div class="scene-layout">
     <ul v-if="total">
       <li v-for="(item,index) in myscene.list" :key="index">
-        <a :href="item.webSite" target="_blank">
-          <img :src="item.thumb" alt="">
-        </a>
+        <div @click="(item.status === 1||item.status===-2) && goto(item.webSite)" class="a-tap">
+          <!-- <img :src="item.thumb" alt=""> -->
+          <img :src="getSceneImg(item)" alt="">
+          <div class="loading-hover" v-if="item.status === 0">
+            <div class="loading-icon">
+              <span class="refreshing-loader"></span>
+              <p>模型计算中</p>
+            </div>
+          </div>
+        </div>
         <div class="name">
           <div class="title">{{item.sceneName}}</div>
           <div class="oper">
-            <span>编辑</span> / <span @click="del(item)">删除</span>
+            <span @click="(item.status === 1||item.status===-2) && gotoEdit(item.webSite)">编辑</span> / <span @click="(item.status === 1||item.status===-2) && del(item)">删除</span>
           </div>
         </div>
         <div><span>拍摄日期:</span><span>{{item.createTime}}</span></div>
       </li>
     </ul>
     <div class="scene-nothing" v-else>
-      <img src="@/assets/images/nothing.png" alt="">
+      <img src="@/assets/images/nothing.png">
       <div>暂无任何场景,赶紧去拍摄吧。</div>
     </div>
     <div class="paging" v-if="total">
@@ -58,6 +65,24 @@ export default {
     this.getList()
   },
   methods: {
+    goto (url) {
+      window.open(url.replace('http://', 'https://'), '_blank')
+    },
+    getSceneImg (item) {
+      switch (item.status) {
+        case -1:
+          return this.$cdn + 'images/scene_error.png'
+        default:
+          return item.thumb
+      }
+    },
+    gotoEdit (url) {
+      if (url.indexOf('www') !== -1) {
+        return
+      }
+      let temp = url.replace('http://', 'https://')
+      window.open(temp.replace('show', 'edit'), '_blank')
+    },
     async del (item) {
       this.$toast.showConfirm('warn', '确定要删除当前场景吗?', async () => {
         let params = {
@@ -77,7 +102,7 @@ export default {
             this.getList()
           })
         }
-        return this.$toast.show('error', '删除失败')
+        return this.$toast.show('error', `删除失败,${data.msg}`)
       })
     },
     pageChange (data) {
@@ -111,10 +136,12 @@ export default {
       color: #a0a0a0;
       max-width: 330px;
       font-size: 14px;
-      a{
+      .a-tap{
+        cursor: pointer;
         width: 100%;
         height: 160px;
         display: inline-block;
+        position: relative;
         img{
           width: 100%;
           height: 100%;
@@ -223,7 +250,7 @@ export default {
       li{
         width: 240px;
         margin-right: 20px;
-        a{
+        .a-tap{
           height: 142px;
         }
       }

+ 1 - 1
src/page/pay/index.vue

@@ -57,7 +57,7 @@
       <div class="bottom" v-if="paytype !== 'paypal'">
         <div class="attr">应付金额:</div>
         <div class="price-detail">
-          <dir class="price">¥{{response.price}}</dir>
+          <div class="price">¥{{response.price}}</div>
           <div class="sao">扫码支付</div>
           <img v-if="response.src" :src="`${$serverName}${response.src}`" alt="">
           <div class="dec">使用<span style="color:#ff0000">{{payZH}}</span>app扫码完成支付</div>

+ 482 - 0
src/page/payrecharge/index.vue

@@ -0,0 +1,482 @@
+<template>
+  <div class="pay-layout">
+    <div class="pay-header">
+      <div class="h-left">
+        <img src="@/assets/images/logo-black.png" alt />
+        <span class="h-line"></span>
+        <span>支付中心</span>
+      </div>
+      <div class="h-right">当前账号:{{info.userName}}</div>
+    </div>
+    <div class="pay-con">
+      <div class="pay-left">
+        <div class="device">
+          <div class="attr">开通选择:</div>
+          <div class="val">b0f1ec548965</div>
+        </div>
+        <div class="top">
+          <div class="attr">开通选择:</div>
+          <div class="val">
+            <div class="tag" :class="{'tag-active':privilege==='year'}" @click="privilege='year'">
+              <span class="year">1年</span>
+              <span class="price">
+                <i style="font-size:12px">¥</i>1999
+                <span class="per">166元/月</span>
+              </span>
+              <img v-if="privilege==='year'" src="@/assets/images/tag-icon.png" alt />
+            </div>
+            <div class="tag" :class="{'tag-active':privilege==='mouth'}" @click="privilege='mouth'">
+              <span class="year">1个月</span>
+              <span class="price">
+                <i style="font-size:12px">¥</i>199
+              </span>
+              <img v-if="privilege==='mouth'" src="@/assets/images/tag-icon.png" alt />
+            </div>
+          </div>
+        </div>
+        <div class="mid">
+          <div class="attr">支付方式:</div>
+          <div class="body">
+            <div
+              class="pay-tag"
+              :class="{'tag-active':paytype==='alipay'}"
+              @click="paytype='alipay'"
+            >
+              <img src="@/assets/images/ali-pay.png" class="t-icon" alt />
+              <span>支付宝</span>
+              <img src="@/assets/images/tag-icon.png" class="t-click" alt />
+            </div>
+            <div
+              class="pay-tag"
+              :class="{'tag-active':paytype==='wechatPay'}"
+              @click="paytype='wechatPay'"
+            >
+              <img src="@/assets/images/wechat-pay.png" class="t-icon" alt />
+              <span>微信支付</span>
+              <img src="@/assets/images/tag-icon.png" class="t-click" alt />
+            </div>
+            <div
+              class="pay-tag paypal-con"
+              :class="{'tag-active':paytype==='paypal'}"
+              @click="paytype='paypal'"
+            >
+              <img src="@/assets/images/paypal.png" class="t-icon" alt />
+              <span>paypal</span>
+              <img src="@/assets/images/tag-icon.png" class="t-click" alt />
+              <form
+                class="form-con"
+                :action="`${$serverName}api/order/pay/paypal`"
+                method="post"
+              >
+                <input v-model="$route.params.orderId" type="text" name="orderId" />
+                <input v-model="$route.params.orderType" type="text" name="orderType" />
+                <input type="submit" value="提交" />
+              </form>
+            </div>
+          </div>
+        </div>
+        <div class="bottom" v-if="paytype !== 'paypal'">
+          <div class="attr">应付金额:</div>
+          <div class="price-detail">
+            <div class="price">¥{{response.price}}</div>
+            <div class="sao">扫码支付</div>
+            <img v-if="response.src" :src="`${$serverName}${response.src}`" alt />
+            <div class="dec">
+              使用
+              <span style="color:#ff0000">{{payZH}}</span>app扫码完成支付
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="pay-right">
+        <p class="p-title">商业版特权</p>
+        <ul class="pay-icon">
+          <li v-for="(item,i) in payicon" :key="i">
+            <img :src="item.img" >
+            <p>{{item.name}}</p>
+          </li>
+        </ul>
+        <div class="pay-detail" @click="$router.push({path:'/introduce'})">了解特权详细</div>
+      </div>
+    </div>
+    <div class="pay-bottom">©2019 4dkankan移动开放平台</div>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+let payTypes = {
+  wechatPay: '微信',
+  alipay: '支付宝',
+  paypal: 'paypal'
+}
+let PAYS = {
+  0: 'wechatPay',
+  1: 'alipay',
+  2: 'paypal'
+}
+let PAYSID = {
+  wechatPay: 0,
+  alipay: 1,
+  paypal: 2
+}
+
+export default {
+  data () {
+    let payicon = [{
+      img: require('@/assets/images/payicon1.png'),
+      name: '25G超大云存储'
+    }, {
+      img: require('@/assets/images/payicon2.png'),
+      name: '高速上传通道'
+    }, {
+      img: require('@/assets/images/payicon3.png'),
+      name: '后台编辑功能全开放'
+    }, {
+      img: require('@/assets/images/payicon4.png'),
+      name: '更优惠的扩容价格'
+    }]
+    return {
+      privilege: 'year',
+      response: '',
+      payicon,
+      t1: null,
+      paytype: PAYS[this.$route.params.payType]
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token,
+      info: state => state.user.info
+    }),
+    payZH () {
+      return payTypes[this.paytype]
+    }
+  },
+  watch: {
+    paytype (newVal, oldVal) {
+      this.getCode()
+    }
+  },
+  mounted () {
+    // this.getCode()
+  },
+  methods: {
+    inverRequest () {
+      clearInterval(this.t1)
+      this.t1 = null
+      this.t1 = setInterval(() => {
+        this.queryOrderStatus()
+      }, 5000)
+    },
+    async queryOrderStatus () {
+      if (this.t1) {
+        let { orderSn, orderType } = this.$route.params
+        if (!orderSn) {
+          return this.$toast.show('error', '获取订单信息失败')
+        }
+
+        let params = {
+          orderSn,
+          orderType: Number(orderType),
+          payType: Number(PAYSID[this.paytype])
+        }
+        let res = await this.$http.post(
+          '/user/order/queryOrderStatus',
+          params,
+          {
+            headers: {
+              token: this.token
+            }
+          }
+        )
+        let response = res.data
+        if (response.code === 0 && response.data) {
+          this.t1 = null
+          this.t1 && clearInterval(this.t1)
+          this.$router.replace({
+            name: 'payresult',
+            params: {
+              isSuccess: 'success'
+            }
+          })
+        }
+      }
+    },
+    async getCode () {
+      let { orderId, orderType } = this.$route.params
+      if (!orderId || (!orderType && orderType !== 0)) {
+        return this.$toast.show('error', '获取订单信息失败')
+      }
+      if (this.paytype !== 'paypal') {
+        let params = {
+          orderId: orderId,
+          orderType: Number(orderType)
+        }
+        let res = await this.$http.post(`/order/pay/${this.paytype}`, params, {
+          headers: {
+            token: this.token
+          }
+        })
+        let response = res.data
+        if (response.code !== 0) {
+          return this.$toast.show('error', '获取支付二维码失败', () => {
+            this.t1 = null
+            this.t1 && clearInterval(this.t1)
+          })
+        }
+        this.response = response.data
+        this.inverRequest()
+      } else {
+        document.getElementById('formid').submit()
+        this.$toast.show('warn', '正在跳转至paypal支付链接,请稍等')
+      }
+    }
+  },
+  beforeDestroy () {
+    clearInterval(this.t1)
+    this.t1 = null
+  }
+}
+</script>
+<style lang="scss" scoped>
+$theme-color: #1fe4dc;
+
+.pay-layout {
+  width: 1030px;
+  min-height: 74vh;
+  margin: 25px auto;
+  .pay-header {
+    width: 100%;
+    margin-bottom: 50px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    .h-left {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      .h-line {
+        width: 1px;
+        height: 20px;
+        background: #000;
+        margin: 0 10px;
+        display: inline-block;
+      }
+      span {
+        font-size: 20px;
+        color: #2d2d2d;
+      }
+    }
+    .h-right {
+      font-size: 14px;
+      color: #2d2d2d;
+    }
+  }
+  .pay-con {
+    background: #f4f4f4;
+    padding: 40px;
+    display: flex;
+    justify-content: space-between;
+    .pay-left {
+      .top,
+      .mid,
+      .device,
+      .bottom {
+        display: flex;
+        margin-bottom: 50px;
+        .attr {
+          font-size: 14px;
+          color: #2d2d2d;
+        }
+
+        .val {
+          display: flex;
+          align-items: center;
+          margin-left: 20px;
+          .tag {
+            height: 100%;
+            font-size: 0;
+            margin-right: 50px;
+            display: flex;
+            align-items: center;
+            border: 1px solid #f4f4f4;
+            position: relative;
+            .year {
+              width: 52px;
+              height: 48px;
+              line-height: 48px;
+              text-align: center;
+              display: inline-block;
+              background: #ededed;
+              color: #777777;
+              font-size: 14px;
+              flex-shrink: 0;
+            }
+            .price {
+              background: #fff;
+              height: 48px;
+              width: 160px;
+              line-height: 48px;
+              display: inline-block;
+              font-size: 18px;
+              color: #ff0000;
+              text-align: center;
+              .per {
+                font-size: 12px;
+                margin-left: 20px;
+                color: #777777;
+              }
+            }
+            img {
+              position: absolute;
+              bottom: 0;
+              right: 0;
+              width: 14px;
+            }
+          }
+          .tag-active {
+            border: 1px solid $theme-color;
+            box-sizing: border-box;
+          }
+        }
+        .body {
+          margin-left: 20px;
+          .pay-tag {
+            cursor: pointer;
+            border: 1px solid #e7e7e7;
+            width: 200px;
+            line-height: 36px;
+            height: 36px;
+            margin-bottom: 20px;
+            position: relative;
+            &:last-of-type {
+              margin-bottom: 0;
+            }
+            span {
+              margin-left: 36px;
+              display: inline-block;
+              text-align: center;
+              padding-left: 60px;
+            }
+            img {
+              position: absolute;
+            }
+            .t-icon {
+              width: 36px;
+              height: 36px;
+              padding: 6px;
+              left: 0;
+              border-right: 1px solid #e7e7e7;
+            }
+            .t-click {
+              right: 0;
+              bottom: 0;
+              display: none;
+            }
+          }
+          .paypal-con {
+            position: relative;
+            .form-con {
+              opacity: 0;
+              input[type="text"] {
+                width: 1px;
+                height: 1px;
+                position: absolute;
+                top: 0;
+                left: 0;
+              }
+              input[type="submit"] {
+                width: 100%;
+                position: absolute;
+                top: 0;
+                left: 0;
+                height: 100%;
+              }
+            }
+          }
+          .tag-active {
+            border: 1px solid $theme-color;
+            span {
+              color: #000;
+            }
+            .t-icon {
+              border-right: 1px solid $theme-color;
+            }
+            .t-click {
+              display: inline-block;
+            }
+          }
+        }
+        .price-detail {
+          margin-left: 6px;
+          text-align: center;
+          position: relative;
+          width: 160px;
+          top: -15px;
+          .price {
+            font-size: 30px;
+            color: #ff0000;
+            margin: 0 0 0 8px;
+            text-align: left;
+            padding: 0;
+            margin-bottom: 40px;
+          }
+          .sao {
+            font-size: 14px;
+            color: #2d2d2d;
+            margin-bottom: 5px;
+          }
+          .dec {
+            color: #2d2d2d;
+            font-size: 12px;
+            margin-top: 10px;
+          }
+          img {
+            width: 130px;
+            height: 130px;
+          }
+        }
+      }
+      .bottom {
+        margin-bottom: 0;
+      }
+    }
+    .pay-right {
+      text-align: center;
+      border-left: 1px solid #e5e5e5;
+      padding-left: 28px;
+      .p-title{
+        font-size: 20px;
+        color: #777777;
+      }
+      .pay-icon{
+        margin-top: 20px;
+        img{
+          margin: 15px 0;
+        }
+        p{
+          color: #969696;
+          font-size: 14px;
+        }
+      }
+      .pay-detail{
+        height: 28px;
+        margin: 20px 0;
+        cursor: pointer;
+        line-height: 28px;
+        font-size: 14px;
+        color: #777777;
+        width: 128px;
+        border: 1px solid #e5e5e5;
+      }
+    }
+  }
+  .pay-bottom {
+    color: #969696;
+    font-size: 12px;
+    text-align: center;
+    margin-top: 20px;
+  }
+}
+</style>

+ 1 - 1
src/page/purchase/index.vue

@@ -57,7 +57,7 @@
         </div>
       </div>
     </div>
-    <div class="plate02" ref="jsgg" :style="{marginLeft:split + 'px'}">
+    <div class="plate02" ref="jsgg">
       <div class="b-title">{{langPurchase.guige.name}}</div>
       <div class="params-con">
         <div class="params-item" v-for="(item,index) in langPurchase.guige.arr" :key="index">

+ 1 - 1
src/page/purchase/style.scss

@@ -166,7 +166,7 @@
 
 .plate02{
   width: 845px;
-  margin-left: 600px;
+  margin: 0 auto;
   padding: 155px 0;
   text-align: center;
   .b-title{

+ 1 - 1
src/page/purchasetow/index.vue

@@ -57,7 +57,7 @@
         </div>
       </div>
     </div>
-    <div class="plate02" ref="jsgg" :style="{marginLeft:split + 'px'}">
+    <div class="plate02" ref="jsgg">
       <div class="b-title">{{langPurchase.guige.name}}</div>
       <div class="params-con">
         <div class="params-item" v-for="(item,index) in langPurchase.guige.arr" :key="index">

+ 1 - 1
src/page/purchasetow/style.scss

@@ -166,7 +166,7 @@
 
 .plate02{
   width: 845px;
-  margin-left: 600px;
+  margin: 0 auto;
   padding: 155px 0;
   text-align: center;
   .b-title{

+ 20 - 0
src/router/index.js

@@ -26,6 +26,11 @@ let router = new Router({
       component: resolve => require(['@/page/pay'], resolve)
     },
     {
+      path: '/payrecharge',
+      name: 'payrecharge',
+      component: resolve => require(['@/page/payrecharge'], resolve)
+    },
+    {
       path: '/payresult/:isSuccess',
       name: 'payresult',
       component: resolve => require(['@/page/payresult'], resolve)
@@ -61,6 +66,11 @@ let router = new Router({
       component: resolve => require(['@/page/purchase'], resolve)
     },
     {
+      path: '/404',
+      name: '404',
+      component: resolve => require(['@/page/404'], resolve)
+    },
+    {
       path: '/purchasetow',
       name: 'purchasetow',
       component: resolve => require(['@/page/purchasetow'], resolve)
@@ -71,6 +81,16 @@ let router = new Router({
       component: resolve => require(['@/page/privilege'], resolve)
     },
     {
+      path: '/introduce/:id',
+      name: 'introduce',
+      component: resolve => require(['@/page/introduce'], resolve)
+    },
+    {
+      path: '/introtow/:id',
+      name: 'introtow',
+      component: resolve => require(['@/page/introtow'], resolve)
+    },
+    {
       path: '/',
       name: 'manage',
       component: resolve => require(['@/page/manage'], resolve),

+ 56 - 0
src/store/language/cn/binocular.js

@@ -75,5 +75,61 @@ export default{
   },
   parmas: {
     name: '四维看看 Lite 详细参数'
+  },
+  standardGroup: {
+    label: '型号',
+    name: '四维看看 Lite',
+    info: [
+      {
+        label: '高度',
+        value: '130mm'
+      },
+      {
+        label: '宽度',
+        value: '47mm'
+      },
+      {
+        label: '厚度',
+        value: '18mm'
+      },
+      {
+        label: '重量',
+        value: '115g'
+      }
+    ],
+    params1: [
+      {
+        label: '材质',
+        value: ['钛金属', '磨砂背']
+      },
+      {
+        label: '摄像头',
+        value: [
+          'f / 2.0 大光圈镜头',
+          '3200万像素SONY sensor',
+          '220°双鱼眼镜头',
+          '9片8组光学镜头',
+          '3K视频录制速度为30fps'
+        ]
+      },
+      {
+        label: '连接',
+        value: ['蓝牙:5.0', 'WiFi:802.11a / b / g / n / ac']
+      }
+    ],
+    params2: [
+      {
+        label: '电池',
+        value: ['2000mAh', '通过USB快速充电']
+      },
+      {
+        label: '存储',
+        value: ['支持128G TF卡', '3K视频 录制120分钟']
+      },
+      {
+        label: '端口',
+        value: ['microUSB', '三脚架固定孔']
+      }
+    ]
   }
 }

+ 1 - 1
src/store/language/cn/coreTech.js

@@ -67,7 +67,7 @@ export default{
           icon: {
             backgroundImage: `url(${require('@/assets/images/img_core_app03.png')})`
           },
-          sub: '人工智能算法与环闭合配合运作,使相机几何校准更加快速稳定'
+          sub: '人工智能算法使相机几何校准更加快速稳定'
         }
       ]
     }

+ 11 - 17
src/store/language/cn/eight.js

@@ -131,39 +131,33 @@ export default{
     name: '四维看看 Pro',
     info: [{
       label: '高度',
-      value: '220.7毫米'
+      value: '220.7mm'
     }, {
       label: '宽度',
-      value: '78.2毫米'
+      value: '78.2mm'
     }, {
       label: '厚度',
-      value: '78.2毫米'
+      value: '78.2mm'
     }],
     params1: [{
       label: '镜头',
       value: ['类型:200°鱼眼镜头', '孔径:f/2.0', '数量:8个', '分辨率:4608*3456像素(每个);12288*6144像素(合计)']
     }, {
       label: '传感器',
-      value: ['f / 2.0 大光圈镜头', '3200万像素SONY sensor', '220°双鱼眼镜头', '9片8组光学镜头', '3K视频录制速度为30fps']
+      value: ['范围:1/2.3英寸', '数量:8个']
     }, {
-      label: '连接',
-      value: ['蓝牙:5.0', 'WiFi:802.11a / b / g / n / ac']
-    }, {
-      label: '',
-      value: []
+      label: '存储内存',
+      value: ['16GB']
     }],
     params2: [{
       label: '电池',
-      value: ['3040mAh', '通过USB快速充电']
-    }, {
-      label: '存储',
-      value: ['支持128G TF卡', '3K视频 录制120分钟']
+      value: ['7.4V 4200mAh', '可通过USB快速充电']
     }, {
-      label: '端口',
-      value: ['microUSB', '三脚架固定孔']
+      label: 'WiFi',
+      value: ['802.11a/b/g/n网络协议', '支持2.4/5GHz通信']
     }, {
-      label: '防水防尘',
-      value: ['IP54']
+      label: '设备接口',
+      value: ['TYPE C']
     }]
   }
 }

+ 29 - 16
src/store/language/cn/purchase.js

@@ -11,33 +11,46 @@ export default{
     dec: '注:本页面所列配置及参数均以实际上市产品为准,如有变更,恕不另行通知;',
     arr: [
       {
-        name: '容量和内存',
-        val: ['LPDDR4X双通道', '6G内存', 'UFS 2.1', '64GB 机身存储']
+        name: '机身尺寸',
+        val: ['高度:220.7mm', '宽度:78.2mm', '厚度:78.2mm']
       },
       {
-        name: '机身尺寸和重量',
-        val: ['高度 = 153.3m', '宽度 = 74.5mm', '厚度 = 7.9mm', '重量 = 170g']
+        name: '镜头',
+        val: [
+          '类型:200°鱼眼镜头',
+          '孔径:f/2.0',
+          '数量:8个',
+          '分辨率:4608*3456像素(每个);12288*6144像素(合计)'
+        ]
+      },
+      {
+        name: '传感器',
+        val: ['范围:1/2.3英寸', '数量:8个']
+      },
+      {
+        name: '存储内存',
+        val: [
+          '16GB'
+        ]
       },
       {
-        name: '处理器平台',
+        name: '电池',
         val: [
-          'Qualcomm® 骁龙™ 845 处理器',
-          '10nm 先进制程',
-          '单核主频可达 2.8GHz',
-          'Adreno™ 630 图形处理器,主频可达 700MHz',
-          '配备人工智能引擎(AI Engine)'
+          '7.4V 4200mAh',
+          '可通过USB快速充电'
         ]
       },
       {
-        name: '网络',
-        val: ['支持 VoLTE 高质量宽带', '支持三载波聚', '支持 LTE B41 4x4 MIMO']
+        name: 'WiFi',
+        val: [
+          '802.11a/b/g/n网络协议',
+          '支持2.4/5GHz通信'
+        ]
       },
       {
-        name: '屏幕',
+        name: '设备接口',
         val: [
-          '6.17 英寸 In-Cell 全高清显示屏',
-          '2242 x 1080 分辨率,403 ppi',
-          '康宁®第三代大猩猩®玻璃'
+          'TYPE C'
         ]
       }
     ]

+ 25 - 20
src/store/language/cn/purchasetow.js

@@ -11,34 +11,39 @@ export default{
     dec: '注:本页面所列配置及参数均以实际上市产品为准,如有变更,恕不另行通知;',
     arr: [
       {
-        name: '容量和内存',
-        val: ['LPDDR4X双通道', '6G内存', 'UFS 2.1', '64GB 机身存储']
+        name: '机身尺寸',
+        val: ['高度:130mm', '宽度:47mm', '厚度:18mm', '重量:115g']
       },
       {
-        name: '机身尺寸和重量',
-        val: ['高度 = 153.3m', '宽度 = 74.5mm', '厚度 = 7.9mm', '重量 = 170g']
-      },
-      {
-        name: '处理器平台',
+        name: '材质',
         val: [
-          'Qualcomm® 骁龙™ 845 处理器',
-          '10nm 先进制程',
-          '单核主频可达 2.8GHz',
-          'Adreno™ 630 图形处理器,主频可达 700MHz',
-          '配备人工智能引擎(AI Engine)'
+          '钛金属',
+          '磨砂背'
         ]
       },
       {
-        name: '网络',
-        val: ['支持 VoLTE 高质量宽带', '支持三载波聚', '支持 LTE B41 4x4 MIMO']
+        name: '摄像头',
+        val: ['f / 2.0 大光圈镜头',
+          '3200万像素SONY sensor',
+          '220°双鱼眼镜头',
+          '9片8组光学镜头',
+          '3K视频录制速度为30fps']
       },
       {
-        name: '屏幕',
-        val: [
-          '6.17 英寸 In-Cell 全高清显示屏',
-          '2242 x 1080 分辨率,403 ppi',
-          '康宁®第三代大猩猩®玻璃'
-        ]
+        name: '连接',
+        val: ['蓝牙:5.0', 'WiFi:802.11a / b / g / n / ac']
+      },
+      {
+        name: '电池',
+        val: ['2000mAh', '通过USB快速充电']
+      },
+      {
+        name: '存储',
+        val: ['支持128G TF卡', '3K视频 录制120分钟']
+      },
+      {
+        name: '端口',
+        val: ['microUSB', '三脚架固定孔']
       }
     ]
   },

+ 56 - 0
src/store/language/en/binocular.js

@@ -75,5 +75,61 @@ export default{
   },
   parmas: {
     name: 'Detailed Parameters of 4DKanKan Lite'
+  },
+  standardGroup: {
+    label: 'Model',
+    name: '4DKanKan Lite',
+    info: [
+      {
+        label: 'Height',
+        value: '130mm'
+      },
+      {
+        label: 'Width',
+        value: '47mm'
+      },
+      {
+        label: 'Depth',
+        value: '18mm'
+      },
+      {
+        label: 'Weight',
+        value: '115g'
+      }
+    ],
+    params1: [
+      {
+        label: 'Fabric',
+        value: ['Titanium', 'Matte surface']
+      },
+      {
+        label: 'Camera',
+        value: [
+          'f/2.0 aperture',
+          '3200-pixels SONY sensor',
+          '220° fisheye lens*2',
+          'Optical lens*8',
+          '30fps recording speed in 3K'
+        ]
+      },
+      {
+        label: 'Connection',
+        value: ['Bluetooth: 5.0', 'WiFi:802.11a / b / g / n / ac']
+      }
+    ],
+    params2: [
+      {
+        label: 'Battery',
+        value: ['2000mAh', 'Quick charge through USB']
+      },
+      {
+        label: 'Storage',
+        value: ['128G Trans-flash Card', '120-minutes 3K video']
+      },
+      {
+        label: 'Interface',
+        value: ['microUSB', 'Tripod attachment hole']
+      }
+    ]
   }
 }

+ 20 - 29
src/store/language/en/eight.js

@@ -129,46 +129,37 @@ export default{
     name: 'Detailed Parameters of 4DKanKan Pro'
   },
   standardGroup: {
-    label: '型号',
-    name: '四维看看 Pro',
+    label: 'Model',
+    name: '4DKanKan Pro',
     info: [{
-      label: '高度',
-      value: '141.5毫米'
+      label: 'Height',
+      value: '220.7mm'
     }, {
-      label: '宽度',
-      value: '71.1mm'
+      label: 'Width',
+      value: '78.2mm'
     }, {
-      label: '厚度',
-      value: '17.98mm'
-    }, {
-      label: '重量',
-      value: '115g'
+      label: 'Depth',
+      value: '78.2mm'
     }],
     params1: [{
-      label: '材质',
-      value: ['钛金属', '磨砂背']
-    }, {
-      label: '摄像头',
-      value: ['f / 2.0 大光圈镜头', '3200万像素SONY sensor', '220°双鱼眼镜头', '9片8组光学镜头', '3K视频录制速度为30fps']
+      label: 'Lens',
+      value: ['Type: 200° fisheye lens', 'Aperture: f/2.0', 'Number: 8', 'Resolution: 4608*3456 pixels(each);<br/>12288*6144 pixels(total)']
     }, {
-      label: '连接',
-      value: ['蓝牙:5.0', 'WiFi:802.11a / b / g / n / ac']
+      label: 'Sensor',
+      value: ['Dimension: 1/2.3"', 'Number: 8']
     }, {
-      label: '',
-      value: []
+      label: 'Storage',
+      value: ['16GB']
     }],
     params2: [{
-      label: '电池',
-      value: ['3040mAh', '通过USB快速充电']
-    }, {
-      label: '存储',
-      value: ['支持128G TF卡', '3K视频 录制120分钟']
+      label: 'Battery',
+      value: ['7.4V 4200mAh', 'Quick charge through USB']
     }, {
-      label: '端口',
-      value: ['microUSB', '三脚架固定孔']
+      label: 'WiFi',
+      value: ['802.11a/b/g/n', '2.4/5GHz communication']
     }, {
-      label: '防水防尘',
-      value: ['IP54']
+      label: 'USB Interface',
+      value: ['TYPE C']
     }]
   }
 }

+ 29 - 16
src/store/language/en/purchase.js

@@ -11,33 +11,46 @@ export default{
     dec: '注:本页面所列配置及参数均以实际上市产品为准,如有变更,恕不另行通知;',
     arr: [
       {
-        name: '容量和内存',
-        val: ['LPDDR4X双通道', '6G内存', 'UFS 2.1', '64GB 机身存储']
+        name: 'Model',
+        val: ['Height: 220.7mm', 'Width: 78.2mm', 'Depth: 78.2mm']
       },
       {
-        name: '机身尺寸和重量',
-        val: ['高度 = 153.3m', '宽度 = 74.5mm', '厚度 = 7.9mm', '重量 = 170g']
+        name: 'Lens',
+        val: [
+          'Type: 200° fisheye lens',
+          'Aperture: f/2.0',
+          'Number: 8',
+          'Resolution: 4608*3456 pixels(each); 12288*6144 pixels(total)'
+        ]
+      },
+      {
+        name: 'Sensor',
+        val: ['Dimension: 1/2.3"', 'Number: 8']
+      },
+      {
+        name: 'Storage',
+        val: [
+          '16GB'
+        ]
       },
       {
-        name: '处理器平台',
+        name: 'Battery',
         val: [
-          'Qualcomm® 骁龙™ 845 处理器',
-          '10nm 先进制程',
-          '单核主频可达 2.8GHz',
-          'Adreno™ 630 图形处理器,主频可达 700MHz',
-          '配备人工智能引擎(AI Engine)'
+          '7.4V 4200mAh',
+          'Quick charge through USB'
         ]
       },
       {
-        name: '网络',
-        val: ['支持 VoLTE 高质量宽带', '支持三载波聚', '支持 LTE B41 4x4 MIMO']
+        name: 'Wi-Fi',
+        val: [
+          '802.11a/b/g/n',
+          '2.4/5GHz communication'
+        ]
       },
       {
-        name: '屏幕',
+        name: 'USB Interface',
         val: [
-          '6.17 英寸 In-Cell 全高清显示屏',
-          '2242 x 1080 分辨率,403 ppi',
-          '康宁®第三代大猩猩®玻璃'
+          'TYPE C'
         ]
       }
     ]

+ 25 - 20
src/store/language/en/purchasetow.js

@@ -11,34 +11,39 @@ export default{
     dec: '注:本页面所列配置及参数均以实际上市产品为准,如有变更,恕不另行通知;',
     arr: [
       {
-        name: '容量和内存',
-        val: ['LPDDR4X双通道', '6G内存', 'UFS 2.1', '64GB 机身存储']
+        name: 'Size',
+        val: ['Height: 130mm', 'Width: 47mm', 'Depth: 18mm', 'Weight: 115g']
       },
       {
-        name: '机身尺寸和重量',
-        val: ['高度 = 153.3m', '宽度 = 74.5mm', '厚度 = 7.9mm', '重量 = 170g']
-      },
-      {
-        name: '处理器平台',
+        name: 'Fabric',
         val: [
-          'Qualcomm® 骁龙™ 845 处理器',
-          '10nm 先进制程',
-          '单核主频可达 2.8GHz',
-          'Adreno™ 630 图形处理器,主频可达 700MHz',
-          '配备人工智能引擎(AI Engine)'
+          'Titanium',
+          'Matte surface'
         ]
       },
       {
-        name: '网络',
-        val: ['支持 VoLTE 高质量宽带', '支持三载波聚', '支持 LTE B41 4x4 MIMO']
+        name: 'Camera',
+        val: ['f/2.0 aperture',
+          '3200-pixels SONY sensor',
+          '220° fisheye lens*2',
+          'Optical lens*8',
+          '30fps recording speed in 3K']
       },
       {
-        name: '屏幕',
-        val: [
-          '6.17 英寸 In-Cell 全高清显示屏',
-          '2242 x 1080 分辨率,403 ppi',
-          '康宁®第三代大猩猩®玻璃'
-        ]
+        name: 'Connection',
+        val: ['Bluetooth: 5.0', 'WiFi:802.11a / b / g / n / ac']
+      },
+      {
+        name: 'Battery',
+        val: ['2000mAh', 'Quick charge through USB']
+      },
+      {
+        name: 'Storage',
+        val: ['128G Trans-flash Card', '120-minutes 3K video']
+      },
+      {
+        name: 'Interface',
+        val: ['microUSB', 'Tripod attachment hole']
       }
     ]
   },

+ 1 - 1
src/store/language/home_cn.js

@@ -139,7 +139,7 @@ export default {
     }
   },
   search: {
-    placeholder: '请输入关键字查找'
+    placeholder: '请输入关键字查找场景'
   },
   footer: {
     fdage: '四维时代',

+ 130 - 3
src/store/user.js

@@ -1,13 +1,16 @@
 import http from '@/util/http'
-import { reg } from '@/util'
+// import { isWorkPhone } from '@/util'
 import Vue from 'Vue'
 import Toast from '@/components/toast/toast'
+import Cookies from 'js-cookie'
 
 Vue.use(Toast)
 
 let vue = new Vue()
 
 let token = (localStorage && localStorage.getItem('token')) || ''
+
+let fdkankantoken = Cookies.get('4dkankantoken') || ''
 let cart = (localStorage && localStorage.getItem('cart')) || []
 let invoice2 = (localStorage && localStorage.getItem('invoice2')) || []
 let invoice3 = (localStorage && localStorage.getItem('invoice3')) || []
@@ -27,10 +30,16 @@ try {
 export default {
   state: {
     token: token,
+    fdkankantoken,
     name: null,
     cart: cart,
     myscene: '',
+    mydevice: '',
+    myexpansion: '',
+    mycharge: '',
+    myinvoicelist: '',
     myorder: '',
+    invoicedevice: '',
     invoice2: invoice2,
     invoice3: invoice3,
     ...dataObj
@@ -39,7 +48,9 @@ export default {
   mutations: {
     saveToken (state, token) {
       state.token = token
+
       try {
+        Cookies.set('fdkankantoken', token)
         localStorage.setItem('token', token)
       } catch (error) {
 
@@ -47,6 +58,7 @@ export default {
     },
     logout (state) {
       try {
+        Cookies.set('fdkankantoken', '')
         Object.keys(state).forEach(key => {
           state[key] = ''
           localStorage.setItem(key, '')
@@ -65,6 +77,29 @@ export default {
       localStorage.setItem('myscene', JSON.stringify(data))
     },
 
+    INVOICEDEVICE (state, data) {
+      state.invoicedevice = data
+      localStorage.setItem('invoicedevice', JSON.stringify(data))
+    },
+    MYDEVICE (state, data) {
+      state.mydevice = data
+      localStorage.setItem('mydevice', JSON.stringify(data))
+    },
+
+    MYEXPANSION (state, data) {
+      state.myexpansion = data
+      localStorage.setItem('myexpansion', JSON.stringify(data))
+    },
+
+    MYCHARGE (state, data) {
+      state.mycharge = data
+      localStorage.setItem('mycharge', JSON.stringify(data))
+    },
+    MYINVOICELIST (state, data) {
+      state.myinvoicelist = data
+      localStorage.setItem('myinvoicelist', JSON.stringify(data))
+    },
+
     INVOICE (state, data) {
       state[`invoice${data.type}`] = data.data
       localStorage.setItem(`invoice${data.type}`, JSON.stringify(data.data))
@@ -135,6 +170,22 @@ export default {
       }
       context.commit('logout')
     },
+    async checkToken (context, params) {
+      let res = await http({
+        method: 'post',
+        headers: {
+          token: context.state.token
+        },
+        url: '/user/checkToken'
+      })
+
+      let data = res.data
+      if (data.code === 0) {
+        context.commit('logout')
+      } else {
+        return vue.$toast.show('warn', data.msg)
+      }
+    },
     async reduceCart (context, params) {
       let res = await http({
         method: 'post',
@@ -190,6 +241,81 @@ export default {
       context.commit('INVOICE', {type: data.type, data: info.data.data})
     },
 
+    async getUserDevice (context, params) {
+      let res = await http({
+        method: 'post',
+        data: params,
+        headers: {
+          token: context.state.token
+        },
+        url: '/user/camera/list'
+      })
+
+      let data = res.data
+      if (data.code !== 0) return
+      context.commit('MYDEVICE', data.data)
+    },
+
+    async getInvoiceDevice (context, params) {
+      let res = await http({
+        method: 'post',
+        data: params,
+        headers: {
+          token: context.state.token
+        },
+        url: '/user/camera/getAll'
+      })
+
+      let data = res.data
+      if (data.code !== 0) return
+      context.commit('INVOICEDEVICE', data.data)
+    },
+
+    async getUserExpansion (context, params) {
+      let res = await http({
+        method: 'post',
+        data: params,
+        headers: {
+          token: context.state.token
+        },
+        url: '/user/virtualOrder/expansionList'
+      })
+
+      let data = res.data
+      if (data.code !== 0) return
+      context.commit('MYEXPANSION', data.data)
+    },
+
+    async getChargeList (context, params) {
+      let res = await http({
+        method: 'post',
+        data: params,
+        headers: {
+          token: context.state.token
+        },
+        url: '/user/virtualOrder/chargeList'
+      })
+
+      let data = res.data
+      if (data.code !== 0) return
+      context.commit('MYCHARGE', data.data)
+    },
+
+    async getInvoiceList (context, params) {
+      let res = await http({
+        method: 'post',
+        data: params,
+        headers: {
+          token: context.state.token
+        },
+        url: '/user/invoice/list'
+      })
+
+      let data = res.data
+      if (data.code !== 0) return
+      context.commit('MYINVOICELIST', data.data)
+    },
+
     async getUserScene (context, params) {
       let res = await http({
         method: 'post',
@@ -219,10 +345,11 @@ export default {
       context.commit('myOrder', data.data)
     },
     async getAuthCode (context, phone) {
-      if (reg.phone.test(phone)) {
+      let languge = localStorage.getItem('language')
+      if (phone) {
         let params = {
           phoneNum: phone,
-          areaNum: '86'
+          areaNum: languge === '中' ? '86' : '8888'
         }
         http({
           method: 'post',

+ 3 - 3
src/util/http.js

@@ -6,11 +6,11 @@ import Vue from 'vue'
 let vue = new Vue()
 // import qs from 'qs'
 const exceptUrls = ['/sso/user/logout', '/sso/user/sendUserInfo', '/user/order/queryOrderStatus']
-axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? 'http://pro.4dkankan.com/api' : '/api'
+// axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? 'http://pro.4dkankan.com/api' : '/api'
 
-// axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? 'http://192.168.0.10:8080/api' : '/api'
+axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? 'http://192.168.0.10:8080/api' : '/api'
 // 请求超时时限
-axios.defaults.timeout = 2000
+axios.defaults.timeout = 15000
 // 请求次数
 axios.defaults.retry = 2
 // 请求的间隙

+ 12 - 0
src/util/index.js

@@ -52,5 +52,17 @@ module.exports = {
   },
   isWide: function () {
     return Math.round(devicePixelRatio * 100) === 100 ? window.innerWidth > 1600 : true
+  },
+  isWorkPhone: function (phone) {
+    let phones = [
+      /^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$/
+    ]
+    for (let i = 0; i < phones.length; i++) {
+      console.log(phones[i].test(phone))
+      if (phones[i].test(phone)) {
+        return true
+      }
+    }
+    return false
   }
 }