tremble 6 anni fa
parent
commit
56601cc586
76 ha cambiato i file con 8088 aggiunte e 513 eliminazioni
  1. 1 1
      build/webpack.dev.conf.js
  2. BIN
      mobile.zip
  3. 1 0
      package.json
  4. 3 10
      src/App.vue
  5. BIN
      src/assets/images/404.png
  6. BIN
      src/assets/images/banner_pro.png
  7. BIN
      src/assets/images/c01.png
  8. BIN
      src/assets/images/icon-huiyuan.png
  9. BIN
      src/assets/images/pro.png
  10. BIN
      src/assets/images/quhao-jiantou.png
  11. 23 16
      src/components/cinvoices/index.vue
  12. 15 8
      src/components/citySelect/index.vue
  13. 4793 0
      src/components/createInvoice/city.js
  14. 332 0
      src/components/createInvoice/index.vue
  15. 218 0
      src/components/createInvoice/style.scss
  16. 11 6
      src/components/invoices/index.vue
  17. 175 0
      src/components/toast/binding.vue
  18. 7 125
      src/components/toast/index.vue
  19. 125 0
      src/components/toast/style.scss
  20. 6 0
      src/components/toast/toast.js
  21. 47 0
      src/pages/404/index.vue
  22. 186 0
      src/pages/account/country.js
  23. 32 1
      src/pages/account/forget/index.vue
  24. 38 1
      src/pages/account/forget/style.scss
  25. 1 1
      src/pages/account/manage/cart/index.vue
  26. 10 7
      src/pages/account/manage/change/index.vue
  27. 3 0
      src/pages/account/manage/change/style.scss
  28. 6 3
      src/pages/account/manage/confirm/index.vue
  29. 4 0
      src/pages/account/manage/confirm/style.scss
  30. 305 0
      src/pages/account/manage/consumption/index.vue
  31. 308 0
      src/pages/account/manage/device/index.vue
  32. 93 2
      src/pages/account/manage/index.vue
  33. 34 35
      src/pages/account/manage/information/index.vue
  34. 18 7
      src/pages/account/manage/myscene/index.vue
  35. 3 3
      src/pages/account/manage/myscene/style.scss
  36. 130 0
      src/pages/account/manage/openInvoice/index.vue
  37. 1 1
      src/pages/account/manage/order/index.vue
  38. 2 2
      src/pages/account/manage/order/style.scss
  39. 64 0
      src/pages/account/manage/style.scss
  40. 5 2
      src/pages/account/manage/submit/index.vue
  41. 38 4
      src/pages/account/register/index.vue
  42. 38 1
      src/pages/account/register/style.scss
  43. 20 12
      src/pages/cases/index.vue
  44. 11 3
      src/pages/cases/style.scss
  45. 1 1
      src/pages/eight/index.vue
  46. 13 0
      src/pages/introduce/index.vue
  47. 0 0
      src/pages/introduce/style.scss
  48. 57 0
      src/pages/introtow/index.vue
  49. 84 0
      src/pages/introtow/style.scss
  50. 11 3
      src/pages/layout/header.vue
  51. 5 7
      src/pages/layout/style.scss
  52. 1 1
      src/pages/location/index.vue
  53. 1 1
      src/pages/location/style.scss
  54. 12 0
      src/pages/privilege/index.vue
  55. 17 64
      src/pages/purchase/index.vue
  56. 1 0
      src/pages/purchase/style.scss
  57. 17 19
      src/pages/purchasetwo/index.vue
  58. 1 0
      src/pages/purchasetwo/style.scss
  59. 39 0
      src/router/index.js
  60. 1 1
      src/store/language/cn/about.js
  61. 2 6
      src/store/language/cn/binocular.js
  62. 3 3
      src/store/language/cn/coreTech.js
  63. 24 26
      src/store/language/cn/eight.js
  64. 1 1
      src/store/language/cn/home.js
  65. 123 0
      src/store/language/cn/purchase.js
  66. 113 0
      src/store/language/cn/purchasetow.js
  67. 19 23
      src/store/language/en/binocular.js
  68. 2 2
      src/store/language/en/coreTech.js
  69. 26 28
      src/store/language/en/eight.js
  70. 1 1
      src/store/language/en/home.js
  71. 123 0
      src/store/language/en/purchase.js
  72. 113 0
      src/store/language/en/purchasetow.js
  73. 29 25
      src/store/language/home_cn.js
  74. 29 40
      src/store/language/home_en.js
  75. 108 6
      src/store/user.js
  76. 4 4
      src/util/http.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.38'
 const PORT = process.env.PORT && Number(process.env.PORT)
 
 const devWebpackConfig = merge(baseWebpackConfig, {

BIN
mobile.zip


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

+ 3 - 10
src/App.vue

@@ -37,6 +37,7 @@ export default {
     if (!this.isMobile) {
       location.href = '/'
     }
+    this.$store.dispatch('checkToken')
   },
   components: {
     iheader: header,
@@ -47,15 +48,7 @@ export default {
 
 <style lang="scss" scoped>
 #app {
-  position: absolute;
   padding-top: 60px;
-  width: 100%;
-  height: 100%;
-  overflow: auto;
-  -webkit-overflow-scrolling: touch;
-  &::-webkit-scrollbar {
-    display: none;
-  }
 }
 
 .header{
@@ -63,7 +56,7 @@ export default {
   top: 0;
   left: 0;
   width: 100%;
+  transform: translateY(0);
 }
-.layout{
-}
+
 </style>

BIN
src/assets/images/404.png


BIN
src/assets/images/banner_pro.png


BIN
src/assets/images/c01.png


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


BIN
src/assets/images/pro.png


BIN
src/assets/images/quhao-jiantou.png


+ 23 - 16
src/components/cinvoices/index.vue

@@ -2,16 +2,16 @@
   <div class="invoices-layout">
     <div class="address-input-con" v-if="selectedId===3">
       <template v-if="isShowInvoice3">
-        <template v-if="tempInvoice3.title">
+        <template v-if="invoicet.title">
           <div class="bc-item">
             <div class="bc-contact">
-              <span>{{tempInvoice3.title}}</span>
+              <span>{{invoicet.title}}</span>
             </div>
-            <div>{{tempInvoice3.code}}</div>
-            <div>{{tempInvoice3.organizedAddress}}</div>
-            <div>{{tempInvoice3.registerPhone}}</div>
-            <div>{{tempInvoice3.bankName}}</div>
-            <div>{{tempInvoice3.bankAccount}}</div>
+            <div>{{invoicet.code}}</div>
+            <div>{{invoicet.organizedAddress}}</div>
+            <div>{{invoicet.registerPhone}}</div>
+            <div>{{invoicet.bankName}}</div>
+            <div>{{invoicet.bankAccount}}</div>
             <div class="bc-edit" @click="isShowInvoice3=false">编辑</div>
           </div>
         </template>
@@ -88,12 +88,12 @@
     </div>
     <div class="address-input-con" v-else>
       <template v-if="isShowInvoice2">
-        <template v-if="tempInvoice2.title">
+        <template v-if="invoice.title">
           <div class="bc-item">
             <div class="bc-contact">
-              <span>{{tempInvoice2.title}}</span>
+              <span>{{invoice.title}}</span>
             </div>
-            <div>{{tempInvoice2.code}}</div>
+            <div>{{invoice.code}}</div>
             <div class="bc-edit" @click="isShowInvoice2=false">编辑</div>
           </div>
         </template>
@@ -141,7 +141,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
@@ -150,7 +150,6 @@ export default {
   props: ['invoice', 'invoicet', 'token', 'selectedId'],
   computed: {
     tempInvoice2: function () {
-      console.log(cloneObj(this.invoice))
       return cloneObj(this.invoice)
     },
     tempInvoice3: function () {
@@ -165,12 +164,12 @@ export default {
   },
   methods: {
     blurHandle () {
-      document.querySelector('#app').style.height = 'auto'
-      setTimeout(() => {
-        document.querySelector('#app').style.height = '100%'
-      }, 20)
+
     },
     saveInvoice () {
+      let isObject = function (obj) {
+        return JSON.stringify(obj) === '{}' ? '' : obj
+      }
       let params = {}
       if (this.selectedId === 2) {
         params = {
@@ -197,6 +196,12 @@ export default {
           bankAccount
         }
       }
+      let test = Object.keys(params)
+      for (let i = 0; i < test.length; i++) {
+        if (!isObject(params[test[i]])) {
+          return this.$toast.show('warn', '信息填写不完整')
+        }
+      }
 
       this.$http
         .post('user/invoice/save', params, {
@@ -208,6 +213,8 @@ export default {
           let res = data.data
           if (res.code !== 0) return
           this.$emit('closeInvoice', true)
+          this.isShowInvoice3 = true
+          this.isShowInvoice2 = true
           let type = this.selectedId === 'geren' ? 2 : 3
           this.$store.dispatch('getInvoice', {
             type: type,

+ 15 - 8
src/components/citySelect/index.vue

@@ -5,13 +5,13 @@
         <div class="address-sub address-name">
           <div class="top-title">姓名</div>
           <div class="ant-input">
-            <input @blur="blurHandle"  v-model="tempAddress.shipName" type="text" placeholder="姓名" />
+            <input v-model="tempAddress.shipName" type="text" placeholder="姓名" />
           </div>
         </div>
         <div class="address-sub address-phone">
           <div class="top-title">联系电话</div>
           <div class="ant-input">
-            <input @blur="blurHandle" v-model="tempAddress.shipMobile" type="text" placeholder="联系电话" />
+            <input v-model="tempAddress.shipMobile" type="text" placeholder="联系电话" />
           </div>
         </div>
       </div>
@@ -45,7 +45,7 @@
             </ul>
           </div>
           <div class="ant-input">
-            <input @blur="blurHandle" v-model="tempAddress.shipAddress" type="text" placeholder="详细地址" />
+            <input v-model="tempAddress.shipAddress" type="text" placeholder="详细地址" />
           </div>
         </div>
       </div>
@@ -69,7 +69,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
@@ -136,10 +136,6 @@ export default {
   },
   methods: {
     blurHandle () {
-      document.querySelector('#app').style.height = 'auto'
-      setTimeout(() => {
-        document.querySelector('#app').style.height = '100%'
-      }, 20)
     },
     uAddress () {
       this.tempAddress.province = this.areaPath[0]
@@ -153,6 +149,11 @@ export default {
         shipMobile,
         shipName
       } = this.tempAddress
+
+      let isObject = function (obj) {
+        return JSON.stringify(obj) === '{}' ? '' : obj
+      }
+
       let params = {
         shipAddress,
         shipAreaPath,
@@ -161,6 +162,12 @@ export default {
         shipMobile,
         shipName
       }
+      let test = Object.keys(params)
+      for (let i = 0; i < test.length; i++) {
+        if (!isObject(params[test[i]])) {
+          return this.$toast.show('warn', '信息填写不完整')
+        }
+      }
       this.$http
         .post('/user/updateAddress', params, {
           headers: {

File diff suppressed because it is too large
+ 4793 - 0
src/components/createInvoice/city.js


+ 332 - 0
src/components/createInvoice/index.vue

@@ -0,0 +1,332 @@
+<template>
+  <div>
+    <div class="select-layout">
+      <p class="sub-title">
+        <span>发票金额</span>
+      </p>
+      <div class="address-input-con">
+        <div class="address-input-item">
+          <div class="address-sub">
+            <div class="top-title">开票金额</div>
+            <div class="ant-input">
+              <input v-model="amount" oninput="value=Math.max(Number(value.replace(/[^\d]/g,'')),1)"  type="text" placeholder="请输入开票金额" />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="select-layout">
+      <p class="sub-title">
+        <span>发票信息</span>
+      </p>
+      <div class="invoice-header">
+        <label class="check-con" @click="type='geren'">
+          <span class="check-box">
+            <span class="checkbox-inner" :class="{'checkbox-inner-checked':type==='geren'}"></span>
+          </span>
+          <span>个人</span>
+        </label>
+        <label class="check-con" @click="type='qiye'">
+          <span class="check-box">
+            <span class="checkbox-inner" :class="{'checkbox-inner-checked':type==='qiye'}"></span>
+          </span>
+          <span>企业</span>
+        </label>
+      </div>
+      <div class="address-input-con" v-if="type==='qiye'">
+        <div class="address-input-item">
+          <div class="address-sub">
+            <div class="top-title">抬头名称</div>
+            <div class="ant-input">
+              <input v-model="tempInvoice3.title" type="text" placeholder="请输入发票抬头" />
+            </div>
+          </div>
+        </div>
+        <div class="address-input-item">
+          <div class="address-sub">
+            <div class="top-title">税号</div>
+            <div class="ant-input">
+              <input v-model="tempInvoice3.code" type="text" placeholder="请输入税务登记号" />
+            </div>
+          </div>
+        </div>
+        <div class="address-input-item">
+          <div class="address-sub">
+            <div class="top-title">地址</div>
+            <div class="ant-input">
+              <input v-model="tempInvoice3.organizedAddress" type="text" placeholder="公司地址" />
+            </div>
+          </div>
+        </div>
+        <div class="address-input-item">
+          <div class="address-sub">
+            <div class="top-title">电话号码</div>
+            <div class="ant-input">
+              <input v-model="tempInvoice3.registerPhone" type="text" placeholder="公司电话号码" />
+            </div>
+          </div>
+        </div>
+        <div class="address-input-item">
+          <div class="address-sub">
+            <div class="top-title">开户银行</div>
+            <div class="ant-input">
+              <input v-model="tempInvoice3.bankName" type="text" placeholder="开户银行" />
+            </div>
+          </div>
+        </div>
+        <div class="address-input-item">
+          <div class="address-sub">
+            <div class="top-title">银行账户</div>
+            <div class="ant-input">
+              <input v-model="tempInvoice3.bankAccount" type="text" placeholder="银行账户" />
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="address-input-con" v-else>
+        <div class="address-input-item">
+          <div class="address-sub">
+            <div class="top-title">抬头名称</div>
+            <div class="ant-input">
+              <input v-model="tempInvoice2.title" type="text" placeholder="发票抬头" />
+            </div>
+          </div>
+        </div>
+        <div class="address-input-item">
+          <div class="address-sub">
+            <div class="top-title">税号</div>
+            <div class="ant-input">
+              <input v-model="tempInvoice2.code" type="text" placeholder="税务登记号" />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="select-layout">
+      <p class="sub-title">
+        <span>收货地址</span>
+      </p>
+      <div class="address-input-con">
+        <div class="address-input-item">
+          <div class="address-sub address-name">
+            <div class="top-title">姓名</div>
+            <div class="ant-input">
+              <input v-model="tempAddress.shipName" type="text" placeholder="姓名" />
+            </div>
+          </div>
+          <div class="address-sub address-phone">
+            <div class="top-title">联系电话</div>
+            <div class="ant-input">
+              <input v-model="tempAddress.shipMobile" type="text" placeholder="联系电话" />
+            </div>
+          </div>
+        </div>
+        <div class="address-input-item">
+          <div class="address-sub prov-name">
+            <div class="top-title">省份</div>
+            <div class="ant-input prov" @click="handleSelect('prov')">
+              {{citylist[currentPID]['p']||'省份'}}
+              <ul v-if="prov">
+                <li
+                  v-for="(item,i) in citylist"
+                  :key="i"
+                  @click="handleClick('currentPID',i)"
+                >{{item.p}}</li>
+              </ul>
+            </div>
+          </div>
+          <div class="address-sub city-phone">
+            <div class="top-title">城市</div>
+            <div class="ant-input city" @click="handleSelect('city')">
+              {{currentProv[currentCID]['n']||'城市'}}
+              <ul v-if="city">
+                <li
+                  v-for="(item,i) in currentProv"
+                  :key="i"
+                  @click="handleClick('currentCID',i)"
+                >{{item.n}}</li>
+              </ul>
+            </div>
+          </div>
+        </div>
+        <div class="address-input-item">
+          <div class="address-sub">
+            <div class="top-title">地址</div>
+            <div class="ant-input dist" @click="handleSelect('dist')">
+              {{currentCity[currentSID]['s']||'区/县'}}
+              <ul v-if="dist">
+                <li
+                  v-for="(item,i) in currentCity"
+                  :key="i"
+                  @click="handleClick('currentSID',i)"
+                >{{item.s}}</li>
+              </ul>
+            </div>
+            <div class="ant-input">
+              <input v-model="tempAddress.shipAddress" type="text" placeholder="详细地址" />
+            </div>
+          </div>
+        </div>
+        <p class="p-dec">请务必详细填写相符无误的地址以免耽误收货</p>
+      </div>
+    </div>
+    <div class="invoice-save">
+      <button @click="saveInvoice" type="submit" class="ant-btn ant-btn-primary">
+        <span>提 交</span>
+      </button>
+      <button type="submit" class="ant-btn ant-btn-primary cancel" @click="$router.back()">
+        <span>取 消</span>
+      </button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+import { citylist } from './city'
+let sle = ['prov', 'city', 'dist']
+
+export default {
+  data () {
+    let idArr = ['', '', '']
+
+    return {
+      type: 'geren',
+      amount: '',
+      tempInvoice2: {},
+      tempInvoice3: {},
+      tempAddress: {},
+      citylist,
+      prov: false,
+      city: false,
+      dist: false,
+      currentPID: idArr[0] || 18,
+      currentCID: idArr[1] || 3,
+      currentSID: idArr[2] || 2,
+      areaPath: ''
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token
+    }),
+    currentProv: function () {
+      let tmp = this.citylist[this.currentPID]
+      return tmp.c
+    },
+    currentCity: function () {
+      let cprov = this.citylist[this.currentPID]
+      let tmp = cprov.c[this.currentCID]
+      return tmp.a
+    }
+  },
+  watch: {
+    currentProv () {
+      this.currentCID = 0
+      this.currentSID = 0
+    }
+  },
+  methods: {
+    handleSelect (item) {
+      sle.forEach(i => {
+        if (i === item) {
+          this[i] = !this[i]
+        } else {
+          this[i] = false
+        }
+      })
+    },
+    handleClick (id, i) {
+      this[id] = i
+      this.handleChange()
+    },
+    handleChange () {
+      let prov = this.citylist[this.currentPID]
+      let city = prov.c[this.currentCID]
+      let dist = city.a[this.currentSID]
+      this.areaPath = [prov.p, city.n, dist.s]
+      console.log(this.areaPath)
+    },
+    async saveInvoice () {
+      let params = {}
+      let invoiceType = ''
+      if (this.type === 'geren') {
+        invoiceType = 2
+        let { title = '', code = '' } = this.tempInvoice2
+        params = {
+          invoiceType,
+          title,
+          code
+        }
+      } else {
+        let {
+          title = '',
+          code = '',
+          organizedAddress = '',
+          registerPhone = '',
+          bankName = '',
+          bankAccount = ''
+        } = this.tempInvoice3
+        invoiceType = 3
+        params = {
+          invoiceType,
+          title,
+          code,
+          organizedAddress,
+          registerPhone,
+          bankName,
+          bankAccount
+        }
+      }
+      let {
+        shipName = '',
+        shipMobile = '',
+        shipAddress = ''
+      } = this.tempAddress
+
+      this.tempAddress.shipAreaPath = this.areaPath.join(',')
+      this.tempAddress.amount = Number(this.amount)
+      this.tempAddress.shipName = shipName || ''
+      this.tempAddress.shipMobile = shipMobile || ''
+      this.tempAddress.shipAddress = shipAddress || ''
+
+      let temp = Object.keys(this.tempAddress)
+      temp.forEach(item => {
+        params[item] = this.tempAddress[item] || ''
+      })
+      console.log(params)
+      let arr = Object.keys(params)
+      for (let i = 0; i < arr.length; i++) {
+        if (!params[arr[i]]) {
+          return this.$toast.show('warn', '信息填写不能为空')
+        }
+      }
+
+      params['cameraId'] = ''
+
+      let res = await this.$http.post('/user/invoice/add', params, {
+        headers: {
+          token: this.token
+        }
+      })
+      let response = res.data
+
+      if (response.code === 0) {
+        this.$toast.show('success', '开票成功', () => {
+          this.$router.replace({name: 'consumption'})
+        })
+      } else {
+        return this.$toast.show('warn', response.msg, () => {})
+      }
+    }
+  },
+  mounted () {
+    this.handleChange()
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "./style.scss";
+</style>

+ 218 - 0
src/components/createInvoice/style.scss

@@ -0,0 +1,218 @@
+.cancel{
+  background: #e7e7e7!important;
+  margin-left: 5px;
+}
+.ant-input{
+  height: auto;
+  input{
+    border: 0;
+    width: 100%;
+    height: 40px;
+    line-height: 40px;
+    padding: 0;
+    font-size: 12px;
+    color: rgba(0, 0, 0, 0.65);
+  }
+}
+
+.select-layout{
+  margin-top: 10px;
+  background-color: #fff;
+  .sub-title{
+    font-size: 14px;
+    line-height: 21px;
+    font-weight: 700;
+    padding: 13px 16px;
+    border-bottom: 1px solid #e9e9e9;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+}
+
+
+.address-input-con {
+  font-size: 12px;
+  line-height: 1.5;
+  margin-bottom: 10px;
+  color: rgba(0, 0, 0, 0.65);
+  padding: 16px;
+  .address-input-item {
+    display: flex;
+    margin-bottom: 8px;
+    .address-sub {
+      width: 100%;
+      .prov,
+      .city,
+      .dist {
+        position: relative;
+        ul{
+          position: absolute;
+          top: 48px;
+          left: 0;
+          background: #fff;
+          width: 100%;
+          box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
+          border-radius: 4px;
+          z-index: 999;
+          transition: all 0.15s cubic-bezier(0.645, 0.045, 0.355, 1);
+          overflow: auto;
+          max-height: 300px;
+          li{
+            padding: 0 11px;
+            line-height: 30px;
+            height: 30px;
+            font-size: 12px;
+            color: rgba(0, 0, 0, 0.7);
+          }
+        }
+      }
+      .dist{
+        margin-bottom:8px;
+      }
+      .top-title {
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        color: rgba(0, 0, 0, 0.85);
+        padding: 0 0 8px;
+        margin: 0;
+        display: block;
+        text-align: left;
+        line-height: 1.5;
+        &::before {
+          display: inline-block;
+          margin-right: 4px;
+          content: "*";
+          font-family: SimSun;
+          line-height: 1;
+          font-size: 12px;
+          color: #f04134;
+        }
+      }
+    }
+    .address-name,
+    .prov-name {
+      width: 33.33%;
+      padding-right: 4px;
+      flex-shrink: 0;
+    }
+    .prov-name {
+      width: 50%;
+    }
+    .address-phone,
+    .city-name {
+      flex: auto;
+    }
+  }
+  .p-dec {
+    line-height: 32px;
+    margin-bottom: 8px;
+  }
+}
+.cancel{
+  background: #e7e7e7!important;
+  margin-left: 5px;
+}
+
+.check-con {
+  box-sizing: border-box;
+  margin: 0;
+  padding: 0;
+  color: rgba(0, 0, 0, 0.65);
+  font-size: 14px;
+  font-variant: tabular-nums;
+  line-height: 1.5;
+  list-style: none;
+  font-feature-settings: "tnum", "tnum";
+  display: inline-block;
+  line-height: unset;
+  cursor: pointer;
+  color: rgba(0,0,0,.65);
+  font-size: 14px;
+  margin-right: 30px;
+  .check-box {
+    box-sizing: border-box;
+    margin: 0;
+    padding: 0;
+    color: rgba(0, 0, 0, 0.65);
+    font-size: 14px;
+    font-variant: tabular-nums;
+    line-height: 1.5;
+    list-style: none;
+    font-feature-settings: "tnum", "tnum";
+    position: relative;
+    top: -0.09em;
+    display: inline-block;
+    line-height: 1;
+    white-space: nowrap;
+    vertical-align: middle;
+    outline: none;
+    cursor: pointer;
+    .checkbox-input {
+      position: absolute;
+      top: 0;
+      right: 0;
+      bottom: 0;
+      left: 0;
+      z-index: 1;
+      width: 100%;
+      height: 100%;
+      cursor: pointer;
+      opacity: 0;
+    }
+    .checkbox-inner {
+      border-radius: 90px;
+      width: 18px;
+      height: 18px;
+      position: relative;
+      top: 0;
+      left: 0;
+      display: block;
+      background-color: #fff;
+      border: 1px solid #d9d9d9;
+      border-collapse: separate;
+      transition: all 0.3s;
+      &::after {
+        position: absolute;
+        top: 50%;
+        left: 21%;
+        display: table;
+        width: 5.71428571px;
+        height: 9.14285714px;
+        border: 2px solid #fff;
+        width: 8px;
+        height: 12px;
+        border-top: 0;
+        border-left: 0;
+        transform: rotate(45deg) scale(0) translate(-50%, -50%);
+        opacity: 0;
+        transition: all 0.1s cubic-bezier(0.71, -0.46, 0.88, 0.6),
+      }
+    }
+    .checkbox-inner-checked {
+      background-color: #1fe4dc;
+      border-color: #1fe4dc;
+      &::after {
+        position: absolute;
+        display: table;
+        border: 2px solid #fff;
+        border-top: 0;
+        border-left: 0;
+        transform: rotate(45deg) scale(1) translate(-50%, -50%);
+        opacity: 1;
+        transition: all 0.2s cubic-bezier(0.12, 0.4, 0.29, 1.46) 0.1s;
+        content: " ";
+      }
+    }
+  }
+}
+
+.invoice-header{
+  padding: 18px 16px 0;
+}
+
+.invoice-save{
+  padding: 16px;
+  background-color: #fff;
+}

+ 11 - 6
src/components/invoices/index.vue

@@ -104,7 +104,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
@@ -113,7 +113,6 @@ export default {
   props: ['invoice', 'invoicet', 'token'],
   computed: {
     tempInvoice2: function () {
-      console.log(cloneObj(this.invoice))
       return cloneObj(this.invoice)
     },
     tempInvoice3: function () {
@@ -127,12 +126,11 @@ export default {
   },
   methods: {
     blurHandle () {
-      document.querySelector('#app').style.height = 'auto'
-      setTimeout(() => {
-        document.querySelector('#app').style.height = '100%'
-      }, 20)
     },
     saveInvoice () {
+      let isObject = function (obj) {
+        return JSON.stringify(obj) === '{}' ? '' : obj
+      }
       let params = {}
       if (this.type === 'geren') {
         params = {
@@ -153,6 +151,13 @@ export default {
         }
       }
 
+      let test = Object.keys(params)
+      for (let i = 0; i < test.length; i++) {
+        if (!isObject(params[test[i]])) {
+          return this.$toast.show('warn', '信息填写不完整')
+        }
+      }
+
       this.$http
         .post('user/invoice/save', params, {
           headers: {

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

@@ -0,0 +1,175 @@
+<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:'320px'}">
+      <div class="t-header ">
+        <span>添加新设备</span>
+        <i class="iconfont icon-cuowu" @click="handleClick"></i>
+      </div>
+      <div class="binding-con">
+        <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>
+          <div class="bind-info">
+           <p v-for="(item,i) in binginfo" :key="i">{{item}}</p>
+          </div>
+        </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.hasBind = true
+        this.errorMsg = '绑定的相机不存在'
+      } else if (data.code === 6010) {
+        this.hasBind = true
+        this.errorMsg = '该序列号已被绑定'
+      } else {
+        this.hasBind = true
+        this.errorMsg = data.msg
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "./style.scss";
+$theme-color: #1fe4dc;
+
+.bind-con{
+  .t-header{
+    height: 50px;
+    line-height: 50px;
+    text-align: center;
+    .iconfont{
+      position: absolute;
+      right: 10px;
+    }
+  }
+  .binding-con{
+    text-align: center;
+    .binding-body{
+      .b-input{
+        width: 70%;
+        margin: 0 auto;
+        input{
+          width: 100%;
+          text-align: center;
+          color: #969696;
+          height: 30px;
+          padding: 0 20px 0 10px;
+          line-height: 30px;
+          font-size: 12px;
+          border: solid 1px #e7e7e7;
+        }
+        .notbing{
+          border: 1px solid #ff0000;
+        }
+      }
+      .bind-info{
+        width: 90%;
+        margin: 15px auto;
+        color: #2d2d2d;
+        text-align: left;
+        p{
+          line-height: 1.5;
+        }
+      }
+      .bind-error{
+        color: #ff0000;
+        font-size: 12px;
+        text-align: center;
+        margin-top: 5px;
+      }
+    }
+  }
+
+  .bind-btn{
+    text-align: center;
+    background: #f7f7f7;
+    span{
+      display: inline-block;
+      margin:  0 auto;
+      line-height: 30px;
+      font-size: 14px;
+      padding: 0 10px;
+      margin: 10px 0;
+      background-color: $theme-color;
+      color: #2d2d2d;
+      border-radius: 4px;
+    }
+  }
+}
+</style>

+ 7 - 125
src/components/toast/index.vue

@@ -1,5 +1,6 @@
 <template>
   <div>
+    <binding :btype="bindingType" :visible='bindingVisible' @closePoint="()=>{bindingVisible = false,emitCallback()}"/>
     <div
       class="toast-layout"
       :style="{background:isLoaing?'none':'rgba(0, 0, 0, 0.3)'}"
@@ -39,15 +40,20 @@
 </template>
 
 <script>
+import binding from './binding'
+
 let types = {
   warn: '提示',
   error: '错误',
   success: '成功'
 }
 export default {
+  components: {binding},
   data () {
     return {
+      bindingType: 1,
       visible: false,
+      bindingVisible: false,
       message: '',
       submsg: '',
       type: 'warn',
@@ -75,129 +81,5 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-$theme-color: #1fe4dc;
-$anima-time:0.2s;
-$anima-delay:0.15s;
-
-.btn {
-  width: 88px;
-  color: #4a90e2;
-  display: inline-block;
-  font-size: 14px;
-  text-align: center;
-  border-radius: 2px;
-  width: 88px;
-  height: 40px;
-  line-height: 40px;
-  cursor: pointer;
-}
-.primary {
-  background: #fff;
-}
-.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);
-      height: 28px;
-      width: 28px;
-      max-height: 28px;
-      max-width: 28px;
-      animation: rotateLoader 1s;
-      animation-iteration-count: infinite;
-    }
-  }
-  .toast-con {
-    position: absolute;
-    padding: 0;
-    overflow: hidden;
-    top: 48%;
-    left: 50%;
-    transform: translate(-50%, -50%);
-    background: #fff;
-    width: 80%;
-    border-radius: 6px;
-    box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
-    .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 10px;
-      text-align: center;
-      height: 86px;
-      position: relative;
-      &>div{
-        position: absolute;
-        top: 50%;
-        width: 100%;
-        left: 50%;
-        transform: translate(-50%,-50%);
-        .main-msg{
-          font-size: 14px;
-          color: #000000;
-          line-height: 24px;
-        }
-        .sub-msg{
-          font-size: 10px;
-          color: #898A8E;
-          line-height: 15px;
-        }
-      }
-    }
-    .bottom {
-      border-top: 1px solid #ddd;
-      display: flex;
-      justify-content: space-around;
-      .b-line{
-        display: inline-block;
-        width: 1px;
-        height: 40px;
-        background: #ddd;
-      }
-    }
-    .mid-bottom {
-      text-align: center;
-      padding: 0;
-      .primary{
-        flex: 1;
-      }
-    }
-  }
-}
-.toast-active{
-  display: block!important;
-  opacity: 1!important;
-}
+@import './style.scss';
 </style>

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

@@ -0,0 +1,125 @@
+$theme-color: #1fe4dc;
+$anima-time:0.2s;
+$anima-delay:0.15s;
+
+.btn {
+  width: 88px;
+  color: #4a90e2;
+  display: inline-block;
+  font-size: 14px;
+  text-align: center;
+  border-radius: 2px;
+  width: 88px;
+  height: 40px;
+  line-height: 40px;
+  cursor: pointer;
+}
+.primary {
+  background: #fff;
+}
+.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);
+      height: 28px;
+      width: 28px;
+      max-height: 28px;
+      max-width: 28px;
+      animation: rotateLoader 1s;
+      animation-iteration-count: infinite;
+    }
+  }
+  .toast-con {
+    position: absolute;
+    padding: 0;
+    overflow: hidden;
+    top: 48%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    background: #fff;
+    width: 80%;
+    border-radius: 6px;
+    box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
+    .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 10px;
+      text-align: center;
+      height: 86px;
+      position: relative;
+      &>div{
+        position: absolute;
+        top: 50%;
+        width: 100%;
+        left: 50%;
+        transform: translate(-50%,-50%);
+        .main-msg{
+          font-size: 14px;
+          color: #000000;
+          line-height: 24px;
+        }
+        .sub-msg{
+          font-size: 10px;
+          color: #898A8E;
+          line-height: 15px;
+        }
+      }
+    }
+    .bottom {
+      border-top: 1px solid #ddd;
+      display: flex;
+      justify-content: space-around;
+      .b-line{
+        display: inline-block;
+        width: 1px;
+        height: 40px;
+        background: #ddd;
+      }
+    }
+    .mid-bottom {
+      text-align: center;
+      padding: 0;
+      .primary{
+        flex: 1;
+      }
+    }
+  }
+}
+.toast-active{
+  display: block!important;
+  opacity: 1!important;
+}

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

@@ -31,6 +31,12 @@ Toast.install = function (Vue) {
     showLoading: () => {
       instance.isLoaing = true
     },
+    showBinding: (val, callback) => {
+      instance.bindingVisible = true
+      instance.bindingType = val
+      instance.callback = callback || function () {
+      }
+    },
     show: (type, msg, callback) => {
       instance.img = imgs[type] || require('@/assets/images/icon/success.png')
       instance.message = msg

+ 47 - 0
src/pages/404/index.vue

@@ -0,0 +1,47 @@
+<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: 80vh;
+  ._404{
+    top: 50%;
+    left: 50%;
+    position: absolute;
+    transform: translate(-50%,-50%);
+    text-align: center;
+    font-size: 16px;
+    color: #2d2d2d;
+    width: 90%;
+    img{
+      width:100%;
+    }
+    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>

+ 186 - 0
src/pages/account/country.js

@@ -0,0 +1,186 @@
+let selectCall = [
+  ['中国', '+86', 'China'],
+  ['美国', '+1', 'USA'],
+  ['日本', '+81', 'Japan'],
+  ['中国香港', '+852', 'Hong Kong China'],
+  ['中国台湾', '+886', 'Taiwan of China'],
+  ['马来西亚', '+60', 'Malaysia'],
+  ['澳大利亚', '+61', 'Australia'],
+  ['加拿大', '+1', 'Canada'],
+  ['英国', '+44', 'UK'],
+  ['新加坡', '+65', 'Singapore'],
+  ['德国', '+49', 'Germany'],
+  ['俄罗斯', '+7', 'Russia'],
+  ['埃及', '+20', 'Egypt'],
+  ['南非', '+27', 'South Africa'],
+  ['希腊', '+30', 'Greece'],
+  ['荷兰', '+31', 'Holland'],
+  ['比利时', '+32', 'Belgium'],
+  ['法国', '+33', 'France'],
+  ['西班牙', '+34', 'Spain'],
+  ['匈牙利', '+36', 'Hungary'],
+  ['意大利', '+39', 'Italy'],
+  ['罗马尼亚', '+40', 'Romania'],
+  ['瑞士', '+41', 'Switzerland'],
+  ['奥地利', '+43', 'Austria'],
+  ['丹麦', '+45', 'Denmark'],
+  ['瑞典', '+46', 'Rachel Canon'],
+  ['挪威', '+47', 'Norway'],
+  ['波兰', '+48', 'Poland'],
+  ['秘鲁', '+51', 'Peru'],
+  ['墨西哥', '+52', 'Mexico'],
+  ['古巴', '+53', 'Cuba'],
+  ['阿根廷', '+54', 'Argentina'],
+  ['巴西', '+55', 'Brazil'],
+  ['智利', '+56', 'Chile'],
+  ['哥伦比亚', '+57', 'Columbia'],
+  ['委内瑞拉', '+58', 'Venezuela'],
+  ['印度尼西亚', '+62', 'Indonesia'],
+  ['菲律宾', '+63', 'Philippines'],
+  ['新西兰', '+64', 'New Zealand'],
+  ['泰国', '+66', 'Thailand'],
+  ['哈萨克斯坦', '+7', 'Kazakhstan'],
+  ['韩国', '+82', 'Korea'],
+  ['越南', '+84', 'Vietnam'],
+  ['土耳其', '+90', 'Turkey'],
+  ['印度', '+91', 'India'],
+  ['巴基斯坦', '+92', 'BaStan'],
+  ['阿富汗', '+93', 'Afghanistan'],
+  ['斯里兰卡', '+94', 'Sri Lanka'],
+  ['缅甸', '+95', 'Burma'],
+  ['伊朗', '+98', 'Iran'],
+  ['摩洛哥', '+212', 'Morocco'],
+  ['阿尔及利亚', '+213', 'Alger'],
+  ['突尼斯', '+216', 'Tunisian'],
+  ['利比亚', '+218', 'Libyan'],
+  ['冈比亚', '+220', 'Gambian'],
+  ['塞内加尔', '+221', 'Senegalese'],
+  ['马里', '+223', 'Mali'],
+  ['几内亚', '+224', 'Guinean'],
+  ['科特迪瓦', '+225', 'Ketediwa'],
+  ['布基纳法索', '+226', 'Burkina Faso'],
+  ['尼日尔', '+227', 'Niger'],
+  ['多哥', '+228', 'Togo'],
+  ['贝宁', '+229', 'Berlin'],
+  ['毛里求斯', '+230', 'Mauritius'],
+  ['利比里亚', '+231', 'Liberian'],
+  ['塞拉利昂', '+232', 'Sierra Leone'],
+  ['加纳', '+233', 'Ghana'],
+  ['尼日利亚', '+234', 'Nigerian'],
+  ['乍得', '+235', 'Chad'],
+  ['中非共和国', '+236', 'Central African Republic'],
+  ['喀麦隆', '+237', 'Cameroon'],
+  ['圣多美和普林西比', '+239', 'Sao Tome and Principe'],
+  ['加蓬', '+241', 'Gabonese'],
+  ['刚果民主共和国', '+243', 'Congo democratic republic'],
+  ['安哥拉', '+244', 'Angolan'],
+  ['阿森松岛', '+247', 'Ascension Island'],
+  ['塞舌尔', '+248', 'seychelles'],
+  ['苏丹', '+249', 'Sudanese'],
+  ['埃塞俄比亚', '+251', 'Ethiopian'],
+  ['索马里', '+252', 'Somalian'],
+  ['吉布提', '+253', 'Djibouti'],
+  ['肯尼亚', '+254', 'Kenyan'],
+  ['坦桑尼亚', '+255', 'Tanzanian'],
+  ['乌干达', '+256', 'Ugandan'],
+  ['布隆迪', '+257', 'Burundi'],
+  ['莫桑比克', '+258', 'Mozambique'],
+  ['赞比亚', '+260', 'Zambian'],
+  ['马达加斯加', '+261', 'Madagascar'],
+  ['津巴布韦', '+263', 'Zimbabwe'],
+  ['纳米比亚', '+264', 'Namibian'],
+  ['马拉维', '+265', 'Malawi'],
+  ['莱索托', '+266', 'Lesotho'],
+  ['博茨瓦纳', '+267', 'Botswana'],
+  ['斯威士兰', '+268', 'Swaziland'],
+  ['直布罗陀', '+350', 'Gibraltar'],
+  ['葡萄牙', '+351', 'Portuguese'],
+  ['卢森堡', '+352', 'Luxembourg'],
+  ['爱尔兰', '+353', 'Irish'],
+  ['冰岛', '+354', 'Icelandic'],
+  ['阿尔巴尼亚', '+355', 'Albanian'],
+  ['马耳他', '+356', 'Malta'],
+  ['塞浦路斯', '+357', 'Cypriot'],
+  ['芬兰', '+358', 'Finnish'],
+  ['保加利亚', '+359', 'Bulgarian'],
+  ['立陶宛', '+370', 'Lithuania'],
+  ['拉脱维亚', '+371', 'Latvian'],
+  ['爱沙尼亚', '+372', 'Estonian'],
+  ['摩尔多瓦', '+373', 'Moldova'],
+  ['亚美尼亚', '+374', 'Armenian'],
+  ['白俄罗斯', '+375', 'Belorussia'],
+  ['安道尔共和国', '+376', 'Republic of Andorra'],
+  ['摩纳哥', '+377', 'Monaco'],
+  ['圣马力诺', '+378', 'san marino'],
+  ['乌克兰', '+380', 'Ukraine'],
+  ['斯洛文尼亚', '+386', 'Slovenia'],
+  ['捷克', '+420', 'Czechoslovakian'],
+  ['斯洛伐克', '+421', 'Slovakian'],
+  ['列支敦士登', '+423', 'Liechtenstein'],
+  ['伯利兹', '+501', 'Belize'],
+  ['瓜地马拉', '+502', 'Guatemala'],
+  ['萨尔瓦多', '+503', 'Salvadoran'],
+  ['洪都拉斯', '+504', 'Honduran'],
+  ['尼加拉瓜', '+505', 'Nicaraguan'],
+  ['哥斯达黎加', '+506', 'Costa Rica'],
+  ['巴拿马', '+507', 'Panamanian'],
+  ['海地', '+509', 'Haiti'],
+  ['玻利维亚', '+591', 'Bolivian'],
+  ['圭亚那', '+592', 'Guyanan'],
+  ['厄瓜多尔', '+593', 'Ecuadoran'],
+  ['法属圭亚那', '+594', 'French Guianan'],
+  ['巴拉圭', '+595', 'Paraguay'],
+  ['马提尼克', '+596', 'Martini gram'],
+  ['苏里南', '+597', 'Surinam'],
+  ['乌拉圭', '+598', 'Uruguayan'],
+  ['文莱', '+673', 'Brunei'],
+  ['巴布亚新几内亚', '+675', 'Papua New Guinean'],
+  ['汤加', '+676', 'Tonga'],
+  ['所罗门群岛', '+677', 'Solomon Islands'],
+  ['斐济', '+679', 'Fijian'],
+  ['库克群岛', '+682', 'Cook Islands'],
+  ['法属波利尼西亚', '+689', 'French Polynesian'],
+  ['中国澳门', '+853', 'Chinese Aomen'],
+  ['柬埔寨', '+855', 'Cambodian'],
+  ['老挝', '+856', 'Laos'],
+  ['孟加拉国', '+880', 'Bangladesh'],
+  ['马尔代夫', '+960', 'Maldives'],
+  ['黎巴嫩', '+961', 'Lebanese'],
+  ['约旦', '+962', 'Jordanian'],
+  ['叙利亚', '+963', 'Syrian'],
+  ['伊拉克', '+964', 'Iraqi'],
+  ['科威特', '+965', 'Kuwaiti'],
+  ['沙特阿拉伯', '+966', 'Saudi Arabian'],
+  ['也门', '+967', 'Yemenese'],
+  ['阿曼', '+968', 'Aman'],
+  ['阿拉伯联合酋长国', '+971', 'United Arab Emirates'],
+  ['以色列', '+972', 'Israeli'],
+  ['巴林', '+973', 'Bahraini'],
+  ['卡塔尔', '+974', 'Qataran'],
+  ['蒙古', '+976', 'Mongolian'],
+  ['尼泊尔', '+977', 'Nepalese'],
+  ['塔吉克斯坦', '+992', 'Tajikistan'],
+  ['土库曼斯坦', '+993', 'Turkmenistan'],
+  ['阿塞拜疆', '+994', 'Azerbaijanian'],
+  ['格鲁吉亚', '+995', 'Georgian'],
+  ['吉尔吉斯斯坦', '+996', 'Kyrgyzstan'],
+  ['乌兹别克斯坦', '+998', 'Uzbekistan'],
+  ['巴哈马', '+1242', 'Bahamian'],
+  ['巴巴多斯', '+1246', 'Barbados'],
+  ['安圭拉岛', '+1264', 'Anguilla island'],
+  ['安提瓜和巴布达', '+1268', 'Antigua and Barbadian'],
+  ['开曼群岛', '+1345', 'cayman islands'],
+  ['百慕大群岛', '+1441', 'Bermuda Islands'],
+  ['格林纳达', '+1473', 'Grenada'],
+  ['蒙特塞拉特岛', '+1664', 'Montserrat'],
+  ['关岛', '+1671', 'Guam'],
+  ['圣卢西亚', '+1758', 'Saint Lucia'],
+  ['波多黎各', '+1787', 'Puerto Rico'],
+  ['多明尼加共和国', '+1809', 'Dominican republic'],
+  ['特立尼达和多巴哥', '+1868', 'Trinidad and Tobago'],
+  ['牙买加', '+1876', 'Jamaica'],
+  ['塞尔维亚共和国', '+381', 'The republic of Serbia'],
+  ['毛里塔尼亚', '+222', 'Mauritania ']
+]
+
+export default selectCall

+ 32 - 1
src/pages/account/forget/index.vue

@@ -8,6 +8,17 @@
     <div class="login-con">
       <div class="input-con" :class="{inputActive:inputActive==='phone'}">
         <img :src="`${$cdn}images/icon/icon-phone@2x.png`" alt="">
+        <div class="phone-select" ref="quhaoMenu">
+          <div @click="showSelect=!showSelect">
+            <span>{{codeActive[1]}}</span>
+            <img :src="`${$cdn}images/quhao-jiantou.png`" >
+          </div>
+          <ul v-show="showSelect" >
+            <li @click="selectItem(item)" v-for="(item,i) in selectCall" :key="i">
+              {{item[0]}}{{item[1]}}
+            </li>
+          </ul>
+        </div>
         <input v-model="phone" oninput="value=value.replace(/[^\d]/g,'')" maxlength='11' @focus="inputActive='phone'" @blur="blurHandle" type="text" placeholder="手机">
       </div>
       <div class="code-con">
@@ -33,6 +44,7 @@
 
 <script>
 import {mapState} from 'vuex'
+import selectCall from '../country.js'
 
 export default {
   computed: {
@@ -42,6 +54,9 @@ export default {
   },
   data () {
     return {
+      showSelect: false,
+      selectCall,
+      codeActive: ['中国', '+86', 'China'],
       phone: '',
       authCode: '',
       interTime: 60,
@@ -51,7 +66,20 @@ export default {
       inputActive: ''
     }
   },
+  mounted () {
+    document.addEventListener('click', (e) => {
+      if (this.$refs.quhaoMenu) {
+        if (!this.$refs.quhaoMenu.contains(e.target)) {
+          this.showSelect = false
+        }
+      }
+    })
+  },
   methods: {
+    selectItem (item) {
+      this.showSelect = false
+      this.codeActive = item
+    },
     blurHandle () {
       this.inputActive = ''
       document.querySelector('#app').style.height = 'auto'
@@ -60,7 +88,10 @@ export default {
       }, 20)
     },
     async getAuthCode () {
-      let res = await this.$store.dispatch('getAuthCode', this.phone)
+      let res = await this.$store.dispatch('getAuthCode', {
+        phone: this.phone,
+        code: Number(this.codeActive[1].substr(1))
+      })
       if (res) {
         this.interl && clearInterval(this.interl)
         this.interl = null

+ 38 - 1
src/pages/account/forget/style.scss

@@ -3,7 +3,6 @@ input[type='password']{
   border: 0;
   outline: 0;
   height: 48px;
-  line-height: 48px;
   padding-right: 16px;
   padding-left: 12px;
   font-size: 14px;
@@ -26,6 +25,44 @@ input[type='password']{
   font-size: 16px;
   color: rgba(0, 0, 0, 0.7);
 }
+.phone-select{
+  &>div{
+    height: 18px;
+    border-right: 1px solid #f1f1f1;
+    &>span{
+      display: inline-block;
+      vertical-align: middle;
+    }
+  }
+  img{
+    width: 10px!important;
+    margin: 0 12px!important;
+    vertical-align: middle!important;
+  }
+  ul{
+    position: absolute;
+    top: 0;
+    left: 0;
+    background: #fff;
+    width: 200px;
+    height: 220px;
+    padding: 0 10px;
+    overflow: auto;
+    transition: ease 0.3s all;
+    z-index: 888;
+    box-shadow: 0px 1px 8px #ddd;
+    li{
+      height: 40px;
+      line-height: 50px;
+      color: #999;
+      font-size: 14px;
+      cursor: pointer;
+      &:hover{
+        color: #000;
+      }
+    }
+  }
+}
 .forget-layout{
   width: 100%;
   .banner{

+ 1 - 1
src/pages/account/manage/cart/index.vue

@@ -78,7 +78,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

+ 10 - 7
src/pages/account/manage/change/index.vue

@@ -5,9 +5,7 @@
         <div class="order-input-item">
           <div class="order-sub">
             <div class="top-title">手机号码</div>
-            <div class="ant-input" >
-              <input @blur="blurHandle" v-model="phone" type="text" placeholder="手机号码" />
-            </div>
+            <div class="top-username">{{info.userName}}</div>
           </div>
         </div>
         <div class="order-input-item">
@@ -18,7 +16,7 @@
                <input @blur="blurHandle" v-model="code" type="text" placeholder="请输入验证码" />
               </div>
                 <button type="submit" class="ant-btn ant-btn-primary code">
-                    <span v-if="!jishi">获取验证码</span>
+                    <span v-if="!jishi" @click="getAuthCode">获取验证码</span>
                     <span v-else>{{interTime}}s后重新发送</span>
                 </button>
             </div>
@@ -54,7 +52,8 @@ import {mapState} from 'vuex'
 export default {
   computed: {
     ...mapState({
-      token: state => state.user.token
+      token: state => state.user.token,
+      info: state => state.user.info
     })
   },
   data () {
@@ -75,7 +74,11 @@ export default {
       }, 20)
     },
     async getAuthCode () {
-      let res = await this.$store.dispatch('getAuthCode', this.phone)
+      let {userName, country} = this.info
+      let res = await this.$store.dispatch('getAuthCode', {
+        phone: userName,
+        code: country === '中国' ? 86 : country
+      })
       if (res) {
         this.interl && clearInterval(this.interl)
         this.interl = null
@@ -100,7 +103,7 @@ export default {
       }
       let params = {
         password: this.password,
-        phoneNum: this.phone,
+        phoneNum: this.info.userName,
         msgAuthCode: this.code
       }
       this.$http({

+ 3 - 0
src/pages/account/manage/change/style.scss

@@ -54,6 +54,9 @@
             text-align: left;
             line-height: 1.5;
           }
+          .top-username{
+            font-size: 16px;
+          }
         }
         .order-name,.prov-name{
           width: 33.33%;

+ 6 - 3
src/pages/account/manage/confirm/index.vue

@@ -21,8 +21,8 @@
     </div>
     <div class="box-con">
       <div class="bc-title">收货地址</div>
-      <div class="bc-item address-item" v-if="isShowAddress">
-        <div class="bc-ct">
+      <div class="bc-item " :class="{'address-item':address.shipName}"  v-if="isShowAddress">
+        <div class="bc-ct" v-if="address.shipName">
           <div class="bc-contact">
             {{address.shipName}}
             <div>{{address.shipMobile}}</div>
@@ -31,6 +31,9 @@
             {{`${address.shipAreaPath}${address.shipAddress}`}}
           </div>
         </div>
+        <div class="noaddress" v-else>
+          <p>暂无收货地址</p>
+        </div>
         <div class="bc-edit" @click="isShowAddress=false">编辑</div>
       </div>
       <div class="address-con" v-else>
@@ -71,7 +74,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

+ 4 - 0
src/pages/account/manage/confirm/style.scss

@@ -66,9 +66,13 @@
       border: 1px solid #1fe4dc;
       position: relative;
       background-color: #f6f9ff;
+      .noaddress{
+        color: rgba(0,0,0,.45);
+      }
       .bc-ct{
         margin-left: 32px;
         margin-right: 50px;
+        min-height: 55px;
         .bc-contact{
           font-size: 12px;
           color: rgba(0,0,0,.7);

+ 305 - 0
src/pages/account/manage/consumption/index.vue

@@ -0,0 +1,305 @@
+<template>
+  <div class="consumption-layout">
+    <div class="plate">
+      <ul class="re-list">
+        <li v-for="(item,i) in data" :key="i">
+          <template v-if="tabActive===1">
+            <p class="f-title">{{item.childName}}</p>
+            <p>{{item.body}}</p>
+            <div>{{item.fuhao}}{{item.points}}<i class="iconfont icon-shang"></i></div>
+
+          </template>
+           <template v-else-if="tabActive===0">
+            <p class="f-title">{{item.childName}}</p>
+            <p>{{item.channel}}</p>
+            <div>{{item.status}}<i class="iconfont icon-shang"></i></div>
+          </template>
+
+          <template v-else>
+            <p class="f-title">{{item.title||''}}</p>
+            <p>{{item.createTime}}</p>
+            <div>{{item.finish}}<i class="iconfont icon-shang"></i></div>
+          </template>
+        </li>
+      </ul>
+      <div class="scene-nothing" v-if="!total">
+        <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>
+  </div>
+</template>
+<script>
+import { mapState } from 'vuex'
+import Paging from '@/components/Paging'
+
+let PAYSSTR = {
+  0: '微信',
+  1: '支付宝',
+  2: 'paypal'
+}
+
+let methodStr = {
+  0: 'getConsumpList',
+  1: 'getChargeList',
+  2: 'getInvoiceList'
+}
+
+let invoceStatusType = {
+  0: '未开票',
+  1: '已开票'
+}
+export default {
+  props: ['tabactive'],
+  components: { Paging },
+  data () {
+    let tabList = [
+      {
+        name: '四维看看Pro',
+        id: 4
+      }, {
+        name: '四维看看Lite',
+        id: 0
+      }
+    ]
+
+    return {
+      tabList,
+      currentPage: 1,
+      total: 0,
+      data: [],
+      tabActive: this.tabactive,
+      searchKey: '',
+      pageSize: 8
+    }
+  },
+  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 : [])
+      }
+    })
+  },
+  methods: {
+    pageChange (data) {
+      this.currentPage = data
+    },
+    getList (searchKey = '') {
+      let str = methodStr[this.tabActive]
+      this[str](searchKey)
+    },
+    async getChargeList (searchKey = '') {
+      let params = {
+        childName: searchKey,
+        pageNum: searchKey ? 1 : this.currentPage,
+        pageSize: this.pageSize
+      }
+      await this.$store.dispatch('getChargeList', params)
+      if (!this.mycharge.total && searchKey) {
+        return this.$toast.show('warn', '没有找到相应的记录', () => {
+          this.getList()
+        })
+      }
+      this.pageSize = this.mycharge.pageSize
+      this.total = this.mycharge.total || 0
+      this.data = this.mycharge.list
+      this.data.forEach(item => {
+        item['fuhao'] = item['status'] === -1 ? '-' : '+'
+      })
+    },
+    async getInvoiceList () {
+      let params = {
+        cameraId: this.activeId,
+        pageNum: this.currentPage,
+        pageSize: this.pageSize,
+        type: this.activeTypeId
+      }
+      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']]
+      })
+    },
+    async getConsumpList (searchKey = '') {
+      let params = {
+        childName: searchKey,
+        pageNum: searchKey ? 1 : this.currentPage,
+        pageSize: this.pageSize
+      }
+      await this.$store.dispatch('getUserExpansion', params)
+      if (!this.myexpansion.total && searchKey) {
+        return this.$toast.show('warn', '没有找到相应的记录', () => {
+          this.getList()
+        })
+      }
+      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']]
+      })
+    }
+  },
+  mounted () {
+    this.$bus.$on('selectdevice', id => {
+      this.tabActive = id
+    })
+    this.getList()
+  },
+  watch: {
+    currentPage () {
+      this.getList()
+    },
+    tabActive (newVal) {
+      this.getList()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+$theme-color: #1fe4dc;
+
+.btn{
+  width: 72px;
+  display: inline-block;
+  border: solid 1px #ddd;
+  line-height: 32px;
+  height: 32px;
+  text-align: center;
+  border-radius: 2px;
+}
+.primary{
+  background-color: $theme-color;
+  border-color: $theme-color;
+}
+.consumption-layout{
+  background: #f6f9fd;
+  .plate{
+    .re-list{
+      margin-top: 20px;
+      li{
+        background-color: #fff;
+        border-bottom: 1px solid #ececec;
+        height: 60px;
+        padding-right: 20%;
+        position: relative;
+        padding: 12px 20% 12px 12px;
+        .f-title{
+          font-weight: bold;
+          color: #2d2d2d;
+          margin-bottom: 8px;
+        }
+        p{
+          color: #777;
+          font-size: 12px;
+        }
+        div{
+          position: absolute;
+          right: 4%;
+          top: 50%;
+          transform: translateY(-50%);
+          font-size: 12px;
+          color: #777;
+          .iconfont{
+            transform: rotate(90deg);
+            display: inline-block;
+          }
+        }
+      }
+    }
+    .scene-nothing{
+      background: #fff;
+      text-align: center;
+      padding:40px 0;
+      img{
+        padding-bottom: 22px;
+      }
+      div{
+        font-size: 14px;
+        color: #969696;
+      }
+    }
+  }
+  .paging {
+    // border-left: #e5e5e5 1px solid;
+    height: 100%;
+    padding-bottom: 20px;
+    & /deep/ .layout {
+      text-align: center;
+      margin-top: 20px;
+    }
+    & /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: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>

+ 308 - 0
src/pages/account/manage/device/index.vue

@@ -0,0 +1,308 @@
+<template>
+  <div class="device-layout">
+    <div class="plate">
+      <template v-if="tabActive===4">
+        <div class="d-item" v-for="(item,i) in mydevice.list" :key="i" >
+          <img :src="`${$cdn}images/banner_pro.png`" alt="">
+          <img v-if="item.spaceEndTime" class="king" :src="`${$cdn}images/icon-huiyuan.png`" alt="">
+
+          <div class="eight-right">
+            <p class="i-title">ID:{{item.childName}}</p>
+            <p class="i-dec">云存储空间</p>
+            <div class="capacity">
+              <div class="c-line">
+                <div class="active" :style="{width:getBar(item.usedSpace,item.totalSpace)}"></div>
+              </div>
+            </div>
+            <p class="i-dec">{{item.usedSpaceStr}} / {{item.totalSpaceStr}}</p>
+
+            <div class="btn-con">
+              <span class="btn" @click="unbind(item)">解绑</span>
+              <span class="btn" @click="$router.push({name:'introduce',params:{id:item.childName}})">扩容</span>
+              <span class="btn primary"  v-if="!item.spaceEndTime" @click="$router.push({name:'privilege',params: {
+          cameraId: item.id,
+          childName: item.childName
+        }})">升级</span>
+              <span class="btn" @click="$router.push({name:'introduce',params:{id:item.childName}})" v-else >续期</span>
+            </div>
+          </div>
+        </div>
+      </template>
+
+      <template v-else>
+        <div class="d-item"  v-for="(item,i) in mydevice.list" :key="i">
+          <img :src="`${$cdn}images/t_product.png`" alt="">
+          <div class="item-right">
+            <p class="i-title">ID:{{item.childName}}</p>
+            <p class="i-dec">剩余点数:</p>
+            <div class="btn-con">
+              <span>{{item.balance}}</span>
+              <div>
+                <span class="btn" @click="unbind(item)">解绑</span>
+                <span class="btn primary" @click="$router.push({name:'introtow',params:{id:item.childName}})">充值</span>
+              </div>
+            </div>
+          </div>
+        </div>
+      </template>
+
+      <div class="scene-nothing" v-if="!total">
+        <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>
+  </div>
+</template>
+<script>
+import { mapState } from 'vuex'
+import Paging from '@/components/Paging'
+
+export default {
+  components: { Paging },
+  data () {
+    let tabList = [
+      {
+        name: '四维看看Pro',
+        id: 4
+      }, {
+        name: '四维看看Lite',
+        id: 0
+      }
+    ]
+    return {
+      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) : {})
+      }
+    })
+  },
+  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/camera/unbind'
+        })
+        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, () => {
+        this.getList()
+      })
+    },
+    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)
+
+      if (!this.mydevice.total && searchKey) {
+        return this.$toast.show('warn', '没有找到对应的设备', () => {
+          this.getList()
+        })
+      }
+      this.pageSize = this.mydevice.pageSize
+      this.total = this.mydevice.total || 0
+    }
+  },
+  mounted () {
+    this.getList()
+    this.$bus.$on('selectdevice', id => {
+      this.tabActive = id
+    })
+  },
+  watch: {
+    currentPage () {
+      this.getList()
+    },
+    tabActive (newVal) {
+      this.currentPage === 1 ? this.getList() : this.currentPage = 1
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+$theme-color: #1fe4dc;
+
+.btn{
+  width: 72px;
+  display: inline-block;
+  border: solid 1px #ddd;
+  line-height: 32px;
+  height: 32px;
+  text-align: center;
+  border-radius: 2px;
+}
+.primary{
+  background-color: $theme-color;
+  border-color: $theme-color;
+}
+.device-layout{
+  background: #f6f9fd;
+  .plate{
+    .scene-nothing{
+      background: #fff;
+      text-align: center;
+      padding:40px 0;
+      img{
+        padding-bottom: 22px;
+      }
+      div{
+        font-size: 14px;
+        color: #969696;
+      }
+    }
+    .d-item{
+      position: relative;
+      background: #fff;
+      margin: 10px 0;
+      padding: 10px 0;
+      img{
+        position: absolute;
+        width: 30px;
+        top: 50%;
+        left: 15%;
+        transform: translate(-50%, -50%);
+      }
+      .king{
+        top: 21%;
+        left: 19.5%;
+      }
+      .item-right,.eight-right{
+        height: 90px;
+        margin-left: 30%;
+        margin-right: 16px;
+        .i-title{
+          font-size: 16px;
+          color: #2d2d2d;
+          margin-bottom: 10px;
+          font-weight: bold;
+        }
+        .i-dec{
+          margin-bottom: 10px;
+          font-size: 14px;
+          color: #777;
+        }
+        .capacity{
+          margin: 5px 0;
+          .c-line{
+            width: 64%;
+            height: 8px;
+            background-color: #ccc;
+            .active{
+              background-color:$theme-color;
+              height: 100%;
+            }
+          }
+        }
+        .btn-con{
+          display: flex;
+          width: 100%;
+          justify-content: space-between;
+        }
+      }
+      .eight-right{
+        height: 130px;
+      }
+    }
+  }
+  .paging {
+    // border-left: #e5e5e5 1px solid;
+    height: 100%;
+    padding-bottom: 20px;
+    & /deep/ .layout {
+      text-align: center;
+      margin-top: 20px;
+    }
+    & /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: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>

+ 93 - 2
src/pages/account/manage/index.vue

@@ -2,29 +2,120 @@
   <div class="manage-layout">
     <div class="m-nav">
       <span>{{title}}</span>
-      <span class="btns"></span>
+      <span v-if="title==='我的设备'" @click="addDevice" class="btns">
+        +添加设备
+      </span>
+      <span v-if="consumpselected.id===2&&title==='消费记录'" @click="openInvoice" class="btns">
+        开具发票
+      </span>
+      <div v-if="title==='我的设备'" class="select" ref="mbMenu1" @click="selectedActive=!selectedActive">
+        {{selected.name}}
+        <div class="s-sub" :class="{'s-active':selectedActive}">
+          <div v-for="(item,i) in selectType" :key="i" :class="{'item-active':selected.name===item.name}" @click="emithandle(item)" class="s-item">{{item.name}}</div>
+        </div>
+      </div>
+      <div v-if="title==='消费记录'" class="select" ref="mbMenu1" @click="selectedActive=!selectedActive">
+        {{consumpselected.name}}
+        <div class="s-sub" :class="{'s-active':selectedActive}">
+          <div v-for="(item,i) in consumpType" :key="i" :class="{'item-active':consumpselected.name===item.name}" @click="emithandlerecord(item)" class="s-item">{{item.name}}</div>
+        </div>
+      </div>
     </div>
-    <router-view />
+    <router-view :tabactive='consumpselected.id' />
   </div>
 </template>
 
 <script>
+import {mapState} from 'vuex'
+
 let titleName = {
   'information': '个人中心',
   'order': '我的订单',
   'myscene': '我的场景',
+  'device': '我的设备',
+  'consumption': '消费记录',
   'change': '修改密码',
   'confirm': '确认订单',
   'submit': '确认订单',
   'paytype': '确认订单',
+  'openInvoice': '开具发票',
   'payselect': '支付方式',
   'cart': '购物车'
 }
 export default {
   computed: {
+    ...mapState({
+      langCases: state => state.language.home.cases,
+      language: state => state.language.current
+    }),
     title: function () {
       return titleName[this.$route.name]
     }
+  },
+  methods: {
+    addDevice () {
+      let val = this.selected.id === 4 ? 1 : 0
+      this.$toast.showBinding(val, () => {
+      })
+    },
+    openInvoice () {
+      this.$router.push({
+        name: 'openInvoice'
+      })
+    },
+    emithandle (item) {
+      this.selected = item
+      this.$bus.$emit('selectdevice', item.id)
+    },
+    emithandlerecord (item) {
+      this.consumpselected = item
+      this.$bus.$emit('selectdevice', item.id)
+    }
+  },
+  data () {
+    let selectType = [
+      {
+        name: 'Pro',
+        id: 4
+      }, {
+        name: 'Lite',
+        id: 0
+      }
+    ]
+    let consumpType = [
+      {
+        name: '扩容记录',
+        id: 0
+      }, {
+        name: '充值记录',
+        id: 1
+      }, {
+        name: '增值发票',
+        id: 2
+      }
+    ]
+    return {
+      selectedActive: false,
+      selectType,
+      consumpType,
+      selected: {
+        name: 'Pro',
+        id: 4
+      },
+      consumpselected: {
+        name: '扩容记录',
+        id: 0
+      }
+    }
+  },
+  mounted () {
+    document.addEventListener('click', (e) => {
+      if (this.$refs.mbMenu1) {
+        if (!this.$refs.mbMenu1.contains(e.target)) {
+          this.selectedActive = false
+        }
+      }
+    })
   }
 }
 </script>

+ 34 - 35
src/pages/account/manage/information/index.vue

@@ -65,7 +65,7 @@
           </div>
         </template>
       </div>
-      <invoices :invoice='invoice2' :invoicet="invoice3" :token="token" @closeInvoice="data=>{isShowInvoice=data}" v-else />
+      <invoices :invoice='editInvoice2' :invoicet="editInvoice3" :token="token" @closeInvoice="data=>{isShowInvoice=data}" v-else />
     </div>
   </div>
 </template>
@@ -74,7 +74,17 @@
 import { mapState } from 'vuex'
 import citySelect from '@/components/citySelect'
 import invoices from '@/components/invoices'
-
+var cloneObj = function (obj) {
+  var newObj = {}
+  if (obj instanceof Array) {
+    newObj = []
+  }
+  for (var key in obj) {
+    var val = obj[key] || ''
+    newObj[key] = typeof val === 'object' ? cloneObj(val) : val
+  }
+  return newObj
+}
 export default {
   components: {
     citySelect,
@@ -92,6 +102,14 @@ export default {
         let condition = state.user.invoice2 && state.user.invoice2 !== 'null' && type !== '[object Array]'
         return (condition ? JSON.parse(state.user.invoice2) : {})
       },
+      editInvoice2: state => {
+        let type = Object.prototype.toString.call(state.user.invoice2)
+        if (type === '[object Object]') {
+          return state.user.invoice2
+        }
+        let condition = state.user.invoice2 && state.user.invoice2 !== 'null' && type !== '[object Array]'
+        return cloneObj(condition ? JSON.parse(state.user.invoice2) : {})
+      },
       invoice3: state => {
         let type = Object.prototype.toString.call(state.user.invoice3)
         if (type === '[object Object]') {
@@ -101,7 +119,16 @@ export default {
 
         return (condition ? JSON.parse(state.user.invoice3) : {})
       },
-      address: state => state.user.address || {}
+      editInvoice3: state => {
+        let type = Object.prototype.toString.call(state.user.invoice3)
+        if (type === '[object Object]') {
+          return state.user.invoice3
+        }
+        let condition = state.user.invoice3 && state.user.invoice3 !== 'null' && type !== '[object Array]'
+        return cloneObj(condition ? JSON.parse(state.user.invoice3) : {})
+      },
+      address: state => state.user.address || {},
+      editAdd: state => cloneObj(state.user.address) || {}
     })
   },
   data () {
@@ -115,40 +142,12 @@ export default {
     getCurrentStatus (data) {
       this.tempSelect = data
     },
-    uAddress () {
-      this.address.province = this.tempSelect[0]
-      this.address.city = this.tempSelect[1]
-      this.address.shipAreaPath = this.tempSelect.join(',')
-      let {
-        shipAddress,
-        shipAreaPath,
-        province,
-        city,
-        shipMobile,
-        shipName
-      } = this.address
-      let params = {
-        shipAddress,
-        shipAreaPath,
-        province,
-        city,
-        shipMobile,
-        shipName
-      }
-      this.$http
-        .post('/user/updateAddress', params, {
-          headers: {
-            token: this.token
-          }
-        })
-        .then(data => {
-          let res = data.data
-          this.addressStatus = true
-          localStorage.setItem('address', JSON.stringify(res.data))
-        })
-    },
     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: {

+ 18 - 7
src/pages/account/manage/myscene/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="scene-layout">
     <template v-if="total">
-      <div class="items" @click="goto(item.webSite)" v-for="(item,i) in myscene.list" :key="i">
+      <div class="items" @click="(item.status === 1||item.status===-2) && goto(item.webSite)" v-for="(item,i) in myscene.list" :key="i">
         <div class="card-img" :style="{backgroundImage: `url(${item.thumb||`${$cdn}images/default.png`})`}"></div>
         <div class="item-txt">
           <!-- <p>{{typeArr[item.sceneType]}}</p> -->
@@ -10,17 +10,17 @@
           <div class="btm-opr">
             <div class="btm-left">
               <img :src="`${$cdn}images/eye.png`" alt>
-              <span>{{item.sceneScheme===4?'Pro':'Lite'}}</span>
+              <span>{{item.sceneScheme>=4?'Pro':'Lite'}}</span>
             </div>
-            <div class="btm-right">编辑</div>
+            <div class="btm-right" @click.stop="(item.status === 1||item.status===-2) && gotoEdit(item.webSite)">编辑</div>
           </div>
         </div>
       </div>
     </template>
     <div class="scene-nothing" v-else>
-        <img src="@/assets/images/nothing.png" alt="">
-        <div>暂无任何场景,赶紧去拍摄吧。</div>
-      </div>
+      <img src="@/assets/images/nothing.png" alt="">
+      <div>暂无任何场景,赶紧去拍摄吧。</div>
+    </div>
     <div class="paging" v-if="total">
       <Paging @clickHandle="pageChange" :current="currentPage" :total="total" :equable="pageSize"/>
     </div>
@@ -63,7 +63,18 @@ export default {
   },
   methods: {
     goto (url) {
-      location.href = url.replace('http://', 'https://')
+      let temp = url.replace('show.html', 'showApp.html')
+      let temp1 = temp.replace('showProPC.html', 'showProMobile.html')
+      location.href = temp1.replace('http://', 'https://')
+    },
+    gotoEdit (url) {
+      if (url.indexOf('www') !== -1) {
+        return
+      }
+      let temp = url.replace('http://', 'https://')
+      let temp1 = temp.replace('showProPC.html', 'showProMobile.html')
+      // console.log(temp1)
+      window.open(temp1.replace('show', 'edit'), '_blank')
     },
     async del (item) {
       this.$toast.showConfirm('warn', '确定要删除当前场景吗?', async () => {

+ 3 - 3
src/pages/account/manage/myscene/style.scss

@@ -25,9 +25,9 @@
       border-bottom: none;
     }
     .card-img{
-      width: 138px;
-      min-width: 138px;
-      height: 121px;
+      width: 165px;
+      min-width: 165px;
+      height: 100px;
       cursor: pointer;
       background-position: center;
       background-size: auto 100%;

+ 130 - 0
src/pages/account/manage/openInvoice/index.vue

@@ -0,0 +1,130 @@
+<template>
+  <div class="i-layout">
+    <div class="address-con">
+      <createInvoice class="address-scon" />
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+import invoices from '@/components/invoices'
+import createInvoice from '@/components/createInvoice'
+
+export default {
+  components: {
+    invoices,
+    createInvoice
+  },
+  data () {
+    return {
+
+    }
+  },
+  computed: {
+    ...mapState({
+      address: state => state.user.address || {}
+    })
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.i-layout{
+  margin-top: 10px;
+  .address-input-con{
+    padding: 16px 0 0;
+    font-size: 12px;
+    line-height: 1.5;
+    color: rgba(0, 0, 0, 0.65);
+    .address-input-item{
+      display: flex;
+      margin-bottom:8px;
+
+      .address-sub{
+        width: 100%;
+        .top-title{
+          overflow: hidden;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+          color: rgba(0, 0, 0, 0.85);
+          padding: 0 0 8px;
+          margin: 0;
+          display: block;
+          text-align: left;
+          line-height: 1.5;
+          &::before{
+            display: inline-block;
+            margin-right: 4px;
+            content: "*";
+            font-family: SimSun;
+            line-height: 1;
+            font-size: 12px;
+            color: #f04134;
+          }
+        }
+      }
+      .address-name,.prov-name{
+        width: 33.33%;
+        padding-right:4px;
+        flex-shrink: 0;
+      }
+      .prov-name{
+        width: 50%;
+      }
+      .address-phone,.city-name{
+        flex: auto;
+      }
+
+    }
+    .bc-item{
+      padding: 16px;
+      margin: 8px 0;
+      background-size: 18px 32px;
+      background-repeat: no-repeat;
+      background-position: left 16px top 16px;
+      border: 1px solid #1fe4dc;
+      position: relative;
+      background-color: #f6f9ff;
+      overflow-wrap: break-word;
+      .bc-contact{
+        font-size: 12px;
+        color: rgba(0,0,0,.7);
+        line-height: 18px;
+
+      }
+      .bc-locotion{
+        font-size: 10px;
+        color: rgba(0,0,0,.45);
+        line-height: 12px;
+      }
+      .bc-edit{
+        position: absolute;
+        top: 16px;
+        right: 16px;
+        font-size: 12px;
+        color: rgba(0,0,0,.7);
+        line-height: 18px;
+      }
+    }
+    .p-dec{
+      line-height:32px;
+      margin-bottom: 8px;
+    }
+  }
+  .address-con{
+    .sub-title{
+      font-size: 14px;
+      line-height: 21px;
+      font-weight: 700;
+      padding: 13px 16px;
+      border-bottom: 1px solid #e9e9e9;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+    }
+    .address-scon{
+    }
+  }
+}
+</style>

+ 1 - 1
src/pages/account/manage/order/index.vue

@@ -30,7 +30,7 @@
               </div>
             </template>
             <template v-else-if="getStatus(item) === 'shipped'">
-              <span class="expreeNum">物流单号:77110342778758</span>
+              <span class="expreeNum">物流单号:{{item.orderItems[0].expressNum}}</span>
             </template>
             <template v-else-if="getStatus(item) === 'unshipped'">
               <span class="expreeNum">等待商家发货</span>

+ 2 - 2
src/pages/account/manage/order/style.scss

@@ -34,7 +34,7 @@
     }
     .o-con{
       margin: 16px 0;
-      padding: 0 24px 0 45px;
+      padding: 0 24px 0 25px;
       display: flex;
       justify-content: space-between;
       align-items: center;
@@ -46,7 +46,7 @@
         display: flex;
         align-items: center;
         img{
-          width: 20px;
+          width: 55px;
           margin-right: 25px;
         }
       }

+ 64 - 0
src/pages/account/manage/style.scss

@@ -1,3 +1,4 @@
+$theme-color: #1fe4dc;
 
 .manage-layout{
   background: #f6f9fd;
@@ -13,5 +14,68 @@
     display: flex;
     justify-content: space-between;
     align-items: center;
+    .btns{
+      font-size: 14px;
+      color: $theme-color;
+      border: 1px solid $theme-color;
+      height: 30px;
+      line-height: 30px;
+      padding: 0 10px;
+      box-sizing: border-box;
+      border-radius: 2px;
+    }
+    .select{
+      position: relative;
+      min-width: 20%;
+      font-size: 14px;
+      font-weight: normal;
+      .s-sub{
+        position: absolute;
+        top: 48px;
+        box-shadow: 1px 1px 5px rgba($color: #000000, $alpha: 0.5);
+        left: -10%;
+        background: #fff;
+        width: 120%;
+        max-height: 0;
+        transition: 0.3s all ease;
+        overflow: hidden;
+        z-index: 999;
+        .s-item{
+          text-align: center;
+          height: 30px;
+          line-height: 30px;
+        }
+        .item-active{
+          background: #f2f2f2;
+        }
+      }
+      .s-active{
+        max-height: 100px;
+      }
+      select{
+        background: #fff;
+        display: inline-block;
+        width:100%;  
+        appearance:none;  
+        -moz-appearance:none;  
+        -webkit-appearance:none;  
+        border: 0;
+        color:#666;  
+        outline:none;
+        padding-right: 20%;
+      }
+      &::after{
+        position: absolute;
+        right: 0;
+        top: 50%;
+        transform: translateY(calc(-50% + 2px));
+        content: '';
+        width: 0;
+        height: 0;
+        border: 4px solid;
+        display: inline-block;
+        border-color: #000 transparent transparent;
+      }
+    }
   }
 }

+ 5 - 2
src/pages/account/manage/submit/index.vue

@@ -111,7 +111,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
@@ -125,6 +125,7 @@ export default {
   computed: {
     ...mapState({
       token: state => state.user.token || '',
+      language: state => state.language.current,
       payinfo: state => {
         let type = Object.prototype.toString.call(state.user.payinfo)
         if (type === '[object Object]') {
@@ -150,7 +151,9 @@ export default {
         goods,
         receiver,
         invoice,
-        payType
+        payType,
+        abroad: this.language === 'en' ? 1 : 0
+
       }
       let res = await this.$http
         .post('user/order/placeOrder', params, {

+ 38 - 4
src/pages/account/register/index.vue

@@ -8,11 +8,22 @@
     <div class="login-con">
       <div class="input-con" :class="{inputActive:inputActive==='nickname'}">
         <img :src="`${$cdn}images/icon/icon-user@2x.png`" alt="">
-        <input oninput="value=value.replace(/[^\d]/g,'')" maxlength='11' v-model="nickname" @focus="inputActive='nickname'" @blur="blurHandle" type="text" placeholder="昵称">
+        <input v-model="nickname" @focus="inputActive='nickname'" @blur="blurHandle" type="text" placeholder="昵称">
       </div>
       <div class="input-con" :class="{inputActive:inputActive==='phone'}">
         <img :src="`${$cdn}images/icon/icon-phone@2x.png`" alt="">
-        <input v-model="phone" @focus="inputActive='phone'" @blur="blurHandle" type="text" placeholder="手机">
+        <div class="phone-select" ref="quhaoMenu">
+          <div @click="showSelect=!showSelect">
+            <span>{{codeActive[1]}}</span>
+            <img :src="`${$cdn}images/quhao-jiantou.png`" >
+          </div>
+          <ul v-show="showSelect" >
+            <li @click="selectItem(item)" v-for="(item,i) in selectCall" :key="i">
+              {{item[0]}}{{item[1]}}
+            </li>
+          </ul>
+        </div>
+        <input oninput="value=value.replace(/[^\d]/g,'')" v-model="phone" @focus="inputActive='phone'" @blur="blurHandle" type="text" placeholder="手机">
       </div>
       <div class="code-con">
         <div class="input-con" :class="{inputActive:inputActive==='code'}">
@@ -46,9 +57,13 @@
 </template>
 
 <script>
+import selectCall from '../country.js'
+
 export default {
   data () {
     return {
+      showSelect: false,
+      codeActive: ['中国', '+86', 'China'],
       nickname: '',
       phone: '',
       authCode: '',
@@ -58,9 +73,19 @@ export default {
       interTime: 60,
       jishi: false,
       interl: null,
+      selectCall,
       isAgree: true
     }
   },
+  mounted () {
+    document.addEventListener('click', (e) => {
+      if (this.$refs.quhaoMenu) {
+        if (!this.$refs.quhaoMenu.contains(e.target)) {
+          this.showSelect = false
+        }
+      }
+    })
+  },
   methods: {
     blurHandle () {
       this.inputActive = ''
@@ -69,8 +94,15 @@ export default {
         document.querySelector('#app').style.height = '100%'
       }, 20)
     },
+    selectItem (item) {
+      this.showSelect = false
+      this.codeActive = item
+    },
     async getAuthCode () {
-      let res = await this.$store.dispatch('getAuthCode', this.phone)
+      let res = await this.$store.dispatch('getAuthCode', {
+        phone: this.phone,
+        code: Number(this.codeActive[1].substr(1))
+      })
       if (res) {
         this.interl && clearInterval(this.interl)
         this.interl = null
@@ -90,12 +122,14 @@ export default {
       if (!this.isAgree) {
         return this.$toast.show('warn', '请查阅并同意四维看看条款')
       }
+      let country = Number(this.codeActive[1].substr(1))
+
       let params = {
         password: this.password,
         phoneNum: this.phone,
         msgAuthCode: this.authCode,
         nickName: this.nickname,
-        country: '中国',
+        country,
         confirmPwd: this.confirmPass
       }
       let res = await this.$http({

+ 38 - 1
src/pages/account/register/style.scss

@@ -3,7 +3,6 @@ input[type='password']{
   border: 0;
   outline: 0;
   height: 48px;
-  line-height: 48px;
   padding-right: 16px;
   padding-left: 12px;
   font-size: 14px;
@@ -26,6 +25,44 @@ input[type='password']{
   font-size: 16px;
   color: rgba(0, 0, 0, 0.7);
 }
+.phone-select{
+  &>div{
+    height: 18px;
+    border-right: 1px solid #f1f1f1;
+    &>span{
+      display: inline-block;
+      vertical-align: middle;
+    }
+  }
+  img{
+    width: 10px!important;
+    margin: 0 12px!important;
+    vertical-align: middle!important;
+  }
+  ul{
+    position: absolute;
+    top: 0;
+    left: 0;
+    background: #fff;
+    width: 200px;
+    height: 220px;
+    padding: 0 10px;
+    overflow: auto;
+    transition: ease 0.3s all;
+    z-index: 888;
+    box-shadow: 0px 1px 8px #ddd;
+    li{
+      height: 40px;
+      line-height: 50px;
+      color: #999;
+      font-size: 14px;
+      cursor: pointer;
+      &:hover{
+        color: #000;
+      }
+    }
+  }
+}
 .register-layout{
   width: 100%;
   .banner{

+ 20 - 12
src/pages/cases/index.vue

@@ -24,17 +24,23 @@
       </div>
     </div>
     <div class="cases">
-      <div class="item" v-for="(item,index) in scene" :key="index" @click="goto(item.webSite)">
-         <img :src="item.thumb||`${$cdn}images/default.png`" alt>
-         <div class="c-title">
-            <span>{{item.sceneName}}</span>
-            <div>
-              <img :src="`${$cdn}images/eye.png`" alt>
-              <span>{{item.sceneScheme===4?'Pro':'Lite'}}</span>
-            </div>
-         </div>
-         <p class="b-text3">作者:{{item.nickName}}</p>
-         <p class="b-text3">查看次数:{{item.viewCount}}</p>
+      <template v-if="scene.length>0">
+        <div class="item" v-for="(item,index) in scene" :key="index" @click="goto(item.webSite)">
+          <img :src="item.thumb||`${$cdn}images/default.png`" alt>
+          <div class="c-title">
+              <span>{{item.sceneName}}</span>
+              <div>
+                <img :src="`${$cdn}images/eye.png`" alt>
+                <span>{{item.sceneScheme>=4?'Pro':'Lite'}}</span>
+              </div>
+          </div>
+          <p class="b-text3">作者:{{item.nickName}}</p>
+          <p class="b-text3">查看次数:{{item.viewCount}}</p>
+        </div>
+      </template>
+      <div class="scene-nothing" v-else>
+        <img src="@/assets/images/nothing.png" alt="">
+        <div>暂无场景</div>
       </div>
     </div>
     <div class="paging" v-if="total">
@@ -119,7 +125,9 @@ export default {
       this.currentPage = data
     },
     goto (url) {
-      location.href = url.replace('http://', 'https://')
+      let temp = url.replace('show.html', 'showApp.html')
+      let temp1 = temp.replace('showProPC.html', 'showProMobile.html')
+      location.href = temp1.replace('http://', 'https://')
     },
     async getData () {
       document.querySelector('#app').scrollTo(0, 0)

+ 11 - 3
src/pages/cases/style.scss

@@ -1,4 +1,15 @@
 .cases-con{
+  .scene-nothing{
+    text-align: center;
+    padding:30px 0;
+    img{
+      padding-bottom: 22px;
+    }
+    div{
+      font-size: 16px;
+      color: #969696;
+    }
+  }
   .nav-hot{
     .list-navs{
       width: 90%;
@@ -28,9 +39,6 @@
       .select{
         position: relative;
         min-width: 23%;
-        span{
-
-        }
         .s-sub{
           position: absolute;
           top: 24px;

+ 1 - 1
src/pages/eight/index.vue

@@ -146,7 +146,7 @@ export default {
       params,
       params2,
       wh,
-      runLineCanvas: false,
+      runLineCanvas: true,
       case1: {
         content: require('@/assets/video/8k.mp4'),
         back: require('@/assets/video/4k.mp4'),

+ 13 - 0
src/pages/introduce/index.vue

@@ -0,0 +1,13 @@
+<template>
+ <div></div>
+</template>
+
+<script>
+
+export default {
+}
+</script>
+
+<style lang="scss" scoped>
+@import './style.scss';
+</style>

+ 0 - 0
src/pages/introduce/style.scss


+ 57 - 0
src/pages/introtow/index.vue

@@ -0,0 +1,57 @@
+<template>
+ <div class="introtow-layout">
+   <div class="it-header it-txt">
+     <p>ID:asdasd</p>
+     <p>剩余点数:2000</p>
+   </div>
+   <div class="point-list it-txt">
+     <p>限时抢购点数包</p>
+     <p>购买立即生效</p>
+     <div class="card-scroll">
+       <div class="card-item" v-for="(item,i) in 3" :key="i">
+         <div></div>
+         <p>小号点数包</p>
+         <p>¥<span>539</span><i>¥600</i></p>
+         <p class="p-tag">限时活动</p>
+       </div>
+     </div>
+   </div>
+   <div class="point-qa">
+     <div class="qa-item" v-for="(item,i) in qa" :key="i">
+       <p>{{item.q}}</p>
+       <p>{{item.a}}</p>
+     </div>
+   </div>
+ </div>
+</template>
+
+<script>
+
+export default {
+
+  data () {
+    let qa = [
+      {
+        q: '为什么需要点数充值?',
+        a: '当您的基础点数不足99点时,最新拍摄的场景将无法生成,通过购买点数则可以计算存储更多场景。'
+      }, {
+        q: '点数充值之后还可以退款吗?',
+        a: '不可以,因为点数充值之后,相应点数会立即到账生效,所以不接受中途退款,敬请谅解。'
+      }, {
+        q: '删除场景后会返还点数吗?',
+        a: '点数充值没有有效期,所以消费后代表永久记录您的美好空间,删除场景后不会返还。'
+      }, {
+        q: '点数不足还可继续拍摄上传吗?',
+        a: '点数不足时,不影响设备正常的拍摄,但会无法上传计算,这时只能进行删除操作;直到您的点数满足消费,此时您才可以将拍摄的场景上传计算,随之可查看、编辑和分享。'
+      }
+    ]
+    return {
+      qa
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import './style.scss';
+</style>

+ 84 - 0
src/pages/introtow/style.scss

@@ -0,0 +1,84 @@
+.introtow-layout{
+  .it-header{
+    height: 74px;
+    padding: 18px 0 23px;
+  }
+  .it-txt{
+    &>p{
+      margin-bottom: 6px;
+      padding-left: 10px;
+      color: #969696;
+      font-size: 12px;
+      &:first-child{
+        font-weight: bold;
+        font-size: 16px;
+        color: #2d2d2d;
+      }
+    }
+  }
+  .point-list{
+    background-color: #f7f7f7;
+    padding: 15px 0;
+    &>p{
+      &:first-child{
+        font-size: 18px;
+      }
+    }
+    .card-scroll{
+      overflow-y: hidden;
+      overflow-x: scroll;
+      white-space: nowrap;
+      margin-left: 12px;
+      &::-webkit-scrollbar{
+        display: none;
+      }
+      .card-item{
+        width: 135px;
+        display: inline-block;
+        background-color: #fff;
+        margin-right: 8px;
+        padding: 12px;
+        .p-tag{
+          background-color: #ffe8e8;
+          display: inline-block;
+          color: #f04c42;
+          font-size: 10px;
+          padding: 2px 4px;
+          border-radius: 4px;
+          margin-bottom: 0;
+        }
+        p{
+          font-size: 14px;
+          font-weight: bold;
+          margin-bottom: 6px;
+          span{
+            font-size: 20px;
+          }
+          i{
+            color: #ccc;
+            font-size: 10px;
+            text-decoration: line-through;
+            margin-left: 4px;
+          }
+        }
+      }
+    }
+  }
+  .point-qa{
+    padding: 12px;
+    .qa-item{
+      p{
+        font-size: 12px;
+        margin-bottom: 10px;
+        color: #969696;
+        line-height: 1.5;
+        &:first-child{
+          color: #2d2d2d;
+          font-weight: bold;
+          font-size: 14px;
+          margin-bottom: 6px;
+        }
+      }
+    }
+  }
+}

+ 11 - 3
src/pages/layout/header.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="header-layout" >
-    <div class="h-left" @touchend="active = !active">
+    <div class="h-left" @click="active = !active">
       <div class="l-con" :class="{active:active}" >
         <span class="l1"></span>
         <span class="l2"></span>
@@ -17,7 +17,7 @@
         <i class="iconfont icon-sousuo" @click="()=>{searchActive = true;active = false}"></i>
       </div>
       <div class="h-user" v-else-if="isAccout">
-          <i class="iconfont icon-cart" @click="$router.push({path:'/cart'})"><span>{{count}}</span></i>
+          <i class="iconfont icon-cart" @click="$router.push({path:'/cart'})"><span>{{count>99?'99+':count}}</span></i>
           <img ref="userList" :src="`${$cdn}images/icon/nav_icon.png`" @click="userList=!userList" alt="">
         <ul :class="{'ul-active':userList}" >
           <li v-for="(item,i) in manage" :key="i" @click="handleClick(item)">{{item.name}}</li>
@@ -118,6 +118,14 @@ export default {
         to: {path: '/myscene'}
       },
       {
+        name: '我的设备',
+        to: {path: '/device'}
+      },
+      {
+        name: '消费记录',
+        to: {path: '/consumption'}
+      },
+      {
         name: '修改密码',
         to: {path: '/change'}
       },
@@ -148,7 +156,7 @@ export default {
     },
     searchTxt (newVal) {
       if (newVal) {
-        this.getData()
+        this.currentPage === 1 ? this.getData() : this.currentPage = 1
       } else {
         this.scene = []
       }

+ 5 - 7
src/pages/layout/style.scss

@@ -19,8 +19,6 @@ $bannerHeight:60px;
   background-color: #1fe4dc;
 }
 .header-layout {
-  position: fixed;
-  box-sizing: content-box;
   z-index: 9999;
   background-color: #101010;
   display: flex;
@@ -29,7 +27,6 @@ $bannerHeight:60px;
   align-items: center;
   padding: 0 10px;
   width: 100%;
-  box-sizing: border-box;
   .h-left {
     width: 40px;
     height: $bannerHeight;
@@ -110,7 +107,7 @@ $bannerHeight:60px;
         }
       }
       .ul-active{
-        max-height: 150px;
+        max-height: 250px;
       }
       img{
         width: 50%;
@@ -131,9 +128,9 @@ $bannerHeight:60px;
           text-align: center;
           li{
             padding: 0 11px;
-            line-height: 30px;
-            height: 30px;
-            font-size: 12px;
+            line-height: 32px;
+            height: 32px;
+            font-size: 14px;
             color: rgba(0, 0, 0, 0.7);
           }
        }
@@ -275,6 +272,7 @@ $bannerHeight:60px;
   }
 
   .nav-active {
+    z-index: 9999;
     position: absolute;
     top: $bannerHeight;
     width: 100%;

+ 1 - 1
src/pages/location/index.vue

@@ -2,7 +2,7 @@
   <div class="home-layout">
     <div class="plate01">
       <div class="fdkk-pro">
-        <img :style="{marginTop:language==='en'?'136px':'64px'}" :src="`${$cdn}images/hxjs-model.png`" alt="">
+        <img :src="`${$cdn}images/hxjs-model.png`" alt="">
         <div class="pulse" v-for="(item,i) in langCoreTech.kjdw.points" :style="item.posi" :key="i"></div>
       </div>
       <div class="title">

+ 1 - 1
src/pages/location/style.scss

@@ -51,7 +51,7 @@
       position: relative;
       padding-top: 80px;
       img {
-        margin-top: 136px;
+        margin-top: 64px;
         width: 100%;
       }
       .pulse {

+ 12 - 0
src/pages/privilege/index.vue

@@ -0,0 +1,12 @@
+<template>
+ <div></div>
+</template>
+
+<script>
+
+export default {
+}
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 17 - 64
src/pages/purchase/index.vue

@@ -2,50 +2,47 @@
   <div class="purchase-layout">
     <div class="plate01">
       <div class="top">
-        <span @touchend="$router.push({name:'eight'})">概览</span>
-        <span @click="scrollTo('jsgg')">技术规格</span>
+        <span @click="$router.push({name:'eight'})">{{langPurchase.top1}}</span>
+        <span @click="scrollTo('jsgg')">{{langPurchase.top2}}</span>
       </div>
       <div class="main-layout">
         <img class="pro" :src="`${$cdn}images/banner_pro.png`" alt="">
         <div class="txt-con">
           <img class="p-logo" :src="`${$cdn}images/pro-logo-m.png`" alt="">
-          <div class="p-label">15分钟快速建模,全自动生成空间模型,实时计算空间尺寸,10K分辨率,支持4倍放大</div>
-          <div class="p-price">RMB 9,800</div>
+          <div class="p-label" v-html="langPurchase.dec"></div>
+          <div class="p-price">{{langPurchase.price}}</div>
         </div>
         <div class="attr-con">
-          <div class="attr">颜色</div>
+          <div class="attr">{{langPurchase.color.key}}</div>
           <div class="box color">
             <i class="iconfont icon-yuandian"></i>
-            静谧黑</div>
-          <div class="attr">服务</div>
+            {{langPurchase.color.val}}</div>
+          <div class="attr">{{langPurchase.service.key}}</div>
           <div class="box service">
             <ul>
-              <li>数据永久存储</li>
-              <li>高速上传计算队列</li>
-              <li>场景分享、热点编辑隐私</li>
+              <li v-for="(item,i) in langPurchase.service.val1" :key="i" v-html="item"></li>
             </ul>
             <span class="line"></span>
             <ul>
-              <li>多种个性化功能</li>
-              <li>附送30G终身容量</li>
+              <li v-for="(item,i) in langPurchase.service.val2" :key="i" v-html="item"></li>
             </ul>
           </div>
-          <div class="attr">赠品</div>
+          <div class="attr">{{langPurchase.gift.key}}</div>
           <div class="box zhijia">
             <img :src="`${$cdn}images/zhijia.png`" alt>
-            <span>官方拍摄支架 x 1</span>
+            <span>{{langPurchase.gift.val}}</span>
           </div>
-          <div class="attr">数量</div>
+          <div class="attr">{{langPurchase.count.key}}</div>
           <spinner class="count" @count='handleNum' />
-          <div class="btn" @click="addcart">立即购买</div>
+          <div class="btn" @click="addcart">{{langPurchase.buy}}</div>
           <div class="dec">* 付款成功后5个工作日内发货,默认顺丰快递包邮</div>
         </div>
       </div>
     </div>
     <div class="plate02" ref="jsgg">
-      <div class="p2-name">{{parmas.name}}</div>
+      <div class="p2-name">{{langPurchase.parmas.name}}</div>
       <div class="p2-pramas">
-        <div v-for="(item,i) in parmas.detail" :key="i">
+        <div v-for="(item,i) in langPurchase.parmas.detail" :key="i">
           <p class="title">{{item.label}}</p>
           <div class="name">{{item.name}}</div>
           <div class="detail" >
@@ -71,56 +68,12 @@ export default {
   },
   computed: {
     ...mapState({
-      token: state => state.user.token
+      token: state => state.user.token,
+      langPurchase: state => state.language.home.purchase
     })
   },
   data () {
-    let parmas = {
-      name: '技术规格',
-      detail: [
-        {
-          label: '型号',
-          dec: [
-            '高度: 141.5毫米 / ',
-            '宽度: 71.1mm / ',
-            '厚度:17.98mm',
-            '<br/>重量:115g'
-          ]
-        }, {
-          label: '材质',
-          name: '',
-          dec: [
-            '钛金属 / ',
-            '磨砂背']
-        }, {
-          label: '摄像头',
-          name: '',
-          dec: ['f / 2.0 大光圈镜头 / ', '3200万像素SONY sensor / ', '220°双鱼眼镜头 / ', '9片8组光学镜头 / ', '3K视频录制速度为30fps']
-        }, {
-          label: '连接',
-          name: '蓝牙:5.0',
-          dec: ['WiFi / ', 'WiFi:802.11a / b / g / n / ac']
-        }, {
-          label: '电池',
-          name: '',
-          dec: ['3040mAh / ', '通过USB快速充电']
-        }, {
-          label: '存储',
-          name: '',
-          dec: ['支持128G TF卡 / ', '3K视频 录制120分钟']
-        }, {
-          label: '端口',
-          name: '',
-          dec: ['microUSB / ', '三脚架固定孔']
-        }, {
-          label: '防水防尘',
-          name: '',
-          dec: ['IP54']
-        }
-      ]
-    }
     return {
-      parmas,
       count: 1
     }
   },

+ 1 - 0
src/pages/purchase/style.scss

@@ -88,6 +88,7 @@
           ul{
             display: inline-block;
             vertical-align: top;
+            width: 40%;
             &:last-child{
               float: right;
               margin-left: 20px;

+ 17 - 19
src/pages/purchasetwo/index.vue

@@ -2,50 +2,47 @@
   <div class="purchase-layout">
     <div class="plate01">
       <div class="top">
-        <span @touchend="$router.push({name:'eight'})">概览</span>
-        <span @click="scrollTo('jsgg')">技术规格</span>
+        <span @click="$router.push({name:'binocular'})">{{langPurchase.top1}}</span>
+        <span @click="scrollTo('jsgg')">{{langPurchase.top2}}</span>
       </div>
       <div class="main-layout">
         <img class="pro" :src="`${$cdn}images/t_product.png`" alt="">
         <div class="txt-con">
           <img class="p-logo" :src="`${$cdn}images/lite-logo-m.png`" alt="">
-          <div class="p-label">10分钟复刻空间,时间仅需传统设备的1/20,4K高清画质,实现沉浸式3D实景空间漫游</div>
-          <div class="p-price">RMB 3,999</div>
+          <div class="p-label"  v-html="langPurchase.dec"></div>
+          <div class="p-price">{{langPurchase.price}}</div>
         </div>
         <div class="attr-con">
-          <div class="attr">颜色</div>
+          <div class="attr">{{langPurchase.color.key}}</div>
           <div class="box color">
             <i class="iconfont icon-yuandian"></i>
-            静谧黑</div>
-          <div class="attr">服务</div>
+            {{langPurchase.color.val}}</div>
+          <div class="attr">{{langPurchase.service.key}}</div>
           <div class="box service">
             <ul>
-              <li>数据永久存储</li>
-              <li>高速上传计算队列</li>
-              <li>场景分享、热点编辑隐私</li>
+              <li v-for="(item,i) in langPurchase.service.val1" :key="i" v-html="item"></li>
             </ul>
             <span class="line"></span>
             <ul>
-              <li>多种个性化功能</li>
-              <li>附送30G终身容量</li>
+              <li v-for="(item,i) in langPurchase.service.val2" :key="i" v-html="item"></li>
             </ul>
           </div>
-          <div class="attr">赠品</div>
+          <div class="attr">{{langPurchase.gift.key}}</div>
           <div class="box zhijia">
             <img :src="`${$cdn}images/zhijia.png`" alt>
-            <span>官方拍摄支架 x 1</span>
+            <span>{{langPurchase.gift.val}}</span>
           </div>
-          <div class="attr">数量</div>
+          <div class="attr">{{langPurchase.count.key}}</div>
           <spinner class="count" @count='handleNum' />
-          <div class="btn" @click="addcart">立即购买</div>
+          <div class="btn" @click="addcart">{{langPurchase.buy}}</div>
           <div class="dec">* 付款成功后5个工作日内发货,默认顺丰快递包邮</div>
         </div>
       </div>
     </div>
     <div class="plate02" ref="jsgg">
-      <div class="p2-name">{{parmas.name}}</div>
+      <div class="p2-name">{{langPurchase.parmas.name}}</div>
       <div class="p2-pramas">
-        <div v-for="(item,i) in parmas.detail" :key="i">
+        <div v-for="(item,i) in langPurchase.parmas.detail" :key="i">
           <p class="title">{{item.label}}</p>
           <div class="name">{{item.name}}</div>
           <div class="detail" >
@@ -71,7 +68,8 @@ export default {
   },
   computed: {
     ...mapState({
-      token: state => state.user.token
+      token: state => state.user.token,
+      langPurchase: state => state.language.home.purchasetow
     })
   },
   data () {

+ 1 - 0
src/pages/purchasetwo/style.scss

@@ -86,6 +86,7 @@
           padding: 13px 12%;
           width: 100%;
           ul{
+            width: 40%;
             display: inline-block;
             vertical-align: top;
             &:last-child{

+ 39 - 0
src/router/index.js

@@ -12,6 +12,27 @@ let router = new Router({
       component: resolve => require(['@/pages/home'], resolve)
     },
     {
+      path: '/404',
+      name: '404',
+      component: resolve => require(['@/pages/404'], resolve)
+    },
+    {
+      path: '/introduce/:id',
+      name: 'introduce',
+      component: resolve => require(['@/pages/introduce'], resolve)
+    },
+    {
+      path: '/introtow/:id',
+      name: 'introtow',
+      component: resolve => require(['@/pages/introtow'], resolve)
+    },
+    {
+      path: '/privilege/:cameraId/:childName',
+      name: 'privilege',
+      component: resolve => require(['@/pages/privilege'], resolve)
+    },
+
+    {
       path: '/binocular',
       name: 'binocular',
       component: resolve => require(['@/pages/binocular'], resolve)
@@ -64,6 +85,24 @@ let router = new Router({
           meta: {requireAuth: true}
         },
         {
+          path: '/openInvoice',
+          name: 'openInvoice',
+          component: resolve => require(['@/pages/account/manage/openInvoice'], resolve),
+          meta: {requireAuth: true}
+        },
+        {
+          name: 'device',
+          path: '/device',
+          component: resolve => require(['@/pages/account/manage/device'], resolve),
+          meta: {requireAuth: true}
+        },
+        {
+          name: 'consumption',
+          path: '/consumption',
+          component: resolve => require(['@/pages/account/manage/consumption'], resolve),
+          meta: {requireAuth: true}
+        },
+        {
           name: 'order',
           path: '/order',
           component: resolve => require(['@/pages/account/manage/order'], resolve),

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

@@ -21,7 +21,7 @@ export default{
       name: '德国人工智能研究中心',
       txt: [
         '德国人工智能研究中心(DFKI)创立于1988年,是德国顶级的人工智能研究机构,也是目前世界上最大的非营利性人工智能研究机构,研究方向覆盖人工智能的主要产业方向,包括大数据分析、知识管理、画面处理和理解自然语言处理、人机交互、机器人。其股东包括Google、Intel、微软、宝马、SAP、Airbus在内的全球顶级科技企业。',
-        '德国人工智能研究中心CEO沃夫冈·瓦尔斯特尔(Wolfgang Wahlster)教授是德国总理默克尔的科技顾问,也是“工业4 . 0”构想发起者之一。中心旗下大约有900名科学家、研究人员及工程师,其中包括德国国家科学院、欧洲科学院、瑞士皇家科学院、德国自然与文学科学院、德国自然与工程科学院、柏林勃兰登堡自然与人类学科学院等知名科学院的院士。'
+        '德国人工智能研究中心CEO——沃夫冈·瓦尔斯特尔(Wolfgang Wahlster)教授是德国总理默克尔的科技顾问,也是“工业4 . 0”构想发起者之一。中心旗下大约有900名科学家、研究人员及工程师,其中包括德国国家科学院、欧洲科学院、瑞士皇家科学院、德国自然与文学科学院、德国自然与工程科学院、柏林勃兰登堡自然与人类学科学院等知名科学院的院士。'
       ],
       img: require('@/assets/images/DFKI.png')
     }

+ 2 - 6
src/store/language/cn/binocular.js

@@ -97,11 +97,11 @@ export default{
       }, {
         label: '连接',
         name: '蓝牙:5.0',
-        dec: ['WiFi / ', 'WiFi:802.11a / b / g / n / ac']
+        dec: ['WiFi:802.11a / b / g / n / ac']
       }, {
         label: '电池',
         name: '',
-        dec: ['3040mAh / ', '通过USB快速充电']
+        dec: ['2000mAh / ', '通过USB快速充电']
       }, {
         label: '存储',
         name: '',
@@ -110,10 +110,6 @@ export default{
         label: '端口',
         name: '',
         dec: ['microUSB / ', '三脚架固定孔']
-      }, {
-        label: '防水防尘',
-        name: '',
-        dec: ['IP54']
       }
     ]
   }

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

@@ -48,7 +48,7 @@ export default{
       }],
     ability: {
       name: 'AI数字化算法的创新技术能力',
-      sub: '全新算法极大提升了关键帧特征点的匹配准确率<br/>把定位丢失的情况降至最低。另外,基于自适应<br/>分段的集束调整,把长序列分成若干<br/>序列在后端优化,改善了优化效率',
+      sub: '计算相机在拍摄时的空间位置,并提取对应的3D点云,从而获取三维空间的真实情况。',
       app: [
         {
           icon: require('@/assets/images/img_core_app01.png'),
@@ -60,14 +60,14 @@ export default{
         },
         {
           icon: require('@/assets/images/img_core_app03.png'),
-          sub: '人工智能算法<br/>与环闭合配合运作<br/>使相机几何校准<br/>加快速稳定'
+          sub: '人工智能算法<br/>使相机几何校准<br/>加快速稳定'
         }
       ]
     }
   },
   kjjm: {
     title: '空间重建',
-    logon: '自动化高精度三维数字建技术,恢复空间的平面<br/>布局以及三维结构,无需人工干预从上传到生成结果<br/>仅需要5-10分钟。自动化高精度三维数字重建技术<br/>在获取稀疏点云和相机位姿后,计算空间的平面布局<br/>并恢复三维结构,生成3D场景',
+    logon: '自动化高精度三维数字建技术,恢复空间的平面<br/>布局以及三位结构,无需人工干预。',
     dec: ['自动化高精度三维数字建模技术', '恢复空间的平面布局以及三维结构', '无需人工干预,从上传到生成结果仅需要5-10分钟。'],
     chars: [
       {

+ 24 - 26
src/store/language/cn/eight.js

@@ -6,7 +6,7 @@ export default{
   introduce: {
     title: ['四维看看 Pro', '专业精准建模,高效复刻空间'],
     price: 'RMB 9,800',
-    dec: '15分钟快速三维重建,全自动生成数字3D空间,实时计算空间尺寸,10K分辨率,支持4倍放大',
+    dec: '15分钟快速三维重建,全自动生成数字3D空间,实时计算空间尺寸,12K分辨率,支持4倍放大',
     btn: '立即购买',
     subTitle: '让三维空间获得数字新生',
     benefitGroup: [
@@ -37,10 +37,10 @@ export default{
     sub: ['快速编辑和分享你的互动式视频', '分享你的空间故事']
   },
   definition: {
-    title: '10K高清画质<br/>捕捉空间的每个细节',
+    title: '12K高清画质<br/>捕捉空间的每个细节',
     top: {
-      dec: '四维看看Pro全方位记录空间信息,生成实景3D数字空间,让您走进3D场景,如临现场般自由探索。10K清晰度,可4倍放大画面,不错过任何细节。',
-      intro: '拍摄画面分辨率高达10000*5000像素'
+      dec: '四维看看Pro全方位记录空间信息,生成实景3D数字空间,让您走进3D场景,如临现场般自由探索。12K清晰度,可4倍放大画面,不错过任何细节。',
+      intro: '拍摄画面分辨率高达12288*6144像素'
 
     },
     bottom: {
@@ -92,7 +92,7 @@ export default{
         lTxt: '四维看看 Lite',
         rTxt: '四维看看 Pro',
         lMask: '4K高清',
-        rMask: '10K高清图像,4倍放大'
+        rMask: '12K高清图像,4倍放大'
       }
     },
     ranging: {
@@ -127,42 +127,40 @@ export default{
     detail: [
       {
         label: '型号',
+        name: '四维看看 Pro',
         dec: [
-          '高度: 141.5毫米 / ',
-          '宽度: 71.1mm / ',
-          '厚度:17.98mm',
-          '<br/>重量:115g'
+          '高度: 220.7毫米 / ',
+          '宽度: 78.2毫米 / ',
+          '厚度:78.2毫米'
         ]
       }, {
-        label: '材质',
+        label: '镜头',
         name: '',
         dec: [
-          '钛金属 / ',
-          '磨砂背']
+          '类型:200°鱼眼镜头 /  ',
+          '孔径:f/2.0 /  ',
+          '数量:8个 /  ',
+          '分辨率:4608*3456像素(每个);12288*6144像素(合计)']
       }, {
-        label: '摄像头',
+        label: '传感器',
         name: '',
-        dec: ['f / 2.0 大光圈镜头 / ', '3200万像素SONY sensor / ', '220°双鱼眼镜头 / ', '9片8组光学镜头 / ', '3K视频录制速度为30fps']
+        dec: ['范围:1/2.3英寸 / ', '数量:8个']
       }, {
-        label: '连接',
-        name: '蓝牙:5.0',
-        dec: ['WiFi / ', 'WiFi:802.11a / b / g / n / ac']
-      }, {
-        label: '电池',
+        label: '存储内存',
         name: '',
-        dec: ['3040mAh / ', '通过USB快速充电']
+        dec: ['16GB']
       }, {
-        label: '存储',
+        label: '电池',
         name: '',
-        dec: ['支持128G TF卡 / ', '3K视频 录制120分钟']
+        dec: ['7.4V 4200mAh / ', '可通过USB快速充电']
       }, {
-        label: '端口',
+        label: 'WiFi',
         name: '',
-        dec: ['microUSB / ', '三脚架固定孔']
+        dec: ['802.11a/b/g/n网络协议 / ', '支持2.4/5GHz通信']
       }, {
-        label: '防水防尘',
+        label: '设备接口',
         name: '',
-        dec: ['IP54']
+        dec: ['TYPE C']
       }
     ]
   }

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

@@ -107,7 +107,7 @@ export default{
       image: baseUrl + 'images/phone_9.jpg',
       icon: baseUrl + 'images/phone_icon_9.png',
       text: '伟星' },
-    {url: 'https://admin.4dmuseum.cn/showPC.html?m=333&bigScene&novr',
+    {url: 'https://admin.4dmuseum.cn/showApp.html?m=240&bigScene&novr',
       image: baseUrl + 'images/phone_10.jpg',
       icon: baseUrl + 'images/phone_icon_10.png',
       text: '武侯祠' }

+ 123 - 0
src/store/language/cn/purchase.js

@@ -0,0 +1,123 @@
+export default{
+  top1: '概览',
+  top2: '技术规格',
+  dec: '15分钟快速三维重建,全自动生成数字3D空间,实时计算空间尺寸,12K分辨率,支持4倍放大',
+  yushou: '【新品预售】',
+  price: 'RMB 9,800',
+  buy: '立即购买',
+  tiaokuan: '* 付款成功后5个工作日内发货,默认顺丰快递包邮',
+  guige: {
+    name: '技术规格',
+    dec: '注:本页面所列配置及参数均以实际上市产品为准,如有变更,恕不另行通知;',
+    arr: [
+      {
+        name: '机身尺寸',
+        val: ['高度:220.7毫米', '宽度:78.2毫米', '厚度:78.2毫米']
+      },
+      {
+        name: '镜头',
+        val: [
+          '类型:200°鱼眼镜头',
+          '孔径:f/2.0',
+          '数量:8个',
+          '分辨率:4608*3456像素(每个);12288*6144像素(合计)'
+        ]
+      },
+      {
+        name: '传感器',
+        val: ['范围:1/2.3英寸', '数量:8个']
+      },
+      {
+        name: '存储内存',
+        val: [
+          '16GB'
+        ]
+      },
+      {
+        name: '电池',
+        val: [
+          '7.4V 4200mAh',
+          '可通过USB快速充电'
+        ]
+      },
+      {
+        name: 'WiFi',
+        val: [
+          '802.11a/b/g/n网络协议',
+          '支持2.4/5GHz通信'
+        ]
+      },
+      {
+        name: '设备接口',
+        val: [
+          'TYPE C'
+        ]
+      }
+    ]
+  },
+  color: {
+    key: '颜色',
+    val: ' 静谧黑'
+  },
+  service: {
+    key: '服务',
+    val1: [
+      '数据永久存储',
+      '高速上传计算队列',
+      '场景分享、热点编辑、隐私加密'
+    ],
+    val2: [
+      '多种个性化功能',
+      '附送30G终身容量'
+    ]
+  },
+  gift: {
+    key: '赠品',
+    val: ' 官方拍摄支架 x 1'
+  },
+  count: {
+    key: '数量'
+  },
+  parmas: {
+    name: '技术规格',
+    detail: [
+      {
+        label: '型号',
+        name: '四维看看 Pro',
+        dec: [
+          '高度: 220.7毫米 / ',
+          '宽度: 78.2毫米 / ',
+          '厚度:78.2毫米'
+        ]
+      }, {
+        label: '镜头',
+        name: '',
+        dec: [
+          '类型:200°鱼眼镜头 /  ',
+          '孔径:f/2.0 /  ',
+          '数量:8个 /  ',
+          '分辨率:4608*3456像素(每个);12288*6144像素(合计)']
+      }, {
+        label: '传感器',
+        name: '',
+        dec: ['范围:1/2.3英寸 / ', '数量:8个']
+      }, {
+        label: '存储内存',
+        name: '',
+        dec: ['16GB']
+      }, {
+        label: '电池',
+        name: '',
+        dec: ['7.4V 4200mAh / ', '可通过USB快速充电']
+      }, {
+        label: 'WiFi',
+        name: '',
+        dec: ['802.11a/b/g/n网络协议 / ', '支持2.4/5GHz通信']
+      }, {
+        label: '设备接口',
+        name: '',
+        dec: ['TYPE C']
+      }
+    ]
+  }
+}

+ 113 - 0
src/store/language/cn/purchasetow.js

@@ -0,0 +1,113 @@
+export default{
+  top1: '概览',
+  top2: '技术规格',
+  dec: '10分钟复刻空间,时间仅需传统设备的1/20,4K高清画质,实现沉浸式3D实景空间漫游',
+  yushou: '【新品预售】',
+  price: 'RMB 3,999',
+  buy: '立即购买',
+  tiaokuan: '* 付款成功后5个工作日内发货,默认顺丰快递包邮',
+  guige: {
+    name: '技术规格',
+    dec: '注:本页面所列配置及参数均以实际上市产品为准,如有变更,恕不另行通知;',
+    arr: [
+      {
+        name: '机身尺寸',
+        val: ['高度:130mm', '宽度:47mm', '厚度:18mm', '重量:115g']
+      },
+      {
+        name: '材质',
+        val: [
+          '钛金属',
+          '磨砂背'
+        ]
+      },
+      {
+        name: '摄像头',
+        val: ['f / 2.0 大光圈镜头',
+          '3200万像素SONY sensor',
+          '220°双鱼眼镜头',
+          '9片8组光学镜头',
+          '3K视频录制速度为30fps']
+      },
+      {
+        name: '连接',
+        val: ['蓝牙:5.0', 'WiFi:802.11a / b / g / n / ac']
+      },
+      {
+        name: '电池',
+        val: ['2000mAh', '通过USB快速充电']
+      },
+      {
+        name: '存储',
+        val: ['支持128G TF卡', '3K视频 录制120分钟']
+      },
+      {
+        name: '端口',
+        val: ['microUSB', '三脚架固定孔']
+      }
+    ]
+  },
+  color: {
+    key: '颜色',
+    val: ' 静谧黑'
+  },
+  service: {
+    key: '服务',
+    val1: [
+      '数据永久存储',
+      '高速上传计算队列',
+      '场景分享、热点编辑、隐私加密'
+    ],
+    val2: [
+      '多种个性化功能',
+      '附送30G终身容量'
+    ]
+  },
+  gift: {
+    key: '赠品',
+    val: ' 官方拍摄支架 x 1'
+  },
+  count: {
+    key: '数量'
+  },
+  parmas: {
+    name: '技术规格',
+    detail: [
+      {
+        label: '型号',
+        dec: [
+          '高度: 141.5毫米 / ',
+          '宽度: 71.1毫米 / ',
+          '厚度:17.98毫米',
+          '<br/>重量:115g'
+        ]
+      }, {
+        label: '材质',
+        name: '',
+        dec: [
+          '钛金属 / ',
+          '磨砂背']
+      }, {
+        label: '摄像头',
+        name: '',
+        dec: ['f / 2.0 大光圈镜头 / ', '3200万像素SONY sensor / ', '220°双鱼眼镜头 / ', '9片8组光学镜头 / ', '3K视频录制速度为30fps']
+      }, {
+        label: '连接',
+        name: '蓝牙:5.0',
+        dec: ['WiFi:802.11a / b / g / n / ac']
+      }, {
+        label: '电池',
+        name: '',
+        dec: ['2000mAh / ', '通过USB快速充电']
+      }, {
+        label: '存储',
+        name: '',
+        dec: ['支持128G TF卡 / ', '3K视频 录制120分钟']
+      }, {
+        label: '端口',
+        name: '',
+        dec: ['microUSB / ', '三脚架固定孔']
+      }
+    ]
+  }
+}

+ 19 - 23
src/store/language/en/binocular.js

@@ -77,43 +77,39 @@ export default{
     name: 'Detailed Parameters of 4DKanKan Lite',
     detail: [
       {
-        label: '型号',
+        label: 'Model',
         dec: [
-          '高度: 130mm / ',
-          '宽度: 47mm / ',
-          '厚度:18mm',
-          '<br/>重量:115g'
+          'Height: 130mm / ',
+          'Width: 47mm / ',
+          'Depth: 18mm',
+          '<br/>Weight: 115g'
         ]
       }, {
-        label: '材质',
+        label: 'Fabric',
         name: '',
         dec: [
-          '钛金属 / ',
-          '磨砂背']
+          'Titanium / ',
+          'Matte surface']
       }, {
-        label: '摄像头',
+        label: 'Camera',
         name: '',
-        dec: ['f / 2.0 大光圈镜头 / ', '3200万像素SONY sensor / ', '220°双鱼眼镜头 / ', '9片8组光学镜头 / ', '3K视频录制速度为30fps']
+        dec: ['f / 2.0 aperture / ', '3200-pixels SONY sensor / ', '220° fisheye lens*2 / ', 'Optical lens*8 / ', '30fps recording speed in 3K']
       }, {
-        label: '连接',
-        name: '蓝牙:5.0',
-        dec: ['WiFi / ', 'WiFi:802.11a / b / g / n / ac']
+        label: 'Connection',
+        name: 'Bluetooth: 5.0',
+        dec: ['WiFi:802.11a / b / g / n / ac']
       }, {
-        label: '电池',
+        label: 'Battery',
         name: '',
-        dec: ['3040mAh / ', '通过USB快速充电']
+        dec: ['2000mAh / ', 'Quick charge through USB']
       }, {
-        label: '存储',
+        label: 'Storage',
         name: '',
-        dec: ['支持128G TF卡 / ', '3K视频 录制120分钟']
+        dec: ['128G Trans-flash Card / ', '120-minutes 3K video']
       }, {
-        label: '端口',
+        label: 'Interface',
         name: '',
-        dec: ['microUSB / ', '三脚架固定孔']
-      }, {
-        label: '防水防尘',
-        name: '',
-        dec: ['IP54']
+        dec: ['microUSB / ', 'Tripod attachment hole']
       }
     ]
   }

+ 2 - 2
src/store/language/en/coreTech.js

@@ -48,7 +48,7 @@ export default{
       }],
     ability: {
       name: 'The Innovative technology of AI Digitization',
-      sub: 'The new algorithm has significantly enhanced the matches of feature points, thus reducing the localization loss to the lowest level. Further, bundle adjustment based on self-adaptive segmentation divides long sequences into several sequences and optimizes it in the back end, thus improving the optimization efficiency.',
+      sub: 'Calculate camera locations and obtain corresponding 3Dpoint clouds to understand real-life environment.',
       app: [
         {
           icon: require('@/assets/images/img_core_app01.png'),
@@ -67,7 +67,7 @@ export default{
   },
   kjjm: {
     title: 'Space reconstruction',
-    logon: '自动化高精度三维数字重建技术,在获取稀疏点云和相机位姿后,计算空间的平面布局<br/>并恢复三维结构,生成3D场景。',
+    logon: 'Automatic and precise 3D digitization technology that recovers floorplan and 3D structure of space without manual intervention.',
     dec: ['Automatic and precise 3D digitization technology that recovers floorplan and 3D structure of space without manual intervention, which takes only 5 to 10 minutes to generate the result.'],
     chars: [
       {

+ 26 - 28
src/store/language/en/eight.js

@@ -6,7 +6,7 @@ export default{
   introduce: {
     title: ['四维看看 Pro', '专业精准建模,高效复刻空间'],
     price: 'RMB 9,800',
-    dec: '4DKanKan Pro generates 3D digital model of space automatically and takes measurements in real time. Results are displayed in 10K definition, and allow 4x magnification.',
+    dec: '4DKanKan Pro generates 3D digital model of space automatically and takes measurements in real time. Results are displayed in 12K definition, and allow 4x magnification.',
     btn: 'Shop Now',
     subTitle: 'Bring Space to Life in Digital 3D',
     benefitGroup: [
@@ -37,10 +37,10 @@ export default{
     sub: ['快速编辑和分享你的互动式视频', '分享你的空间故事']
   },
   definition: {
-    title: '10K Image Quality That Captures Every Detail in the Space',
+    title: '12K Image Quality That Captures Every Detail in the Space',
     top: {
-      dec: '4DKanKan Pro records three-dimensional information of space, andproduces realistic 3D digital spaces, allowing you to enter anytimeand freely explore as you were there. Never miss a detail with 10K definition and 4x magnification.',
-      intro: 'Quality of images shot by 4DKanKan Pro<br/>reaches up to 10000*5000 pixels'
+      dec: '4DKanKan Pro records three-dimensional information of space, andproduces realistic 3D digital spaces, allowing you to enter anytimeand freely explore as you were there. Never miss a detail with 12K definition and 4x magnification.',
+      intro: 'Quality of images shot by 4DKanKan Pro<br/>reaches up to 12288*6144 pixels'
     },
     bottom: {
       title: '细节之处,纤毫毕现',
@@ -91,7 +91,7 @@ export default{
         lTxt: '4DKanKan Lite',
         rTxt: '4DKanKan Pro',
         lMask: 'High-definition of 4K',
-        rMask: '10K HD picture with 4-times magnification'
+        rMask: '12K HD picture with 4-times magnification'
       }
     },
     ranging: {
@@ -122,46 +122,44 @@ export default{
     dec: 'Powered by the integrated work of hundreds of sophisticated parts, 4DKanKan Pro is light and compact, portable and durable, and can capture space in 3D for you at any time.'
   },
   parmas: {
-    name: 'Detailed Parameters of 4DKanKan Pro',
+    name: '四维看看 Pro 详细参数',
     detail: [
       {
-        label: '型号',
+        label: 'Model',
+        name: '4DKanKan Pro',
         dec: [
-          '高度: 141.5毫米 / ',
-          '宽度: 71.1mm / ',
-          '厚度:17.98mm',
-          '<br/>重量:115g'
+          'Height:220.7mm / ',
+          'Width:78.2mm / ',
+          'Depth:78.2mm'
         ]
       }, {
-        label: '材质',
+        label: 'Lenses',
         name: '',
         dec: [
-          '钛金属 / ',
-          '磨砂背']
+          'Type:200°fisheye lens /  ',
+          'Aperture:f/2.0 /  ',
+          'Number:8 /  ',
+          'Resolution:4608*3456pixels(each); 12288*6144pixels(total)']
       }, {
-        label: '摄像头',
+        label: 'Sensors',
         name: '',
-        dec: ['f / 2.0 大光圈镜头 / ', '3200万像素SONY sensor / ', '220°双鱼眼镜头 / ', '9片8组光学镜头 / ', '3K视频录制速度为30fps']
+        dec: ['Dimension:1/2.3" / ', 'Number:8']
       }, {
-        label: '连接',
-        name: '蓝牙:5.0',
-        dec: ['WiFi / ', 'WiFi:802.11a / b / g / n / ac']
-      }, {
-        label: '电池',
+        label: 'Storage',
         name: '',
-        dec: ['3040mAh / ', '通过USB快速充电']
+        dec: ['16GB']
       }, {
-        label: '存储',
+        label: 'Battery',
         name: '',
-        dec: ['支持128G TF卡 / ', '3K视频 录制120分钟']
+        dec: ['7.4V 4200mAh / ', 'USB charge']
       }, {
-        label: '端口',
+        label: 'WiFi',
         name: '',
-        dec: ['microUSB / ', '三脚架固定孔']
+        dec: ['802.11a/b/g/n / ', '2.4/5GHz communication']
       }, {
-        label: '防水防尘',
+        label: 'USB',
         name: '',
-        dec: ['IP54']
+        dec: ['TYPE C']
       }
     ]
   }

+ 1 - 1
src/store/language/en/home.js

@@ -107,7 +107,7 @@ export default{
       image: baseUrl + 'images/phone_9.jpg',
       icon: baseUrl + 'images/phone_icon_9.png',
       text: '伟星' },
-    {url: 'https://admin.4dmuseum.cn/showPC.html?m=333&bigScene&novr',
+    {url: 'https://admin.4dmuseum.cn/showApp.html?m=240&bigScene&novr',
       image: baseUrl + 'images/phone_10.jpg',
       icon: baseUrl + 'images/phone_icon_10.png',
       text: '武侯祠' }

+ 123 - 0
src/store/language/en/purchase.js

@@ -0,0 +1,123 @@
+export default{
+  top1: '概览',
+  top2: '技术规格',
+  dec: '15分钟快速三维重建,全自动生成数字3D空间,实时计算空间尺寸,12K分辨率,支持4倍放大',
+  yushou: '【新品预售】',
+  price: 'RMB 9,800',
+  buy: '立即购买',
+  tiaokuan: '* 付款成功后5个工作日内发货,默认顺丰快递包邮',
+  guige: {
+    name: '技术规格',
+    dec: '注:本页面所列配置及参数均以实际上市产品为准,如有变更,恕不另行通知;',
+    arr: [
+      {
+        name: '机身尺寸',
+        val: ['高度:220.7毫米', '宽度:78.2毫米', '厚度:78.2毫米']
+      },
+      {
+        name: '镜头',
+        val: [
+          '类型:200°鱼眼镜头',
+          '孔径:f/2.0',
+          '数量:8个',
+          '分辨率:4608*3456像素(每个);12288*6144像素(合计)'
+        ]
+      },
+      {
+        name: '传感器',
+        val: ['范围:1/2.3英寸', '数量:8个']
+      },
+      {
+        name: '存储内存',
+        val: [
+          '16GB'
+        ]
+      },
+      {
+        name: '电池',
+        val: [
+          '7.4V 4200mAh',
+          '可通过USB快速充电'
+        ]
+      },
+      {
+        name: 'WiFi',
+        val: [
+          '802.11a/b/g/n网络协议',
+          '支持2.4/5GHz通信'
+        ]
+      },
+      {
+        name: '设备接口',
+        val: [
+          'TYPE C'
+        ]
+      }
+    ]
+  },
+  color: {
+    key: '颜色',
+    val: ' 静谧黑'
+  },
+  service: {
+    key: '服务',
+    val1: [
+      '数据永久存储',
+      '高速上传计算队列',
+      '场景分享、热点编辑、隐私加密'
+    ],
+    val2: [
+      '多种个性化功能',
+      '附送30G终身容量'
+    ]
+  },
+  gift: {
+    key: '赠品',
+    val: ' 官方拍摄支架 x 1'
+  },
+  count: {
+    key: '数量'
+  },
+  parmas: {
+    name: '技术规格',
+    detail: [
+      {
+        label: 'Model',
+        name: '4DKanKan Pro',
+        dec: [
+          'Height:220.7mm / ',
+          'Width:78.2mm / ',
+          'Depth:78.2mm'
+        ]
+      }, {
+        label: 'Lenses',
+        name: '',
+        dec: [
+          'Type:200°fisheye lens /  ',
+          'Aperture:f/2.0 /  ',
+          'Number:8 /  ',
+          'Resolution:4608*3456pixels(each); 12288*6144pixels(total)']
+      }, {
+        label: 'Sensors',
+        name: '',
+        dec: ['Dimension:1/2.3" / ', 'Number:8']
+      }, {
+        label: 'Storage',
+        name: '',
+        dec: ['16GB']
+      }, {
+        label: 'Battery',
+        name: '',
+        dec: ['7.4V 4200mAh / ', 'USB charge']
+      }, {
+        label: 'WiFi',
+        name: '',
+        dec: ['802.11a/b/g/n / ', '2.4/5GHz communication']
+      }, {
+        label: 'USB',
+        name: '',
+        dec: ['TYPE C']
+      }
+    ]
+  }
+}

+ 113 - 0
src/store/language/en/purchasetow.js

@@ -0,0 +1,113 @@
+export default{
+  top1: '概览',
+  top2: '技术规格',
+  dec: '10分钟复刻空间,时间仅需传统设备的1/20,4K高清画质,实现沉浸式3D实景空间漫游',
+  yushou: '【新品预售】',
+  price: 'RMB 3,999',
+  buy: '立即购买',
+  tiaokuan: '* 付款成功后5个工作日内发货,默认顺丰快递包邮',
+  guige: {
+    name: '技术规格',
+    dec: '注:本页面所列配置及参数均以实际上市产品为准,如有变更,恕不另行通知;',
+    arr: [
+      {
+        name: 'Size',
+        val: ['Height: 130mm', 'Width: 47mm', 'Depth: 18mm', 'Weight: 115g']
+      },
+      {
+        name: 'Fabric',
+        val: [
+          'Titanium',
+          'Matte surface'
+        ]
+      },
+      {
+        name: 'Camera',
+        val: ['f/2.0 aperture',
+          '3200-pixels SONY sensor',
+          '220° fisheye lens*2',
+          'Optical lens*8',
+          '30fps recording speed in 3K']
+      },
+      {
+        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']
+      }
+    ]
+  },
+  color: {
+    key: '颜色',
+    val: ' 静谧黑'
+  },
+  service: {
+    key: '服务',
+    val1: [
+      '数据永久存储',
+      '高速上传计算队列',
+      '场景分享、热点编辑、隐私加密'
+    ],
+    val2: [
+      '多种个性化功能',
+      '附送30G终身容量'
+    ]
+  },
+  gift: {
+    key: '赠品',
+    val: ' 官方拍摄支架 x 1'
+  },
+  count: {
+    key: '数量'
+  },
+  parmas: {
+    name: '技术规格',
+    detail: [
+      {
+        label: 'Model',
+        dec: [
+          'Height: 130mm / ',
+          'Width: 47mm / ',
+          'Depth: 18mm /',
+          '<br/>Weight: 115g'
+        ]
+      }, {
+        label: 'Fabric',
+        name: '',
+        dec: [
+          'Titanium / ',
+          'Matte surface']
+      }, {
+        label: 'Camera',
+        name: '',
+        dec: ['f/2.0 aperture / ', '3200-pixels SONY sensor / ', '220° fisheye lens*2 / ', 'Optical lens*8 / ', '30fps recording speed in 3K']
+      }, {
+        label: 'Connection',
+        name: 'Bluetooth: 5.0',
+        dec: ['WiFi:802.11a / b / g / n / ac']
+      }, {
+        label: 'Battery',
+        name: '',
+        dec: ['2000mAh / ', 'Quick charge through USB']
+      }, {
+        label: 'Storage',
+        name: '',
+        dec: ['128G Trans-flash Card / ', '120-minutes 3K video']
+      }, {
+        label: 'Interface',
+        name: '',
+        dec: ['microUSB / ', 'Tripod attachment hole']
+      }
+    ]
+  }
+}

+ 29 - 25
src/store/language/home_cn.js

@@ -3,6 +3,8 @@ import binocular from './cn/binocular'
 import eight from './cn/eight'
 import about from './cn/about'
 import coreTech from './cn/coreTech'
+import purchase from './cn/purchase'
+import purchasetow from './cn/purchasetow'
 
 export default {
   title: '中文',
@@ -54,30 +56,30 @@ export default {
           }
         ]
       },
-      {
-        title: '服务支持',
-        url: '',
-        id: 'fwzc',
-        sub: [ {
-          icon: 'icon-tutorial',
-          name: '使用教程',
-          to: {name: 'service', params: {id: 'use'}}
-        },
-        {
-          icon: 'icon-faq',
-          name: '常见问题',
-          to: {name: 'service', params: {id: 'qa'}}
-        }, {
-          icon: 'icon-appdown',
-          name: 'app下载',
-          to: {name: 'service', params: {id: 'app'}}
-        },
-        {
-          icon: 'icon-sysc',
-          name: '产品手册',
-          to: {name: 'service', params: {id: 'product'}}
-        }]
-      },
+      // {
+      //   title: '服务支持',
+      //   url: '',
+      //   id: 'fwzc',
+      //   sub: [ {
+      //     icon: 'icon-tutorial',
+      //     name: '使用教程',
+      //     to: {name: 'service', params: {id: 'use'}}
+      //   },
+      //   {
+      //     icon: 'icon-faq',
+      //     name: '常见问题',
+      //     to: {name: 'service', params: {id: 'qa'}}
+      //   }, {
+      //     icon: 'icon-appdown',
+      //     name: 'app下载',
+      //     to: {name: 'service', params: {id: 'app'}}
+      //   },
+      //   {
+      //     icon: 'icon-sysc',
+      //     name: '产品手册',
+      //     to: {name: 'service', params: {id: 'product'}}
+      //   }]
+      // },
       {
         title: '核心技术',
         url: '/location',
@@ -98,6 +100,8 @@ export default {
       }
     ]
   },
+  purchase,
+  purchasetow,
   home,
   eight,
   binocular,
@@ -188,7 +192,7 @@ export default {
       },
       {
         name: '联系电话',
-        content: '400-6698-025'
+        content: '0086 756-6996790-800'
       }
     ],
     links: [{

+ 29 - 40
src/store/language/home_en.js

@@ -3,6 +3,8 @@ import binocular from './en/binocular'
 import eight from './en/eight'
 import about from './en/about'
 import coreTech from './en/coreTech'
+import purchase from './en/purchase'
+import purchasetow from './en/purchasetow'
 
 export default {
   title: '英文',
@@ -54,50 +56,35 @@ export default {
           }
         ]
       },
-      {
-        title: 'Services',
-        url: '',
-        id: 'fwzc',
-        sub: [ {
-          icon: 'icon-tutorial',
-          name: 'Tutorials',
-          to: {name: 'service', params: {id: 'use'}}
-        },
-        {
-          icon: 'icon-faq',
-          name: 'Q&As',
-          to: {name: 'service', params: {id: 'qa'}}
-        }, {
-          icon: 'icon-appdown',
-          name: 'Download',
-          to: {name: 'service', params: {id: 'app'}}
-        },
-        {
-          icon: 'icon-sysc',
-          name: 'Specifications',
-          to: {name: 'service', params: {id: 'product'}}
-        }]
-      },
+      // {
+      //   title: 'Services',
+      //   url: '',
+      //   id: 'fwzc',
+      //   sub: [ {
+      //     icon: 'icon-tutorial',
+      //     name: 'Tutorials',
+      //     to: {name: 'service', params: {id: 'use'}}
+      //   },
+      //   {
+      //     icon: 'icon-faq',
+      //     name: 'Q&As',
+      //     to: {name: 'service', params: {id: 'qa'}}
+      //   }, {
+      //     icon: 'icon-appdown',
+      //     name: 'Download',
+      //     to: {name: 'service', params: {id: 'app'}}
+      //   },
+      //   {
+      //     icon: 'icon-sysc',
+      //     name: 'Specifications',
+      //     to: {name: 'service', params: {id: 'product'}}
+      //   }]
+      // },
       {
         title: 'Technologies',
         url: '/location',
         id: '',
         sub: []
-        // sub: [{
-        //   name: '空间定位',
-        //   icon: 'icon-tech_space_location',
-        //   to: {name: 'location', query: {id: 'kjdw'}}
-        // }, {
-        //   name: '空间建模',
-        //   icon: 'icon-tech_space_modeling',
-        //   to: {name: 'location', query: {id: 'kjjm'}}
-
-        // }, {
-        //   name: '空间展示',
-        //   icon: 'icon-tech_space_display',
-        //   to: {name: 'location', query: {id: 'kjzs'}}
-
-        // }]
       },
       {
         title: 'About us',
@@ -115,6 +102,8 @@ export default {
   },
   home,
   eight,
+  purchase,
+  purchasetow,
   binocular,
   coreTech,
   about,
@@ -203,7 +192,7 @@ export default {
       },
       {
         name: 'Tel',
-        content: '400-6698-025'
+        content: '0086 756-6996790-800'
       }
     ],
     links: [{

+ 108 - 6
src/store/user.js

@@ -1,13 +1,15 @@
 import http from '@/util/http'
-import { reg } 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 payinfo = (localStorage && localStorage.getItem('payinfo')) || {}
 let orderinfo = (localStorage && localStorage.getItem('orderinfo')) || {}
@@ -33,8 +35,13 @@ export default {
     token: token,
     name: null,
     cart: cart,
+    fdkankantoken,
     myscene: '',
     myorder: '',
+    mydevice: '',
+    myexpansion: '',
+    mycharge: '',
+    myinvoicelist: '',
     payinfo,
     orderinfo,
     invoice2: invoice2,
@@ -47,12 +54,14 @@ export default {
       state.token = token
       try {
         localStorage.setItem('token', token)
+        Cookies.set('fdkankantoken', token)
       } catch (error) {
 
       }
     },
     logout (state) {
       try {
+        Cookies.set('fdkankantoken', '')
         Object.keys(state).forEach(key => {
           state[key] = ''
           localStorage.setItem(key, '')
@@ -70,6 +79,10 @@ export default {
       state.myscene = data
       localStorage.setItem('myscene', JSON.stringify(data))
     },
+    MYDEVICE (state, data) {
+      state.mydevice = data
+      localStorage.setItem('mydevice', JSON.stringify(data))
+    },
 
     ORDERINFO (state, data) {
       console.log(data)
@@ -92,6 +105,20 @@ export default {
       localStorage.setItem('cart', 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))
+    },
+
     myOrder (state, data) {
       state.myorder = data
       localStorage.setItem('myorder', JSON.stringify(data))
@@ -194,6 +221,21 @@ export default {
       context.commit('CART', 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 getInvoice (context, data) {
       let info = await http({
         method: 'post',
@@ -235,23 +277,83 @@ export default {
       if (data.code !== 0) return
       context.commit('myOrder', data.data)
     },
-    async getAuthCode (context, phone) {
-      if (reg.phone.test(phone)) {
+    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')
+      }
+    },
+    async getAuthCode (context, item) {
+      let {phone, code} = item
+      let areaNum = Number(code) || 86
+      if (phone) {
         let params = {
-          phoneNum: phone,
-          areaNum: '86'
+          phoneNum: Number(phone),
+          areaNum
         }
         http({
           method: 'post',
           data: params,
           url: '/sso/user/getMsgAuthCode'
         }, res => {
-
         })
         return true
       } else {
         return vue.$toast.show('warn', '手机号码不合法')
       }
+    },
+
+    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)
     }
   }
 }

+ 4 - 4
src/util/http.js

@@ -5,15 +5,15 @@ import Vue from 'vue'
 
 let vue = new Vue()
 // import qs from 'qs'
-const exceptUrls = ['/sso/user/logout', '/sso/user/sendUserInfo']
+const exceptUrls = ['/sso/user/logout', '/sso/user/sendUserInfo', '/user/checkToken']
 
 // axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? 'http://192.168.0.10:8080/api' : '/api'
 axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? 'https://pro.4dkankan.com/api' : '/api'
 
-// 请求超时时限 我设置500毫秒
-axios.defaults.timeout = 2000
+// 请求超时时限
+axios.defaults.timeout = 15000
 // 请求次数
-axios.defaults.retry = 4
+axios.defaults.retry = 2
 // 请求的间隙
 axios.defaults.retryDelay = 1000