Explorar el Código

Merge branch 'master' of http://192.168.0.115:3000/tangning/personalhubs

wangfumin hace 1 semana
padre
commit
8696a2e2eb

+ 1 - 0
components.d.ts

@@ -39,6 +39,7 @@ declare module '@vue/runtime-core' {
     IconSupport: typeof import('./src/components/icons/IconSupport.vue')['default']
     IconTooling: typeof import('./src/components/icons/IconTooling.vue')['default']
     Mobile: typeof import('./src/components/mobile/index.vue')['default']
+    Paging: typeof import('./src/components/pc/Paging/index.vue')['default']
     Pc: typeof import('./src/components/pc/index.vue')['default']
     Popup: typeof import('./src/components/popup/index.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']

+ 255 - 0
src/components/pc/Paging/index.vue

@@ -0,0 +1,255 @@
+<script setup lang="ts">
+import { onMounted, ref, computed, watch } from 'vue'
+const emit = defineEmits(['maxPage', 'clickHandle', 'input'])
+const props = defineProps({
+  current: {
+    type: Number,
+    default: 1
+  },
+  reindex: {
+    type: Number,
+    default: 1
+  },
+  total: {
+    type: Number,
+    default: 10
+  },
+  equable: {
+    type: Number,
+    default: 10
+  },
+  length: {
+    type: Number,
+    default: 5
+  },
+  value: {
+    type: Number,
+    default: 1
+  },
+  color: {
+    type: String,
+    default: '#2d2d2d'
+  }
+})
+const index = ref<number>(props.value)
+const maxPage = computed(() => {
+  let val = Math.ceil(props.total / props.equable)
+  emit('maxPage', val)
+  return val
+})
+const pages = computed(() => {
+  return getPageNumArr(props.length, index.value, maxPage.value)
+})
+const useUser = useUserStore()
+useUser.getInfo()
+// 监听过滤数据变化更新总数
+watch(index.value, (newVal: number) => {
+  emit('input', newVal)
+})
+watch(props.current, (newVal: number) => {
+  index.value = newVal
+})
+watch(props.total, (newVal: number) => {
+  if (index.value > maxPage.value) {
+    index.value = maxPage.value
+    clickHandle(maxPage.value)
+  }
+})
+onMounted(() => {
+  emit('maxPage', maxPage)
+})
+function clickHandle(indexs) {
+  if (indexs > 0 && indexs <= this.maxPage) {
+    index.value = indexs
+  }
+  emit('clickHandle', index.value)
+}
+function getPageNumArr(showPageMaxCount, pageNow, pageCount) {
+  let pageNumArr = []
+  let pageNumBegin, pageNumEnd
+
+  if (pageCount <= showPageMaxCount) {
+    pageNumBegin = 1
+    pageNumEnd = pageCount
+  } else {
+    if (pageNow <= Math.floor(showPageMaxCount / 2)) {
+      pageNumBegin = 1
+      pageNumEnd = showPageMaxCount
+    } else if (pageCount - pageNow <= Math.floor(showPageMaxCount / 2)) {
+      pageNumBegin = pageCount - showPageMaxCount
+      pageNumEnd = pageCount
+      pageNumEnd - pageNumBegin >= showPageMaxCount && pageNumBegin++
+    } else {
+      pageNumBegin = Math.ceil(pageNow - showPageMaxCount / 2)
+      pageNumEnd = Math.floor(pageNow + showPageMaxCount / 2)
+      pageNumEnd - pageNumBegin >= showPageMaxCount && pageNumBegin++
+    }
+  }
+  for (let i = pageNumBegin; i <= pageNumEnd; i++) {
+    pageNumArr.push(i)
+  }
+
+  return pageNumArr
+}
+</script>
+<template>
+  <div class="layout">
+    <!-- <a class="next-page pre-page" v-if="index>1" @click="clickHandle(index - 1)"></a> -->
+    <a class="page-item" @click="clickHandle(1)" :class="{ active: index === 1 }">1</a
+    ><a class="page-item more" @click="clickHandle(current - 3)" v-if="pages[0] - 2 >= 1">...</a
+    ><a
+      v-if="page !== maxPage && page !== 1"
+      v-for="page in pages"
+      :key="page"
+      @click="clickHandle(page)"
+      class="page-item"
+      :class="{ active: index === page }"
+      >{{ page }}</a
+    ><a
+      class="more page-item"
+      @click="clickHandle(pages[pages.length - 1] + 2)"
+      v-if="maxPage > 1 && pages[pages.length - 1] + 2 <= maxPage"
+      >...</a
+    ><a
+      @click="clickHandle(maxPage)"
+      class="page-item"
+      v-if="maxPage !== 1"
+      :class="{ active: index === maxPage }"
+      >{{ maxPage }}</a
+    >
+    <a
+      v-show="index !== maxPage"
+      class="next-page next-page-item"
+      @click="clickHandle(index + 1)"
+    ></a>
+  </div>
+</template>
+
+<style scoped>
+.layout .more:hover::after {
+  transform: scaleX(0) !important;
+}
+.layout .next-page-item:hover::before {
+  transform: scaleX(2);
+}
+.layout .next-page-item:hover::after {
+  transform: translateX(5px);
+}
+.layout .next-page-item::before {
+  background-color: #111;
+  height: 2px;
+  width: 8px;
+  transform-origin: 0 0;
+}
+.layout .next-page-item::after {
+  width: 0;
+  height: 0;
+  border-style: solid;
+  border-width: 5px 0 5px 8px;
+  border-color: transparent transparent transparent #011111;
+}
+.layout .pre-page::after {
+  transform-origin: 100% 0;
+}
+.layout .pre-page:hover::after {
+  transform: scaleX(2);
+  transform-origin: 100% 0;
+}
+.layout .pre-page:hover::before {
+  transform: translateX(-5px);
+}
+.layout .pre-page::after {
+  background-color: #111;
+  height: 2px;
+  width: 8px;
+}
+.layout .pre-page::before {
+  width: 0;
+  height: 0;
+  border-style: solid;
+  border-width: 5px 8px 5px 0;
+  border-color: transparent #011111 transparent transparent;
+}
+.layout {
+  /* text-align: left; */
+  margin-top: 0;
+  /* margin-left: 30px; */
+}
+.layout a {
+  display: inline-block;
+  width: 32px;
+  height: 32px;
+  text-align: center;
+  line-height: 32px;
+}
+.layout a:not(:last-child) {
+  margin: 10px 8px;
+  font-size: 16px;
+  display: inline-block;
+  font-weight: 500;
+  cursor: pointer;
+  user-select: none;
+  color: #323233;
+  position: relative;
+  transition: color 0.3s;
+}
+.layout a:last-child {
+  position: relative;
+  top: -5px;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+  -ms-flex-align: center;
+  align-items: center;
+  height: 22px;
+  padding: 0 9.6px;
+  padding: 0 0.6rem;
+}
+.layout a:last-child::before,
+.layout a:last-child::after {
+  content: '';
+  display: inline-block;
+  will-change: transform;
+  transition: transform 0.3s;
+}
+
+.layout a:not(:last-child).active,
+.layout a:not(:last-child):hover {
+  color: #fff;
+  transform: scaleX(1);
+  background: #323233;
+}
+
+.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;
+}
+
+/* .layout {
+  text-align: center;
+}
+
+.layout a {
+  margin: 10px;
+  font-size: 18px;
+  display: inline-block;
+  cursor: pointer;
+  user-select: none;
+  color: #2d2d2d;
+
+}
+
+.layout a.active,
+.layout a:hover {
+  color: #111111;
+  border-bottom: 2px solid #111;
+} */
+</style>

+ 608 - 0
src/views/pc/order/components/consumption.vue

@@ -0,0 +1,608 @@
+<template>
+  <div class="consump-layout">
+    <div class="c-header">
+      <ul class="tab-list">
+        <li @click="active = i" :class="{active:i===active}" v-for="(item,i) in tabList" :key="i">
+          {{item.name}}
+        </li>
+      </ul>
+      
+      <!-- <div class="tab-search" v-else :style="{border:!deviceLogin?'1px solid #ccc':'none'}">
+         <template v-if="!deviceLogin">
+          <input v-model="searchKey" @keyup.enter="getList(searchKey)" type="text" :placeholder="$t('manage.Spending.placeholdersearchID')">
+          <i class="iconfont icon-sousuo" @click="getList(searchKey)"></i>
+         </template>
+      </div> -->
+    </div>
+    
+
+    <div class="table-list">
+      <div class="invoices" v-if="active===2">
+      <span>相机</span>
+      <div v-if="!deviceLogin" class="tab-select" ref="deviceMenu" @click="deviceActive=!deviceActive" :class="{'tab-active':deviceActive}">
+        {{activeDevice||'暂无相机'}}
+        <ul>
+          <li v-for="(item,i) in invoicedevice" @click="selectInId(item)" :key="i" >{{item.childName}}</li>
+        </ul>
+      </div>
+      <span v-else>{{deviceLogin}} </span>
+      <div v-if="active===2 && !deviceLogin" class="tab-select" ref="invoiceMenu" @click="tabActive=!tabActive" :class="{'tab-active':tabActive}">
+        {{activeType}}
+        <ul>
+          <li v-for="(item,i) in cameraList"  @click="selectCamTy(item)" :key="i">{{item.name}}</li>
+        </ul>
+      </div>
+      <span>可开票额度(元){{max}}</span>
+      <div class="btn default" :class="{parmary:max>0&&!deviceLogin}" @click="openInvice">开票</div>
+    </div>
+      <tableList :header='tabHeader' :data='data'  >
+        <div slot-scope="{data}" slot="header">
+          {{data.name}}
+        </div>
+        <div slot-scope="{data,canclick,item, subKey}" slot="item">
+          <span class="edit" v-if="canclick" @click="showDetail(item)">{{data}}</span>
+          <span v-else-if="subKey === 'payType'">{{ PAYSIDMAP[data] }}</span>
+          
+          <span v-else>{{data}}</span>
+        </div>
+      </tableList>
+      <div class="paging" v-if="total">
+        <vcenter>
+          <Paging @clickHandle="pageChange" :current="currentPage" :total="total" :equable="pageSize" />
+        </vcenter>
+      </div>
+      <div class="scene-nothing"  v-if="!total">
+        <img :src="`${$cdn}images/nothing.png`" >
+        <div>{{$t('manage.Spending.norecord')}}</div>
+      </div>
+    </div>
+    
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+import tableList from '@/components/table'
+import {capacity, recharge, invoice} from './iconsumption'
+import Paging from '@/components/Paging'
+import vcenter from '@/components/vcenter'
+import MemberApi from '@/apis/member'
+import MallConfig from '@/config/mall'
+
+let AMOUNTSTR = {
+  0: '¥',
+  1: '¥',
+  2: '$'
+}
+
+let methodStr = {
+  0: 'getMemberOrderList',
+  1: 'getChargeList',
+  2: 'getInvoiceList'
+}
+let rechargeType = {
+  0: '系统赠送',
+  '-1': '支出',
+  1: '充值',
+  2: '系统退充值'
+}
+
+let invoceStatusType = {
+  0: '未开票',
+  1: '已开票'
+}
+
+let invoiceType = {
+  1: '不需要发票',
+  2: '增值税普通发票',
+  3: '增值税专用发票'
+}
+
+export default {
+  components: {
+    tableList,
+    Paging,
+    vcenter
+  },
+  data () {
+    let cameraList = [
+      {
+        name: '全部',
+        id: ''
+      },
+      {
+        name: '二目充值',
+        id: 0
+      },
+      {
+        name: '会员权益',
+        id: 4
+      }
+    ]
+    return {
+      PAYSIDMAP: MallConfig.PAYSIDMAP,
+      tabHeader: capacity,
+      data: [],
+      cameraList,
+      active: 0,
+      recharge,
+      total: 30,
+      pageSize: 10,
+      currentPage: 1,
+      tabActive: false,
+      deviceActive: false,
+      max: 0,
+      activeDevice: '',
+      activeType: '全部',
+      activeId: '',
+      activeTypeId: '',
+      tabList: [
+        {
+          name: this.$t('manage.Spending.tabListMember')
+        },
+        {
+          name: this.$t('manage.Spending.tabListRecharge')
+        },
+        {
+          name: this.$t('manage.Spending.tabListInvoice')
+        },
+      ]
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token,
+      language: state => state.language.current,
+      deviceLogin: state => state.user.deviceLogin,
+      // 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 : [])
+      },
+      searchKey () {
+        return this.$parent.searchKey
+      }
+    })
+  },
+  watch: {
+    currentPage (newVal) {
+      this.getList()
+    },
+    language (newVal) {
+      this.active = 0
+      this.data.forEach(item => {
+        let condition = item['validDate'] === '终身有效' ? (newVal === 'en' ? 'N/A' : '终身有效') : item['validDate']
+        item['validDateStr'] = condition
+        item['unitSize1'] = item['unitSize'] + item['unit'] + '/' + this.$t(`manage.shixian.${item['month']}`)
+        item['channel'] = this.$t(`manage.channelType.${item['status']}`)
+        item['amount1'] = AMOUNTSTR[item['payType']] + item['amount']
+        item['payTypeStr'] = this.$t(`manage.PAYSSTR.${item['payType']}`)
+      })
+    },
+    activeId (newVal) {
+      if (this.active === 2) {
+        this.getList()
+      }
+      this.getInvoiceMax()
+    },
+    activeTypeId (newVal) {
+      if (this.active === 2) {
+        this.getList()
+      }
+    },
+    active (newVal) {
+      switch (newVal) {
+        case 1:
+          this.tabHeader = recharge
+          break
+        case 2:
+          !this.deviceLogin && this.getAllDevice()
+          this.tabHeader = invoice
+          break
+        default:
+          this.tabHeader = capacity
+          break
+      }
+      if (newVal !== 1) {
+        this.$emit('changeSearchShow', false)
+      } else {
+        this.$emit('changeSearchShow', true)
+      }
+      this.currentPage === 1 ? this.getList() : this.currentPage = 1
+    }
+  },
+  methods: {
+    pageChange (data) {
+      this.currentPage = data
+    },
+    selectInId (item) {
+      this.activeDevice = item.childName
+      this.activeId = item.id
+    },
+    selectCamTy (item) {
+      this.activeType = item.name
+      this.activeTypeId = item.id
+    },
+    showDetail (item) {
+      this.$toast.showInvoiceDetail(item)
+    },
+    getList (searchKey = '') {
+      window.scrollTo(0, 0)
+      let str = methodStr[this.active]
+      this[str](searchKey)
+    },
+    openInvice () {
+      let params = {
+        max: this.max,
+        cameraId: this.activeId
+      };
+      (this.max && !this.deviceLogin) && this.$toast.showInvoice(params)
+    },
+    async getAllDevice (searchKey = '') {
+      let params = {
+        cameraType: ''
+      }
+      await this.$store.dispatch('getInvoiceDevice', params)
+      this.activeDevice = this.invoicedevice[0].childName
+      this.activeId = this.invoicedevice[0].id
+    },
+
+    // 扩容记录
+    async getConsumpList (searchKey = '') {
+      if (this.deviceLogin) {
+        searchKey = this.deviceLogin
+      }
+      let data = {
+        params: {
+          childName: searchKey.trim(),
+          pageNum: searchKey ? 1 : this.currentPage,
+          pageSize: this.pageSize
+        },
+        url: this.deviceLogin ? '/device/virtualOrder/expansionList' : '/user/virtualOrder/expansionList'
+      }
+      await this.$store.dispatch('getUserExpansion', data)
+      if (!this.myexpansion.total && searchKey && !this.deviceLogin) {
+        return this.$toast.show('warn', this.$t('toast.25'), () => {
+          this.getList()
+        })
+      }
+      console.log(this.myexpansion, 'this.myexpansion')
+      this.pageSize = this.myexpansion.pageSize
+      this.total = this.myexpansion.total || 0
+      this.data = this.myexpansion.list
+      this.data.forEach(item => {
+        let condition = item['validDate'] === '终身有效' ? (this.language === 'en' ? 'N/A' : '终身有效') : item['validDate']
+        item['validDateStr'] = condition
+        item['statusStr'] = this.$t(`manage.myOrders.${item['status']}`)
+        item['unitSize1'] = item['unitSize'] + item['unit'] + '/' + this.$t(`manage.shixian.${item['month']}`)
+        item['channel'] = this.$t(`manage.channelType.${item['status']}`)
+        item['amount1'] = AMOUNTSTR[item['payType']] + item['amount']
+        item['payTypeStr'] = this.$t(`manage.PAYSSTR.${item['payType']}`)
+      })
+    },
+    getMemberOrderList () {
+      let data = {
+        snCode: this.searchKey,
+        pageNum: this.currentPage,
+        pageSize: this.pageSize
+      }
+      MemberApi.getVirtualOrderList(data).then(res => {
+        this.data = res.data.data.list
+        console.log(this.data)
+        this.total = res.data.data.total
+      })
+    },
+    async getInvoiceMax () {
+      let res = await this.$http({
+        method: 'post',
+        data: {
+          cameraId: this.activeId
+        },
+        headers: {
+          token: this.token
+        },
+        url: '/user/invoice/max'
+      })
+
+      let data = res.data
+      if (data.code !== 0) return
+      this.max = data.data.maxInvoice
+    },
+
+    // 充值记录
+    async getChargeList (searchKey = '') {
+      if (this.deviceLogin) {
+        searchKey = this.deviceLogin
+      }
+      let data = {
+        params: {
+          childName: searchKey,
+          pageNum: searchKey ? 1 : this.currentPage,
+          pageSize: this.pageSize
+        },
+        url: this.deviceLogin ? '/device/virtualOrder/chargeList' : '/user/virtualOrder/chargeList'
+      }
+      await this.$store.dispatch('getChargeList', data)
+      if (!this.mycharge.total && searchKey && !this.deviceLogin) {
+        return this.$toast.show('warn', this.$t('toast.25'), () => {
+          this.getList()
+        })
+      }
+      this.pageSize = this.mycharge.pageSize
+      this.total = this.mycharge.total || 0
+      this.data = this.mycharge.list
+      this.data.forEach(item => {
+        item['status'] = rechargeType[item['status']]
+      })
+    },
+
+    // 发票记录
+    async getInvoiceList () {
+      let data = {
+        params: {
+          cameraId: this.activeId,
+          pageNum: this.currentPage,
+          pageSize: this.pageSize,
+          type: this.activeTypeId
+        },
+        url: this.deviceLogin ? '/device/invoice/list' : '/user/invoice/list'
+      }
+
+      await this.$store.dispatch('getInvoiceList', data)
+      this.pageSize = this.myinvoicelist.pageSize
+      this.total = this.myinvoicelist.total || 0
+      this.data = this.myinvoicelist.list
+      this.data.forEach(item => {
+        item['detail'] = '详细'
+        item['money'] = '¥' + item['money']
+        item['finish'] = invoceStatusType[item['finish']]
+        item['type'] = invoiceType[item['type']]
+      })
+    },
+    handleSearch (keyword) {
+      this.getList(keyword)
+    }
+  },
+  mounted () {
+    this.getList()
+
+    this.$bus.$off('refreshInvoice')
+    this.$bus.$on('refreshInvoice', () => {
+      if (this.active === 2) {
+        this.getList()
+      }
+      this.getInvoiceMax()
+    })
+
+    document.addEventListener('click', (e) => {
+      if (this.$refs.invoiceMenu) {
+        if (!this.$refs.invoiceMenu.contains(e.target)) {
+          this.tabActive = false
+        }
+      }
+      if (this.$refs.deviceMenu) {
+        if (!this.$refs.deviceMenu.contains(e.target)) {
+          this.deviceActive = false
+        }
+      }
+    })
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+$theme-color: #15BEC8;
+$font-color: #2d2d2d;
+$border-color: #d9d9d9;
+.btn {
+    text-align: center;
+    cursor: pointer;
+  }
+.default {
+  width: 88px;
+  height: 28px;
+  line-height: 28px;
+  font-size: 14px;
+  background-color: #e7e7e7;
+  cursor: initial;
+
+}
+.parmary {
+  background-color: $theme-color;
+  cursor: pointer;
+}
+
+.consump-layout{
+  .c-header{
+    .tab-list{
+      display: flex;
+      color: #323233;
+      li{
+        line-height: 32px;
+        cursor: pointer;
+        font-size: 14px;
+        background: #EBEBEB;
+        width: 104px;
+        text-align: center;
+        margin-right: 1px;
+      }
+      .active{
+        background: #ffff;
+        position: relative;
+        border: 1px solid rgba(235, 235, 235, 1);
+        border-bottom: none;
+        &::after {
+          content: '';
+          display: block;
+          height: 1px;
+          width: 100%;
+          background: #fff;
+          position: absolute;
+          bottom: -1px;
+        }
+      }
+    }
+
+  }
+  .invoices{
+    display: flex;
+    align-items: center;
+    margin-top: 17px;
+    position: relative;
+    span{
+      font-size: 14px;
+      margin-right: 20px;
+    }
+    .tab-select{
+      margin-right: 20px;
+    }
+    .default {
+      position: absolute;
+      right: 0;
+      cursor: pointer;
+      line-height: 32px;
+      width: 104px;
+      height: 32px;
+    }
+  }
+  .tab-search{
+      float: right;
+      position: relative;
+      width: 200px;
+      padding-left: 10px;
+      margin-right: 15px;
+      border: 1px solid #ccc;
+      display: flex;
+      .iconfont{
+        width: 28px;
+        height: 28px;
+        padding: 6px;
+        background: #e4e4e4;
+        cursor: pointer;
+      }
+      input{
+        width: 100%;
+        font-size: 14px;
+        appearance: none;
+        line-height: 28px;
+        height: 28px;
+        border: 0;
+      }
+    }
+  .tab-select{
+      float: right;
+      position: relative;
+      width: 200px;
+      height: 32px;
+      line-height: 32px;
+      padding-left: 10px;
+      border: 1px solid $border-color;
+      font-size: 14px;
+      color: #969696;
+      cursor: pointer;
+      &::after{
+        position: absolute;
+        right: 10px;
+        top: 50%;
+        transform: translateY(calc(-50% + 3px));
+        content: '';
+        width: 0;
+        height: 0;
+        border: 5px solid;
+        display: inline-block;
+        border-color: #828282 transparent transparent;
+      }
+      ul{
+        position: absolute;
+        max-height: 0;
+        left: 0;
+        top: 34px;
+        background: #fff;
+        overflow: hidden;
+        width: 100%;
+        transition:all 0.3s ease;
+        box-shadow: 0 0 10px rgba($color: #000000, $alpha: 0.4);
+        li{
+          padding-left: 10px;
+          &:hover{
+            background: $theme-color;
+            color: #2d2d2d;
+          }
+        }
+      }
+    }
+    .tab-active{
+      ul{
+        max-height: 220px;
+        overflow: auto;
+      }
+    }
+  .table-list{
+    padding: 0 30px;
+    &>div{
+      width: 100%;
+    }
+    .edit{
+      color: $theme-color;
+      cursor: pointer;
+    }
+  }
+  .scene-nothing{
+    padding: 42px 0 0 40px;
+    text-align: center;
+    img{
+      padding-bottom: 22px;
+    }
+    div{
+      font-size: 16px;
+      color: #969696;
+      text-align: center;
+    }
+  }
+  .paging {
+    height: 100%;
+  }
+}
+
+</style>
+
+<style lang="less">
+.consump-layout {
+  .table-list {
+    border: 1px solid rgba(235, 235, 235, 1);
+    .t-header, .t-item {
+      line-height: 52px;
+      border-bottom: 1px solid rgba(32, 32, 32, 0.2);
+      font-size: 14px;
+      padding: 0 !important;
+    }
+  }
+}
+</style>

+ 107 - 0
src/views/pc/order/components/deviceOrder.vue

@@ -0,0 +1,107 @@
+<template>
+  <div>
+    <div v-if="total">
+      <div class="order-item" v-for="(item,i) in myorder.list" :key="item.orderSn">
+        <OrderItem :item="item" :i="i" @isOrderInvoice="edit"  />
+      </div>
+    </div>
+    <div class="scene-nothing" v-else>
+      <img :src="`${$cdn}images/nothing.png`" alt>
+      <div>{{$t('manage.myOrders.norecord')}} 
+        <a class="gotoBuy" @click="$router.push({name: 'mallHome'})">{{$t('manage.gotoBuy')}}</a>
+      </div>
+    </div>
+    <div class="paging" v-if="total">
+      <Paging @clickHandle="pageChange" @maxPage="data=>maxPage=data" :current="currentPage" :total="total" :equable="pageSize"/>
+    </div>
+  </div>
+</template>
+
+<script>
+import OrderItem from './orderItem'
+import { mapState } from 'vuex'
+import Paging from '@/components/Paging'
+import Vue from 'vue'
+export default {
+  provide () {
+    return {
+      getList: this.getList
+    }
+  },
+  data () {
+    return {
+      pageSize: 5,
+      currentPage: 1,
+      total: 0,
+      maxPage: 0,
+      showInvoice: false,
+      currentI: '',
+      currentItem: ''
+    }
+  },
+  
+  watch: {
+    currentPage () {
+      this.getList()
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token,
+      language: state => state.language.current,
+      myorder: state => {
+        let type = Object.prototype.toString.call(state.user.myorder)
+        if (type === '[object Object]') {
+          return state.user.myorder
+        }
+        let condition = state.user.myorder && state.user.myorder !== 'null' && type !== '[object Array]'
+        return condition ? JSON.parse(state.user.myorder) : {}
+      }
+    })
+  },
+  components: {
+    OrderItem,
+    Paging
+  },
+  mounted () {
+    this.getList()
+  },
+  methods: {
+    edit (bool) {
+      console.log(bool)
+      this.$bus.$emit('isOrderInvoice', bool)
+    },
+    
+    pageChange (data) {
+      this.currentPage = data
+    },
+    async getList () {
+      window.scrollTo(0, 0)
+      let params = {
+        type: '',
+        pageNum: this.currentPage,
+        pageSize: this.pageSize
+      }
+      await this.$store.dispatch('getUserOrder', params)
+      this.pageSize = this.myorder.pageSize
+      this.total = this.myorder.total || 0
+    },
+    
+    
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.scene-nothing {
+  text-align: center;
+  padding: 42px 0 210px 0;
+  img {
+    padding-bottom: 22px;
+  }
+  div {
+    font-size: 16px;
+    color: #969696;
+  }
+}
+</style>

+ 400 - 0
src/views/pc/order/components/downItem.vue

@@ -0,0 +1,400 @@
+<template>
+  <div class="order-item" :key="i">
+        <!-- <div class="o-top"></div> -->
+        <div class="o-title">
+          <span>
+            <span class="orderSn table-header">{{$t('manage.myOrders.numbers')}}{{item.orderSn}}</span>
+            <span class="orderTime">{{ item.tradeTime }}</span>
+          </span>
+          <span class="table-header">{{$t('manage.myOrders.total1')}}</span>
+        </div>
+        <div class="o-detail">
+          <div class="od-name">
+            <div>
+              <!-- <p>{{ item.status }}{{$t('manage.myOrders.recname')}}</p> -->
+              <p>{{ item.sceneName }}{{item.sceneNum && `(${item.sceneNum})`}}{{$t('manage.Spending.rechargeLabel.downdesc')}}</p>
+              <p>{{$t('manage.Spending.listLabel.payType')}}:{{ PAYSIDMAP[item.payType] }}</p>
+            </div>
+          </div>
+          <div class="sum total-momey">{{item.amount || 0}}</div>
+        </div>
+
+        <div class="inovice-con" :class="{'ic-active':item.showInvoice}">
+          <div class="o-invoiceTitle">
+            <span>{{$t('manage.myOrders.invoice')}}</span>
+            <span v-if="getStatus(item) !== 'shipped'" @click="edit"><i class="iconfont icon-edit"></i>{{$t('manage.myOrders.edit')}}</span>
+            <!-- <span v-else><i class="iconfont icon-choice"></i>发票已寄出</span> -->
+          </div>
+          <div class="o-invoice">
+            <editInvoice :data="getItemInvoice(item)" :orderId='item.id' :invoiceId="item.invoice&&(item.invoice.id)"/>
+          </div>
+        </div>
+        <div class="bottom-area">
+          <div class="to-pay">
+            <template v-if="getStatus(item) !== 'expire'">
+              <span class="cancel btns" @click="changeIvoiceStatus(i,item)">
+                {{item.invoice && item.invoice.type ? $t('manage.myOrders.invoiceInfo') : $t('manage.myOrders.invoice')}}
+              </span>
+            </template>
+          </div>
+        </div>
+      </div>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+import editInvoice from '@/components/editInvoice'
+import MallConfig from '@/config/mall'
+
+export default {
+  props: {
+    item: Object,
+    i: Number
+  },
+  provide () {
+    return {
+      hideInvoice: this.hideInvoice,
+      saveInvoiceData: this.saveInvoice
+    }
+  },
+  data () {
+    return {
+      PAYSIDMAP: MallConfig.PAYSIDMAP,
+      showInvoice: true
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token,
+      language: state => state.language.current,
+      myorder: state => {
+        let type = Object.prototype.toString.call(state.user.myorder)
+        if (type === '[object Object]') {
+          return state.user.myorder
+        }
+        let condition = state.user.myorder && state.user.myorder !== 'null' && type !== '[object Array]'
+        return condition ? JSON.parse(state.user.myorder) : {}
+      }
+    })
+  },
+  components: {
+    editInvoice
+  },
+  mounted () {
+    this.$set(this.item, 'showInvoice', false)
+  },
+  methods: {
+    edit () {
+      this.showInvoice = false
+    },
+    hideInvoice () {
+      this.showInvoice = true
+    },
+    changeIvoiceStatus (i, item) {
+      // item.showInvoice = !item.showInvoice
+      // this.$set(this.item, 'showInvoice', item.showInvoice)
+      // this.$bus.emit('order/showInvoice', item)
+
+      
+      this.$bus.$emit('order/showInvoice', {
+        order: item,
+        orderId: item.id,
+        data: this.getItemInvoice(item),
+        invoiceId: item.invoice&&(item.invoice.id)
+      })
+    },
+    saveInvoice (data) {
+      this.$set(this.item, 'invoice', data)
+    },
+    getItemInvoice (item) {
+      let invoice = item.invoice
+      if (!invoice) {
+        return ''
+      }
+      invoice['typeName'] = this.$t(`manage.invoiceTypeName.${invoice.type}`)
+      return invoice
+    },
+    getStatus (item) {
+      let temp = ''
+      let sPay = function () {
+        switch (item.shippingStatus) {
+          case 'unshipped':
+            temp = 'unshipped'
+            break
+          case 'partShipped':
+            temp = 'partShipped'
+            break
+          case 'shipped':
+            temp = 'shipped'
+            break
+          case 'received':
+            temp = 'received'
+            break
+          default:
+            break
+        }
+      }
+      let pPay = function () {
+        switch (item.paymentStatus) {
+          case 'unpaid':
+            temp = 'unpaid'
+            break
+          case 'paid':
+            sPay()
+            break
+          default:
+            break
+        }
+      }
+
+      switch (item.orderStatus) {
+        case 'unprocessed':
+          pPay()
+          break
+        case 'completed':
+          temp = 'finish'
+          break
+        case 'processed':
+          sPay()
+          break
+        case 'expire':
+          temp = 'expire'
+          break
+        default:
+          break
+      }
+      return temp
+    },
+    toPay (item) {
+      this.$router.push({
+        name: 'pay',
+        query: {
+          payType: 0,
+          orderId: item.id,
+          orderType: 0,
+          orderSn: item.orderSn
+        }
+      })
+    },
+    async cancal (item) {
+      this.$toast.showConfirm('warn', this.$t('toast.15'), async () => {
+        let params = {
+          orderId: item.id
+        }
+        let res = await this.$http({
+          method: 'post',
+          data: params,
+          headers: {
+            token: this.token
+          },
+          url: '/user/order/cancel'
+        })
+        let data = res.data
+        if (data.code === 0) {
+          return this.$toast.show('success', this.$t('toast.37'), () => {
+            this.currentPage = this.currentPage >= this.maxPage ? this.maxPage : this.currentPage
+            this.getList()
+          })
+        }
+        return this.$toast.show('error', this.$t('toast.38'))
+      })
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.order-item {
+    margin-bottom: 40px;
+    border: 1px solid #EBEBEB;
+    .inovice-con{
+      max-height: 0;
+      overflow: hidden;
+    }
+    .ic-active{
+      max-height: 500px;
+      transition: 0.3s ease max-height;
+    }
+    .o-top {
+      color: #68b8f1;
+      line-height: 60px;
+      height: 60px;
+      font-size: 16px;
+      padding: 0 20px;
+      user-select: none;
+      border-bottom: 1px solid #EBEBEB;
+    }
+    .o-title,.o-invoiceTitle {
+      user-select: none;
+      display: flex;
+      height: 32px;
+      padding: 0 20px;
+      align-items: center;
+      line-height: 32px;
+      // border-bottom: 1px solid #EBEBEB;
+      background: #F7F7F7;
+      span {
+        font-size: 14px;
+        flex: 1;
+        text-align: center;
+        &:first-child {
+          flex: 5;
+          text-align: left;
+        }
+      }
+    }
+    .orderSn {
+      color: #323233;
+      margin-right: 15px;
+    }
+    .o-invoiceTitle{
+      align-items: center;
+      .iconfont{
+        vertical-align: middle;
+        font-size: 20px;
+        margin-right: 5px;
+      }
+      .icon-edit{
+        color: #15BEC8;
+      }
+      .icon-choice{
+        color: #02e430;
+      }
+      span {
+        display: inline-block;
+        vertical-align: middle;
+        &:last-child{
+          transform: translateX(11px);
+          cursor: pointer;
+        }
+        &:first-child {
+          flex: 1;
+          transform: translateX(0);
+          text-align: left;
+        }
+      }
+    }
+    .o-invoice{
+      display: flex;
+      align-items: center;
+      padding: 10px 20px 10px 85px;
+      color: #4a4a4a;
+      font-size: 14px;
+      border-bottom: 1px solid #EBEBEB;
+    }
+
+    .o-detail {
+      display: flex;
+      align-items: center;
+      height: 86px;
+      line-height: 86px;
+      padding: 0 20px;
+      color: #4a4a4a;
+      font-size: 14px;
+      border-bottom: 1px solid #EBEBEB;
+      .od-name {
+        display: flex;
+        align-items: center;
+        flex: 5;
+        .thumbnail {
+          width: 55px;
+          margin-right: 10px;
+        }
+        p {
+          line-height: 1.5;
+          font-size: 14px;
+          color: #969696;
+          &:first-of-type{
+           font-weight: bold;
+           color: #2d2d2d;
+          }
+        }
+      }
+      .count {
+        flex: 1;
+        text-align: center;
+      }
+      .sum {
+        flex: 1;
+        text-align: center;
+      }
+    }
+    .sum-price {
+      display: flex;
+      height: 40px;
+      line-height: 40px;
+      padding: 0 40px;
+      border-bottom: 1px solid #EBEBEB;
+      div {
+        flex: 2;
+        color: #4a4a4a;
+        font-size: 14px;
+        &:last-child {
+          flex: 1;
+          text-align: right;
+        }
+      }
+    }
+
+    .bottom-area{
+      position: relative;
+      .bottom-left{
+        position: absolute;
+        top: 50%;
+        left: 20px;
+        color: #a0a0a0;
+        transform: translateY(-50%);
+        font-size: 14px;
+        color: #323233;
+      }
+      .to-pay {
+        text-align: right;
+        height: 50px;
+        line-height: 50px;
+        padding: 0 25px;
+        .cancel {
+          font-size: 14px;
+          // border: 1px solid #ccc;
+          display: inline-block;
+          text-align: center;
+          cursor: pointer;
+          background: #fff;
+          color: #202020;
+          border: 1px solid #323233;
+          width: 104px;
+          height: 32px;
+          line-height: 32px;
+          border-radius: 4px;
+        }
+        .pay {
+          background: #15BEC8;
+          font-size: 14px;
+          color: #fff;
+          display: inline-block;
+          width: 104px;
+          height: 32px;
+          line-height: 32px;
+          text-align: center;
+          cursor: pointer;
+        }
+        .expreeNum {
+          margin-right: 60px;
+          color: #323233;
+          
+        }
+      }
+    }
+
+  }
+
+  .table-header {
+    font-weight: 600;
+    color: #202020;
+
+  }
+
+  .total-momey {
+    font-weight: 400;
+    color: #202020;
+    font-size: 20px;
+  }
+</style>

+ 394 - 0
src/views/pc/order/components/downOrder.vue

@@ -0,0 +1,394 @@
+<template>
+  <div>
+    <div v-if="total">
+      <div class="order-item" v-for="(item,i) in data" :key="item.orderSn">
+        <InterestsItem :item="item" :i="i"  />
+      </div>
+    </div>
+    <div class="scene-nothing" v-else>
+      <img :src="`${$cdn}images/nothing.png`" alt>
+      <div>{{$t('manage.myOrders.norecord')}} 
+        <!-- <a class="gotoBuy" >{{$t('manage.gotoBuy')}}</a> -->
+      </div>
+    </div>
+    <div class="paging" v-if="total">
+      <Paging @clickHandle="pageChange" @maxPage="data=>maxPage=data" :current="currentPage" :total="total" :equable="pageSize"/>
+    </div>
+  </div>
+</template>
+
+<script>
+
+import InterestsItem from './downItem.vue'
+import { mapState } from 'vuex'
+import tableList from '@/components/table'
+import {capacity, recharge, invoice} from './iconsumption'
+import Paging from '@/components/Paging'
+import vcenter from '@/components/vcenter'
+import MemberApi from '@/apis/member'
+import MallConfig from '@/config/mall'
+import { i18n } from '@/lang'
+
+let AMOUNTSTR = {
+  0: '¥',
+  1: '¥',
+  2: '$'
+}
+
+let methodStr = {
+  0: 'getMemberOrderList',
+  1: 'getChargeList',
+  2: 'getInvoiceList'
+}
+let rechargeType = {
+  0: i18n.t('manage.Spending.rechargeValue.0'),
+  '-1': i18n.t('manage.Spending.rechargeValue.-1'),
+  1: i18n.t('manage.Spending.rechargeValue.1'),
+  2: i18n.t('manage.Spending.rechargeValue.2')
+}
+
+let invoceStatusType = {
+  0: '未开票',
+  1: '已开票'
+}
+
+let invoiceType = {
+  1: '不需要发票',
+  2: '增值税普通发票',
+  3: '增值税专用发票'
+}
+
+export default {
+  components: {
+    tableList,
+    Paging,
+    vcenter,
+    InterestsItem
+  },
+  data () {
+    let cameraList = [
+      {
+        name: '全部',
+        id: ''
+      },
+      {
+        name: '二目充值',
+        id: 0
+      },
+      {
+        name: '会员权益',
+        id: 4
+      }
+    ]
+    return {
+      PAYSIDMAP: MallConfig.PAYSIDMAP,
+      tabHeader: capacity,
+      data: [],
+      cameraList,
+      active: 1,
+      recharge,
+      total: 30,
+      pageSize: 5,
+      currentPage: 1,
+      tabActive: false,
+      deviceActive: false,
+      max: 0,
+      activeDevice: '',
+      activeType: '全部',
+      activeId: '',
+      activeTypeId: '',
+      tabList: [
+        {
+          name: this.$t('manage.Spending.tabListMember')
+        },
+        {
+          name: this.$t('manage.Spending.tabListRecharge')
+        },
+        {
+          name: this.$t('manage.Spending.tabListInvoice')
+        },
+      ]
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token,
+      language: state => state.language.current,
+      deviceLogin: state => state.user.deviceLogin,
+      // 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 : [])
+      },
+      searchKey () {
+        return this.$parent.searchKey
+      }
+    })
+  },
+  watch: {
+    currentPage (newVal) {
+      this.getList()
+    },
+    language (newVal) {
+      this.active = 0
+      this.data.forEach(item => {
+        let condition = item['validDate'] === '终身有效' ? (newVal === 'en' ? 'N/A' : '终身有效') : item['validDate']
+        item['validDateStr'] = condition
+        item['unitSize1'] = item['unitSize'] + item['unit'] + '/' + this.$t(`manage.shixian.${item['month']}`)
+        item['channel'] = this.$t(`manage.channelType.${item['status']}`)
+        item['amount1'] = AMOUNTSTR[item['payType']] + item['amount']
+        item['payTypeStr'] = this.$t(`manage.PAYSSTR.${item['payType']}`)
+      })
+    },
+    activeId (newVal) {
+      if (this.active === 2) {
+        this.getList()
+      }
+      this.getInvoiceMax()
+    },
+    activeTypeId (newVal) {
+      if (this.active === 2) {
+        this.getList()
+      }
+    },
+    active (newVal) {
+      switch (newVal) {
+        case 1:
+          this.tabHeader = recharge
+          break
+        case 2:
+          !this.deviceLogin && this.getAllDevice()
+          this.tabHeader = invoice
+          break
+        default:
+          this.tabHeader = capacity
+          break
+      }
+      if (newVal !== 1) {
+        this.$emit('changeSearchShow', false)
+      } else {
+        this.$emit('changeSearchShow', true)
+      }
+      this.currentPage === 1 ? this.getList() : this.currentPage = 1
+    }
+  },
+  methods: {
+    pageChange (data) {
+      this.currentPage = data
+    },
+    selectInId (item) {
+      this.activeDevice = item.childName
+      this.activeId = item.id
+    },
+    selectCamTy (item) {
+      this.activeType = item.name
+      this.activeTypeId = item.id
+    },
+    showDetail (item) {
+      this.$toast.showInvoiceDetail(item)
+    },
+    getList (searchKey = '') {
+      window.scrollTo(0, 0)
+      let str = methodStr[this.active]
+      this[str](searchKey)
+    },
+    openInvice () {
+      let params = {
+        max: this.max,
+        cameraId: this.activeId
+      };
+      (this.max && !this.deviceLogin) && this.$toast.showInvoice(params)
+    },
+    async getAllDevice (searchKey = '') {
+      let params = {
+        cameraType: ''
+      }
+      await this.$store.dispatch('getInvoiceDevice', params)
+      this.activeDevice = this.invoicedevice[0].childName
+      this.activeId = this.invoicedevice[0].id
+    },
+
+    // 扩容记录
+    async getConsumpList (searchKey = '') {
+      if (this.deviceLogin) {
+        searchKey = this.deviceLogin
+      }
+      let data = {
+        params: {
+          childName: searchKey.trim(),
+          pageNum: searchKey ? 1 : this.currentPage,
+          pageSize: this.pageSize
+        },
+        url: this.deviceLogin ? '/device/virtualOrder/expansionList' : '/user/virtualOrder/expansionList'
+      }
+      await this.$store.dispatch('getUserExpansion', data)
+      if (!this.myexpansion.total && searchKey && !this.deviceLogin) {
+        return this.$toast.show('warn', this.$t('toast.25'), () => {
+          this.getList()
+        })
+      }
+      console.log(this.myexpansion, 'this.myexpansion')
+      this.pageSize = this.myexpansion.pageSize
+      this.total = this.myexpansion.total || 0
+      this.data = this.myexpansion.list
+      this.data.forEach(item => {
+        let condition = item['validDate'] === '终身有效' ? (this.language === 'en' ? 'N/A' : '终身有效') : item['validDate']
+        item['validDateStr'] = condition
+        item['statusStr'] = this.$t(`manage.myOrders.${item['status']}`)
+        item['unitSize1'] = item['unitSize'] + item['unit'] + '/' + this.$t(`manage.shixian.${item['month']}`)
+        item['channel'] = this.$t(`manage.channelType.${item['status']}`)
+        item['amount1'] = AMOUNTSTR[item['payType']] + item['amount']
+        item['payTypeStr'] = this.$t(`manage.PAYSSTR.${item['payType']}`)
+      })
+    },
+    getMemberOrderList () {
+      let data = {
+        snCode: this.searchKey,
+        pageNum: this.currentPage,
+        pageSize: this.pageSize
+      }
+      MemberApi.getVirtualOrderList(data).then(res => {
+        this.data = res.data.data.list
+        console.log(this.data)
+        this.total = res.data.data.total
+      })
+    },
+    async getInvoiceMax () {
+      let res = await this.$http({
+        method: 'post',
+        data: {
+          cameraId: this.activeId
+        },
+        headers: {
+          token: this.token
+        },
+        url: '/user/invoice/max'
+      })
+
+      let data = res.data
+      if (data.code !== 0) return
+      this.max = data.data.maxInvoice
+    },
+
+    // 充值记录
+    async getChargeList (searchKey = '') {
+      if (this.deviceLogin) {
+        searchKey = this.deviceLogin
+      }
+      let data = {
+        params: {
+          pageNum: searchKey ? 1 : this.currentPage,
+          pageSize: this.pageSize
+        },
+        url:`/user/virtualOrder/downloadOrderList`
+      }
+      await this.$store.dispatch('getChargeList', data)
+      if (!this.mycharge.total && searchKey && !this.deviceLogin) {
+        return this.$toast.show('warn', this.$t('toast.25'), () => {
+          this.getList()
+        })
+      }
+      this.pageSize = this.mycharge.pageSize
+      this.total = this.mycharge.total || 0
+      this.data = this.mycharge.list
+      this.data.forEach(item => {
+        item['status'] = rechargeType[item['status']]
+      })
+
+      console.log(this.data)
+    },
+
+    // 发票记录
+    async getInvoiceList () {
+      let data = {
+        params: {
+          cameraId: this.activeId,
+          pageNum: this.currentPage,
+          pageSize: this.pageSize,
+          type: this.activeTypeId
+        },
+        url: this.deviceLogin ? '/device/invoice/list' : '/user/invoice/list'
+      }
+
+      await this.$store.dispatch('getInvoiceList', data)
+      this.pageSize = this.myinvoicelist.pageSize
+      this.total = this.myinvoicelist.total || 0
+      this.data = this.myinvoicelist.list
+      this.data.forEach(item => {
+        item['detail'] = '详细'
+        item['money'] = '¥' + item['money']
+        item['finish'] = invoceStatusType[item['finish']]
+        item['type'] = invoiceType[item['type']]
+      })
+    },
+    handleSearch (keyword) {
+      this.getList(keyword)
+    }
+  },
+  mounted () {
+    this.getList()
+
+    this.$bus.$off('refreshInvoice')
+    this.$bus.$on('refreshInvoice', () => {
+      if (this.active === 2) {
+        this.getList()
+      }
+      this.getInvoiceMax()
+    })
+
+    document.addEventListener('click', (e) => {
+      if (this.$refs.invoiceMenu) {
+        if (!this.$refs.invoiceMenu.contains(e.target)) {
+          this.tabActive = false
+        }
+      }
+      if (this.$refs.deviceMenu) {
+        if (!this.$refs.deviceMenu.contains(e.target)) {
+          this.deviceActive = false
+        }
+      }
+    })
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.scene-nothing {
+  text-align: center;
+  padding: 42px 0 210px 0;
+  img {
+    padding-bottom: 22px;
+  }
+  div {
+    font-size: 16px;
+    color: #969696;
+  }
+}
+</style>

+ 544 - 0
src/views/pc/order/components/editInvoice.vue

@@ -0,0 +1,544 @@
+<template>
+  <div class="invoice edit-invoice" slot="edit">
+    <div class="select-con edit-item">
+      <span>{{$t('manage.account.invoiceModule.invoiceType')}}</span>
+      <div :class="{'tag-active':invoice===null}" @click="invoice=null" v-show="false">
+        <span>{{$t('manage.myOrders.type1')}}</span>
+        <img :src="`${$cdn}images/tag-icon.png`" alt />
+      </div>
+
+      <div :class="{'tag-active':invoice===2}" @click="invoice=2">
+        <span>{{$t('manage.myOrders.type2')}}</span>
+        <img :src="`${$cdn}images/tag-icon.png`" alt />
+      </div>
+      <div :class="{'tag-active':invoice===3}" @click="invoice=3">
+        <span>{{$t('manage.myOrders.type3')}}</span>
+        <i></i>
+        <img :src="`${$cdn}images/tag-icon.png`" alt />
+      </div>
+    </div>
+    <div class="invoice-input" v-if="invoice===2">
+      <div class="input-con edit-item">
+        <span>{{$t('manage.account.invoiceModule.title')}}</span>
+        <input @input="errMsg = checkParams(invoice).errMsg,showMsg.title = true" type="text" :placeholder="$t('manage.myOrders.title')" maxlength="20" v-model="editInvoice2.title" />
+        <p class="errmsg">{{showMsg.title && errMsg.title}}</p>
+      </div>
+      <div class="input-con edit-item">
+        <span>{{$t('manage.account.invoiceModule.invoiceShui')}}</span>
+        <input
+          @input="e => { (errMsg = checkParams(invoice).errMsg), showMsg.code = true}"
+          maxlength="18"
+          v-model="editInvoice2.code"
+          type="text"
+          :placeholder="$t('manage.myOrders.code')"
+          oninput="value=value.replace(/[^\w\.\/]/ig,'')"
+        />
+        <p class="errmsg">{{showMsg.code && errMsg.code}}</p>
+      </div>
+      <div class="input-con edit-item">
+        <span>{{$t('manage.account.invoiceEmail')}}</span>
+        <input @input="errMsg = checkParams(invoice).errMsg, showMsg.email = true" type="text" :placeholder="$t('manage.myOrders.email')" maxlength="30" v-model="editInvoice2.emailAddress" />
+        <p class="errmsg">{{showMsg.email && errMsg.email}}</p>
+      </div>
+      <div class="input-con edit-item">
+        <span>{{$t('manage.account.placeholder.shipMobile')}}</span>
+        <input @input="errMsg = checkParams(invoice).errMsg, showMsg.phone = true" type="text" :placeholder="$t('manage.account.placeholder.phone')" maxlength="20" oninput="value=value.replace(/[^\d\-]/g,'')" v-model="editInvoice2.shipMobile" />
+        <p class="errmsg">{{showMsg.phone && errMsg.phone}}</p>
+      </div>
+    </div>
+    <div class="invoice-input" v-if="invoice===3">
+      <div class="input-con" style="padding-left: 30px" v-if="(!this.shaddress || !this.shaddress.id || !this.shaddress.shipMobile)">
+        <Address class="invoice-address-module" ref="address" />
+        <p class="errmsg">{{showMsg.shaddress && errMsg.shaddress}}</p>
+      </div>
+      <template v-else>
+        <div class="input-con edit-item">
+          <span>{{$t('manage.account.invoiceModule.title')}}</span>
+          <input @input="errMsg = checkParams(invoice).errMsg,showMsg.title1=true" type="text" v-model="editInvoice3.title" maxlength="20" :placeholder="$t('manage.myOrders.title')"/>
+          <p class="errmsg">{{showMsg.title1 && errMsg.title}}</p>
+        </div>
+        <div class="input-con edit-item">
+          <span>{{$t('manage.account.invoiceModule.invoiceShui')}}</span>
+          <input
+            @input="e => {(errMsg = checkParams(invoice).errMsg),showMsg.code1 = true}"
+            maxlength="18"
+            v-model="editInvoice3.code"
+            type="text"
+            oninput="value=value.replace(/[^\w\.\/]/ig,'')"
+            :placeholder="$t('manage.myOrders.code')"
+          />
+          <p class="errmsg">{{showMsg.code1 && errMsg.code}}</p>
+        </div>
+        <div class="input-con edit-item">
+          <span>{{$t('manage.account.invoiceModule.address')}}</span>
+          <input
+            @input="errMsg = checkParams(invoice).errMsg, showMsg.organizedAddress = true"
+            type="text"
+            maxlength="100"
+            v-model="editInvoice3.organizedAddress"
+            :placeholder="$t('manage.myOrders.organizedAddress')"
+          />
+          <p class="errmsg">{{showMsg.organizedAddress && errMsg.organizedAddress}}</p>
+        </div>
+        <div class="input-con edit-item">
+          <span>{{$t('manage.account.invoiceModule.phone')}}</span>
+          <input @input="errMsg = checkParams(invoice).errMsg,showMsg.guhua=true" type="text" maxlength="20" oninput="value=value.replace(/[^\d\-]/g,'')" v-model="editInvoice3.registerPhone" :placeholder="$t('manage.myOrders.registerPhone')"/>
+          <p class="errmsg">{{showMsg.guhua && errMsg.guhua}}</p>
+        </div>
+        <div class="input-con edit-item">
+          <span>{{$t('manage.account.invoiceModule.bank')}}</span>
+          <input @input="errMsg = checkParams(invoice).errMsg,showMsg.bankName=true" type="text" maxlength="40" v-model="editInvoice3.bankName" :placeholder="$t('manage.myOrders.bankName')" />
+          <p class="errmsg">{{showMsg.bankName && errMsg.bankName}}</p>
+        </div>
+        <div class="input-con edit-item">
+          <span>{{$t('manage.account.invoiceModule.bankAccount')}}</span>
+          <input @input="errMsg = checkParams(invoice).errMsg,showMsg.bankAccount=true" type="text" maxlength="40" v-model="editInvoice3.bankAccount" :placeholder="$t('manage.myOrders.bankAccount')"  />
+          <p class="errmsg">{{showMsg.bankAccount && errMsg.bankAccount}}</p>
+        </div>
+        <div class="input-con edit-item">
+          <span>{{$t('manage.account.placeholder.shipMobile')}}</span>
+          <input @input="errMsg = checkParams(invoice).errMsg, showMsg.phone = true" type="text" :placeholder="$t('manage.account.placeholder.phone')" maxlength="20" oninput="value=value.replace(/[^\d\-]/g,'')" v-model="editInvoice3.shipMobile" />
+          <p class="errmsg">{{showMsg.phone && errMsg.phone}}</p>
+        </div>
+      </template>
+
+    </div>
+    <div class="bottom-floot">
+      <div @click="hideInvoice" class="btn">{{$t('manage.myOrders.cancal1')}}</div>
+      <div @click="saveInvoice(invoice)" class="btn parmary">{{$t('manage.myOrders.save')}}</div>
+    </div>
+  </div>
+</template>
+<script>
+import { reg } from '@/util'
+import { mapState } from 'vuex'
+import address from '@/page/mall/confirm/components/addressModule'
+
+export default {
+  props: ['data', 'orderId', 'invoiceId', 'consumeType'],
+  inject: ['hideInvoice', 'saveInvoiceData'],
+  data: function () {
+    return {
+      showMsg: {},
+      errMsg: {},
+      editInvoice2: this.data.type === 2 ? this.data : {},
+      editInvoice3: this.data.type === 3 ? this.data : {},
+      invoice: this.data.type || 2
+    }
+  },
+  watch: {
+    data (newVal) {
+      this.invoice = newVal.type || 2
+      this.editInvoice2 = newVal.type === 2 ? newVal : {}
+      this.editInvoice3 = newVal.type === 3 ? newVal : {}
+    },
+    invoice () {
+      this.errMsg = this.checkParams(this.invoice).errMsg
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token,
+      shaddress: state => state.user.address,
+      language: state => state.language.current
+    })
+  },
+  mounted () {
+    this.errMsg = this.checkParams(this.invoice).errMsg
+  },
+  methods: {
+    checkParams (cInvoice) {
+      let invoiceType = ''
+      let isObject = function (obj) {
+        return JSON.stringify(obj) === '{}' ? '' : obj
+      }
+      let check = value => {
+        for (let i = 0, len = value.length; i < len; i++) {
+          if (!value[i].val) {
+            errMsg[value[i].key] = value[i].name + this.$t('toast.7')
+          }
+        }
+        return true
+      }
+      let params = {}
+      let errMsg = {}
+      console.log('cInvoice', cInvoice)
+      if (cInvoice === 2) {
+        invoiceType = 2
+        console.log(this.editInvoice2)
+        let title = isObject(this.editInvoice2.title)
+        let code = isObject(this.editInvoice2.code)
+        let emailAddress = isObject(this.editInvoice2.emailAddress)
+        let shipMobile = isObject(this.editInvoice2.shipMobile)
+
+        if (code && code.length !== 18) {
+          errMsg.code = this.$t('toast.21')
+        }
+        if (!reg.email.test(emailAddress)) {
+          errMsg.email = this.$t('toast.8')
+        }
+        //if (!shipMobile) {
+        //  errMsg.phone = this.$t('toast.22')
+        //}
+        params = {
+          invoiceType,
+          title,
+          code: code || '',
+          emailAddress,
+          shipMobile
+        }
+
+        let checkStr = [
+          {
+            name: this.$t('manage.account.invoiceTitle'),
+            val: title,
+            key: 'title'
+          },
+          {
+            name: this.$t('mall.invoiceEmail'),
+            val: emailAddress,
+            key: 'emailAddress'
+          },
+          {
+            name: this.$t('manage.account.placeholder.shipMobile'),
+            val: shipMobile,
+            key: 'shipMobile'
+          }
+        ]
+        check(checkStr)
+        if (shipMobile && !reg.phone.test(shipMobile)) {
+          errMsg.phone = this.$t('toast.22')
+        }
+      } else {
+        if ((!this.shaddress || !this.shaddress.id || !this.shaddress.shipMobile)) {
+          errMsg.shaddress = this.$t('manage.myOrders.unaddress')
+        } else {
+          delete errMsg.shaddress
+        }
+
+        let {title: title1, code: code1, shipMobile, organizedAddress: organizedAddress1, registerPhone: registerPhone1, bankName: bankName1, bankAccount: bankAccount1} = this.editInvoice3
+        invoiceType = 3
+        console.log('shipMobile', shipMobile, !reg.phone.test(shipMobile))
+        let title = isObject(title1)
+        let code = isObject(code1)
+        let organizedAddress = isObject(organizedAddress1)
+        let registerPhone = isObject(registerPhone1)
+        let bankName = isObject(bankName1)
+        let bankAccount = isObject(bankAccount1)
+
+        params = {
+          invoiceType,
+          title,
+          code: code || '',
+          organizedAddress,
+          registerPhone,
+          bankName,
+          bankAccount,
+          shipMobile
+        }
+        let checkStr = [
+          {
+            name: this.$t('manage.account.invoiceTitle'),
+            val: title,
+            key: 'title'
+          },
+          {
+            name: this.$t('manage.account.invoiceModule.code'),
+            val: code,
+            key: 'code'
+          },
+          {
+            name: this.$t('manage.account.invoiceModule.address'),
+            val: organizedAddress,
+            key: 'organizedAddress'
+          },
+          {
+            name: this.$t('manage.account.invoiceModule.phone'),
+            val: registerPhone,
+            key: 'registerPhone'
+          },
+          {
+            name: this.$t('manage.account.invoiceModule.bank'),
+            val: bankName,
+            key: 'bankName'
+          },
+          {
+            name: this.$t('manage.account.invoiceModule.bankAccount'),
+            val: bankAccount,
+            key: 'bankAccount'
+          },
+          {
+            name: this.$t('manage.account.placeholder.shipMobile'),
+            val: shipMobile,
+            key: 'shipMobile'
+          }
+        ]
+
+        check(checkStr)
+
+        if (!code || code.length !== 18) {
+          errMsg.code = this.$t('toast.21')
+        }
+
+        if (!reg.guhua.test(registerPhone)) {
+          errMsg.guhua = this.$t('toast.22')
+        }
+        if (shipMobile && !reg.phone.test(shipMobile)) {
+          errMsg.phone = this.$t('toast.22')
+        }
+      }
+
+      return {
+        errMsg,
+        params,
+        invoiceType
+      }
+    },
+    changeType (type) {
+      this.$emit('changtype', type)
+    },
+    saveInvoice (cInvoice) {
+      if (!cInvoice) {
+        if (this.invoiceId) {
+          this.$http
+            .post('user/invoice/delete', {
+              invoiceId: this.invoiceId
+            }, {
+              headers: {
+                token: this.token
+              }
+            })
+            .then(data => {
+              let response = data.data
+              if (response.code === 0) {
+                this.$bus.$emit('editItem', {
+                  id: '',
+                  type: null
+                })
+                ()
+              }
+            })
+        } else {
+          this.$bus.$emit('editItem', {
+            id: '',
+            type: null
+          })
+          this.hideInvoice()
+        }
+        return
+      }
+
+      let {params, invoiceType, errMsg} = this.checkParams(cInvoice)
+      let keys = Object.keys(errMsg)
+      if (keys.length) {
+        return this.$toast.show('warn', errMsg[keys[0]])
+      }
+
+      if (this.invoiceId) {
+        params['invoiceId'] = params['id'] = this.invoiceId || null
+      }
+      params['orderId'] = this.orderId
+      params['type'] = invoiceType
+      params['consumeType'] = this.consumeType
+      this.$http
+        .post('user/invoice/open', params, {
+          headers: {
+            token: this.token
+          }
+        })
+        .then(data => {
+          let response = data.data
+          if (response.code === 0) {
+            this.saveInvoiceData(response.data)
+            this.hideInvoice()
+          } else {
+            let key = `toast.${response.code}`
+            let msg = this.$t(key) && this.$t(key) !== key ? this.$t(key) : response.msg
+            this.$toast.show('warn', msg)
+          }
+        })
+    }
+  },
+  components: {
+    Address: address
+  }
+}
+</script>
+
+<style>
+.invoice-address-module h3{
+  display: none;
+}
+
+.invoice-address-module .submit-btn {
+  background-color: #15BEC8;
+  color: #fff;
+}
+
+.invoice-address-module .cancel-btn {
+  border: solid 1px #ccc;
+  background: none !important;
+  font-weight: 600;
+  color: #202020;
+}
+
+</style>
+
+<style lang="scss" scoped>
+$theme-color: #15BEC8;
+$border-color: #e7e7e7;
+input {
+  appearance: none;
+  line-height: 40px;
+  height: 40px;
+  border: solid 1px $border-color;
+  padding-left: 10px;
+  &:focus {
+    border: solid 1px $theme-color;
+  }
+}
+.btn {
+  text-align: center;
+  cursor: pointer;
+  width: 126px;
+  height: 36px;
+  line-height: 36px;
+  margin: 10px 25px 0 0;
+  display: inline-block;
+  border: solid 1px #ccc;
+}
+.parmary {
+  background-color: $theme-color;
+  border: solid 1px $theme-color;
+}
+.invoice {
+  margin-top: 20px;
+  p {
+    line-height: 18px;
+    margin-bottom: 8px;
+    overflow-wrap: break-word;
+    &:last-of-type {
+      margin-bottom: 0;
+    }
+    span {
+      padding-right: 10px;
+    }
+  }
+  .p-desc {
+    color: #a0a0a0;
+    overflow-wrap: break-word;
+    line-height: 24px;
+  }
+  .no-info {
+    margin-top: 4px;
+  }
+  .avatar {
+    width: 68px;
+    height: 68px;
+    box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4);
+    margin: 5px 0;
+  }
+  .nickname {
+    width: 126px;
+  }
+}
+.edit-invoice {
+  .select-con {
+    div {
+      position: relative;
+      cursor: pointer;
+      line-height: 36px;
+      height: 36px;
+      text-align: center;
+      margin: 10px 26px 10px 0;
+      border: solid 1px $border-color;
+      color: #a0a0a0;
+      padding: 0 10px;
+      display: inline-block;
+      font-size: 12px;
+      img {
+        display: none;
+        position: absolute;
+        bottom: 0;
+        right: 0;
+      }
+      &:last-of-type {
+        margin-right: 0;
+      }
+    }
+    .tag-active {
+      border: solid 1px $theme-color;
+      color: #000;
+      img {
+        display: inline-block;
+      }
+    }
+  }
+  .input-con {
+    input {
+      width: 316px;
+      line-height: 40px;
+      height: 40px;
+      margin: 10px 25px 10px 0;
+      &:last-of-type {
+        margin-right: 0;
+      }
+    }
+  }
+}
+
+.edit-item  {
+  position: relative;
+  padding-left: 130px;
+  margin: 20px 0;
+
+  .errmsg {
+    font-size: 12px;
+    font-family: PingFangSC-Regular, PingFang SC;
+    font-weight: 400;
+    color: #FF3E3E;
+    line-height: 12px;
+    top: 100%;
+    left: 130px;
+    position: absolute;
+  }
+
+  > span {
+    position: absolute;
+    left: 0;
+    top: 50%;
+    width: 100px;
+    text-align: right;
+    transform: translateY(-50%);
+    font-size: 14px;
+    font-family: PingFangSC-Regular, PingFang SC;
+    font-weight: 400;
+    color: #202020;
+    line-height: 20px;
+  }
+}
+
+.bottom-floot {
+  border-top: 1px solid #EBEBEB;
+  padding-top: 20px;
+  text-align: center;
+  width: calc(100% + 48px);
+
+  .btn {
+    border-radius: 4px;
+    margin: 0;
+    font-size: 14px;
+    font-family: PingFangSC-Semibold, PingFang SC;
+    font-weight: 600;
+    color: #202020;
+
+    &.parmary {
+      color: #fff;
+    }
+    &:first-child {
+      margin-right: 20px;
+    }
+  }
+}
+
+</style>

+ 74 - 0
src/views/pc/order/components/iconsumption.js

@@ -0,0 +1,74 @@
+import { i18n } from '@/lang'
+let capacity = [
+  {
+    key: 'orderSn',
+    name: i18n.t('manage.Spending.listLabel.orderId'),
+    width: 200
+  }, {
+    key: 'name',
+    name: i18n.t('manage.Spending.listLabel.memberName'),
+    width: 200,
+    staticName: '四维看看会员权益'
+  }, {
+    key: 'count',
+    name: i18n.t('manage.Spending.listLabel.count'),
+    width: 90
+  }, {
+    key: 'payType',
+    name: i18n.t('manage.Spending.listLabel.payType')
+  }, {
+    key: 'amount',
+    name: i18n.t('manage.Spending.listLabel.payNum')
+  }, {
+    key: 'tradeTime',
+    name: i18n.t('manage.Spending.listLabel.payTime'),
+    width: 200
+  }
+]
+
+let recharge = [
+  {
+    key: 'status',
+    name: i18n.t('manage.Spending.rechargeLabel.type')
+  }, {
+    key: 'body',
+    name: i18n.t('manage.Spending.rechargeLabel.name')
+  }, {
+    key: 'points',
+    name: i18n.t('manage.Spending.rechargeLabel.point')
+  }, {
+    key: 'childName',
+    name: i18n.t('manage.Spending.rechargeLabel.deviceName')
+  }, {
+    key: 'tradeTime',
+    name: i18n.t('manage.Spending.rechargeLabel.createTime')
+  }
+]
+
+let invoice = [
+  {
+    key: 'createTime',
+    name: i18n.t('manage.Spending.invoiceLabel.createTime')
+  }, {
+    key: 'type',
+    name: i18n.t('manage.Spending.invoiceLabel.type')
+  }, {
+    key: 'title',
+    name: i18n.t('manage.Spending.invoiceLabel.title')
+  }, {
+    key: 'money',
+    name: i18n.t('manage.Spending.invoiceLabel.money')
+  }, {
+    key: 'finish',
+    name: i18n.t('manage.Spending.invoiceLabel.status')
+  }, {
+    key: 'detail',
+    name: i18n.t('manage.Spending.invoiceLabel.detail'),
+    canclick: true
+  }
+]
+export {
+  capacity,
+  recharge,
+  invoice
+}

+ 409 - 0
src/views/pc/order/components/interestsItem.vue

@@ -0,0 +1,409 @@
+<template>
+  <div class="order-item" :key="i">
+        <!-- <div class="o-top"></div> -->
+        <div class="o-title">
+          <span>
+            <span class="orderSn table-header">{{$t('manage.myOrders.numbers')}}{{item.orderSn}}</span>
+            <span class="orderTime">{{ item.tradeTime }}</span>
+          </span>
+          <span class="table-header">{{$t('manage.myOrders.quantity')}}</span>
+          <span class="table-header">{{$t('manage.myOrders.subtotal')}}</span>
+          <span class="table-header">{{$t('manage.myOrders.total1')}}</span>
+        </div>
+        <div class="o-detail">
+          <div class="od-name">
+            <div>
+              <p>{{$t('manage.myOrders.memerText')}}</p>
+              <p>{{$t('manage.Spending.listLabel.payType')}}:{{ PAYSIDMAP[item.payType] }}</p>
+              <p style="word-break: break-all;" v-if="item.incrementIds" :title="item.incrementIds">{{$t('manage.member.memberPackage')}}:{{ item.incrementIds.join(",") }}</p>
+              <p v-else>{{$t('manage.member.memberPackage')}}:{{ item.incrementId }}</p>
+            </div>
+          </div>
+          <div class="count">{{item.count}}</div>
+          <div class="sum">{{item.amount}}</div>
+          <div class="sum total-momey">{{item.amount}}</div>
+        </div>
+
+        <div class="inovice-con" :class="{'ic-active':item.showInvoice}">
+          <div class="o-invoiceTitle">
+            <span>{{$t('manage.myOrders.invoice')}}</span>
+            <span v-if="getStatus(item) !== 'shipped'" @click="edit"><i class="iconfont icon-edit"></i>{{$t('manage.myOrders.edit')}}</span>
+            <!-- <span v-else><i class="iconfont icon-choice"></i>发票已寄出</span> -->
+          </div>
+          <div class="o-invoice">
+            <editInvoice :data="getItemInvoice(item)" :orderId='item.id' :invoiceId="item.invoice&&(item.invoice.id)"/>
+          </div>
+        </div>
+        <div class="bottom-area">
+          <div class="to-pay">
+            <template v-if="getStatus(item) !== 'expire'">
+              <span class="cancel btns" @click="changeIvoiceStatus(i,item)">{{item.invoice && item.invoice.type ?  $t('manage.myOrders.invoiceInfo') : $t('manage.myOrders.invoice')}}</span>
+            </template>
+          </div>
+        </div>
+      </div>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+import editInvoice from '@/components/editInvoice'
+import MallConfig from '@/config/mall'
+
+export default {
+  props: {
+    item: Object,
+    i: Number
+  },
+  provide () {
+    return {
+      hideInvoice: this.hideInvoice,
+      saveInvoiceData: this.saveInvoice
+    }
+  },
+  data () {
+    return {
+      PAYSIDMAP: MallConfig.PAYSIDMAP,
+      showInvoice: true
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token,
+      language: state => state.language.current,
+      myorder: state => {
+        let type = Object.prototype.toString.call(state.user.myorder)
+        if (type === '[object Object]') {
+          return state.user.myorder
+        }
+        let condition = state.user.myorder && state.user.myorder !== 'null' && type !== '[object Array]'
+        return condition ? JSON.parse(state.user.myorder) : {}
+      }
+    })
+  },
+  components: {
+    editInvoice
+  },
+  mounted () {
+    this.$set(this.item, 'showInvoice', false)
+  },
+  methods: {
+    edit () {
+      this.showInvoice = false
+    },
+    hideInvoice () {
+      this.showInvoice = true
+    },
+    changeIvoiceStatus (i, item) {
+      // item.showInvoice = !item.showInvoice
+      // this.$set(this.item, 'showInvoice', item.showInvoice)
+
+      
+      this.$bus.$emit('order/showInvoice', {
+        order: item,
+        orderId: item.id,
+        data: this.getItemInvoice(item),
+        invoiceId: item.invoice&&(item.invoice.id)
+      })
+    },
+    saveInvoice (data) {
+      this.$set(this.item, 'invoice', data)
+    },
+    getItemInvoice (item) {
+      let invoice = item.invoice
+      if (!invoice) {
+        return ''
+      }
+      invoice['typeName'] = this.$t(`manage.invoiceTypeName.${invoice.type}`)
+      return invoice
+    },
+    getStatus (item) {
+      let temp = ''
+      let sPay = function () {
+        switch (item.shippingStatus) {
+          case 'unshipped':
+            temp = 'unshipped'
+            break
+          case 'partShipped':
+            temp = 'partShipped'
+            break
+          case 'shipped':
+            temp = 'shipped'
+            break
+          case 'received':
+            temp = 'received'
+            break
+          default:
+            break
+        }
+      }
+      let pPay = function () {
+        switch (item.paymentStatus) {
+          case 'unpaid':
+            temp = 'unpaid'
+            break
+          case 'paid':
+            sPay()
+            break
+          default:
+            break
+        }
+      }
+
+      switch (item.orderStatus) {
+        case 'unprocessed':
+          pPay()
+          break
+        case 'completed':
+          temp = 'finish'
+          break
+        case 'processed':
+          sPay()
+          break
+        case 'expire':
+          temp = 'expire'
+          break
+        default:
+          break
+      }
+      return temp
+    },
+    toPay (item) {
+      this.$router.push({
+        name: 'pay',
+        query: {
+          payType: 0,
+          orderId: item.id,
+          orderType: 0,
+          orderSn: item.orderSn
+        }
+      })
+    },
+    async cancal (item) {
+      this.$toast.showConfirm('warn', this.$t('toast.15'), async () => {
+        let params = {
+          orderId: item.id
+        }
+        let res = await this.$http({
+          method: 'post',
+          data: params,
+          headers: {
+            token: this.token
+          },
+          url: '/user/order/cancel'
+        })
+        let data = res.data
+        if (data.code === 0) {
+          return this.$toast.show('success', this.$t('toast.37'), () => {
+            this.currentPage = this.currentPage >= this.maxPage ? this.maxPage : this.currentPage
+            this.getList()
+          })
+        }
+        return this.$toast.show('error', this.$t('toast.38'))
+      })
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.text-ellipsis{
+  overflow:hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  -o-text-overflow:ellipsis;
+}
+.order-item {
+    margin-bottom: 40px;
+    border: 1px solid #EBEBEB;
+    .inovice-con{
+      max-height: 0;
+      overflow: hidden;
+    }
+    .ic-active{
+      max-height: 500px;
+      transition: 0.3s ease max-height;
+    }
+    .o-top {
+      color: #68b8f1;
+      line-height: 60px;
+      height: 60px;
+      font-size: 16px;
+      padding: 0 20px;
+      user-select: none;
+      border-bottom: 1px solid #EBEBEB;
+    }
+    .o-title,.o-invoiceTitle {
+      user-select: none;
+      display: flex;
+      height: 32px;
+      padding: 0 20px;
+      align-items: center;
+      line-height: 32px;
+      // border-bottom: 1px solid #EBEBEB;
+      background: #F7F7F7;
+      span {
+        font-size: 14px;
+        flex: 1;
+        text-align: center;
+        &:first-child {
+          flex: 5;
+          text-align: left;
+        }
+      }
+    }
+    .orderSn {
+      color: #323233;
+      margin-right: 15px;
+    }
+    .o-invoiceTitle{
+      align-items: center;
+      .iconfont{
+        vertical-align: middle;
+        font-size: 20px;
+        margin-right: 5px;
+      }
+      .icon-edit{
+        color: #15BEC8;
+      }
+      .icon-choice{
+        color: #02e430;
+      }
+      span {
+        display: inline-block;
+        vertical-align: middle;
+        &:last-child{
+          transform: translateX(11px);
+          cursor: pointer;
+        }
+        &:first-child {
+          flex: 1;
+          transform: translateX(0);
+          text-align: left;
+        }
+      }
+    }
+    .o-invoice{
+      display: flex;
+      align-items: center;
+      padding: 10px 20px 10px 85px;
+      color: #4a4a4a;
+      font-size: 14px;
+      border-bottom: 1px solid #EBEBEB;
+    }
+
+    .o-detail {
+      display: flex;
+      align-items: center;
+      min-height: 86px;
+      line-height: 86px;
+      padding: 0 20px;
+      color: #4a4a4a;
+      font-size: 14px;
+      border-bottom: 1px solid #EBEBEB;
+      .od-name {
+        display: flex;
+        align-items: center;
+        flex: 5;
+        .thumbnail {
+          width: 55px;
+          margin-right: 10px;
+        }
+        p {
+          line-height: 1.5;
+          font-size: 14px;
+          color: #969696;
+          &:first-of-type{
+           font-weight: bold;
+           color: #2d2d2d;
+          }
+        }
+      }
+      .count {
+        flex: 1;
+        text-align: center;
+      }
+      .sum {
+        flex: 1;
+        text-align: center;
+      }
+    }
+    .sum-price {
+      display: flex;
+      height: 40px;
+      line-height: 40px;
+      padding: 0 40px;
+      border-bottom: 1px solid #EBEBEB;
+      div {
+        flex: 2;
+        color: #4a4a4a;
+        font-size: 14px;
+        &:last-child {
+          flex: 1;
+          text-align: right;
+        }
+      }
+    }
+
+    .bottom-area{
+      position: relative;
+      .bottom-left{
+        position: absolute;
+        top: 50%;
+        left: 20px;
+        color: #a0a0a0;
+        transform: translateY(-50%);
+        font-size: 14px;
+        color: #323233;
+      }
+      .to-pay {
+        text-align: right;
+        height: 50px;
+        line-height: 50px;
+        padding: 0 25px;
+        .cancel {
+          font-size: 14px;
+          // border: 1px solid #ccc;
+          display: inline-block;
+          text-align: center;
+          cursor: pointer;
+          background: #fff;
+          color: #202020;
+          border: 1px solid #323233;
+          width: 104px;
+          height: 32px;
+          line-height: 32px;
+          border-radius: 4px;
+        }
+        .pay {
+          background: #15BEC8;
+          font-size: 14px;
+          display: inline-block;
+          width: 104px;
+          height: 32px;
+          line-height: 32px;
+          color: #fff;
+          text-align: center;
+          cursor: pointer;
+          border-radius: 4px;
+        }
+        .expreeNum {
+          margin-right: 60px;
+          color: #323233;
+          
+        }
+      }
+    }
+
+  }
+
+  .table-header {
+    font-weight: 600;
+    color: #202020;
+
+  }
+
+  .total-momey {
+    font-weight: 400;
+    color: #202020;
+    font-size: 20px;
+  }
+</style>

+ 100 - 0
src/views/pc/order/components/interestsOrder.vue

@@ -0,0 +1,100 @@
+<template>
+  <div>
+    <div v-if="total">
+      <div class="order-item" v-for="(item,i) in data" :key="item.orderSn">
+        <InterestsItem :item="item" :i="i" @isOrderInvoice="edit"  />
+      </div>
+    </div>
+    <div class="scene-nothing" v-else>
+      <img :src="`${$cdn}images/nothing.png`" alt>
+      <div>{{$t('manage.myOrders.norecord')}} 
+        <a class="gotoBuy" @click="$router.push({name: 'member'})">{{$t('manage.gotoBuy')}}</a>
+      </div>
+    </div>
+    <div class="paging" v-if="total">
+      <Paging @clickHandle="pageChange" @maxPage="data=>maxPage=data" :current="currentPage" :total="total" :equable="pageSize"/>
+    </div>
+  </div>
+</template>
+
+<script>
+import InterestsItem from './interestsItem'
+import { mapState } from 'vuex'
+import Paging from '@/components/Paging'
+import MemberApi from '@/apis/member'
+
+export default {
+  provide () {
+    return {
+      getList: this.getList
+    }
+  },
+  data () {
+    return {
+      pageSize: 5,
+      currentPage: 1,
+      data: [],
+      total: 0,
+      maxPage: 0,
+      showInvoice: false,
+      currentI: '',
+      currentItem: ''
+    }
+  },
+  
+  watch: {
+    currentPage () {
+      this.getMemberOrderList()
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token,
+      language: state => state.language.current
+    })
+  },
+  components: {
+    InterestsItem,
+    Paging
+  },
+  mounted () {
+    this.getMemberOrderList()
+  },
+  methods: {
+    edit (bool) {
+      console.log(bool)
+      this.$bus.$emit('isOrderInvoice', bool)
+    },
+    pageChange (data) {
+      this.currentPage = data
+    },
+    getMemberOrderList () {
+      let data = {
+        snCode: '',
+        pageNum: this.currentPage,
+        pageSize: this.pageSize
+      }
+      MemberApi.getVirtualOrderList(data).then(res => {
+        this.data = res.data.data.list
+        this.total = res.data.data.total
+      })
+    },
+    
+    
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.scene-nothing {
+  text-align: center;
+  padding: 42px 0 210px 0;
+  img {
+    padding-bottom: 22px;
+  }
+  div {
+    font-size: 16px;
+    color: #969696;
+  }
+}
+</style>

+ 429 - 0
src/views/pc/order/components/orderItem.vue

@@ -0,0 +1,429 @@
+<template>
+  <div class="order-item" :key="i">
+        <!-- <div class="o-top"></div> -->
+        <div class="o-title">
+          <span>
+            <span class="orderSn table-header">{{$t('manage.myOrders.numbers')}}{{item.orderSn}}</span>
+            <span class="orderTime">{{ item.orderTime }}</span>
+          </span>
+          <span class="table-header">{{$t('manage.myOrders.quantity')}}</span>
+          <span class="table-header">{{$t('manage.myOrders.subtotal')}}</span>
+          <span class="table-header">{{$t('manage.myOrders.total1')}}</span>
+        </div>
+        <div class="o-detail" v-for="(sub,index) in item.orderItems" :key="index">
+          <div class="od-name">
+            <img class="thumbnail" :src="sub.pic" alt>
+            <div>
+              <p>{{$t(`manage.cameraName.${sub.goodsId}`)}}</p>
+              <p v-for="(sb,i) in $t(`manage.orderDetail.${sub.goodsId}`)" :key="i" v-html="sb"></p>
+            </div>
+          </div>
+          <div class="count">{{sub.goodsCount}}</div>
+          <div class="sum">{{sub.goodsPrice*sub.goodsCount}}</div>
+          <div class="sum"></div>
+        </div>
+        <div class="sum-price">
+          <div>¥{{item.goodsAmount}}</div>
+        </div>
+        <div class="inovice-con" :class="{'ic-active':item.showInvoice}">
+          <div class="o-invoiceTitle">
+            <span>{{$t('manage.myOrders.invoice')}}</span>
+            <span v-if="getStatus(item) !== 'shipped'" @click="edit"><i class="iconfont icon-edit"></i>{{$t('manage.myOrders.edit')}}</span>
+            <!-- <span v-else><i class="iconfont icon-choice"></i>发票已寄出</span> -->
+          </div>
+          <div class="o-invoice">
+            <editInvoice :data="getItemInvoice(item)" :orderId='item.id' :invoiceId="item.invoice&&(item.invoice.id)"/>
+          </div>
+        </div>
+        <div class="bottom-area">
+          <div class="bottom-left">
+            <template v-if="getStatus(item) === 'unpaid'">
+              <span></span>
+            </template>
+             <template v-else-if="getStatus(item) === 'shipped'">
+              <span class="expreeNum">{{$t('manage.myOrders.wlNum')}}{{item.orderItems[0].expressNum}}</span>
+            </template>
+            <template v-else-if="getStatus(item) === 'unshipped'">
+              <span class="expreeNum">{{$t('manage.myOrders.unshipped')}}</span>
+            </template>
+            <template v-else-if="getStatus(item) === 'finish'">
+              <span class="expreeNum">{{$t('manage.myOrders.finish')}}</span>
+            </template>
+            <template v-else-if="getStatus(item) === 'partShipped'">
+              <span class="expreeNum">{{$t('manage.myOrders.partShipped')}}</span>
+            </template>
+            <template v-else-if="getStatus(item) === 'received'">
+              <span class="expreeNum">{{$t('manage.myOrders.received')}}:{{item.orderItems[0].expressNum}}</span>
+            </template>
+            <template v-else-if="getStatus(item) === 'expire'">
+              <span class="expreeNum">{{$t('manage.myOrders.expire')}}</span>
+            </template>
+            <template v-else>
+              <span class="expreeNum">{{$t('manage.myOrders.hasCancal')}}</span>
+            </template>
+          </div>
+          <div class="to-pay">
+            <template v-if="getStatus(item) !== 'expire'">
+              <span class="cancel btns" @click="changeIvoiceStatus(i,item)">{{item.invoice && item.invoice.type ? $t('manage.myOrders.invoiceInfo') : $t('manage.myOrders.invoice')}}</span>
+              <template v-if="getStatus(item) === 'unpaid'">
+                <span class="cancel btns" @click="cancal(item)">{{$t('manage.myOrders.cancal')}}</span>
+                <span class="pay btns" @click="toPay(item)">{{$t('manage.myOrders.pay')}}</span>
+              </template>
+            </template>
+          </div>
+        </div>
+      </div>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+import editInvoice from '@/components/editInvoice'
+
+export default {
+  props: {
+    item: Object,
+    i: Number
+  },
+  inject: ['getList'],
+  provide () {
+    return {
+      hideInvoice: this.hideInvoice,
+      saveInvoiceData: this.saveInvoice
+    }
+  },
+  data () {
+    return {
+      showInvoice: true
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token,
+      language: state => state.language.current,
+      myorder: state => {
+        let type = Object.prototype.toString.call(state.user.myorder)
+        if (type === '[object Object]') {
+          return state.user.myorder
+        }
+        let condition = state.user.myorder && state.user.myorder !== 'null' && type !== '[object Array]'
+        return condition ? JSON.parse(state.user.myorder) : {}
+      }
+    })
+  },
+  components: {
+    editInvoice
+  },
+  mounted () {
+    this.$set(this.item, 'showInvoice', false)
+  },
+  methods: {
+    edit () {
+      this.showInvoice = false
+    },
+    hideInvoice () {
+      this.showInvoice = true
+    },
+    changeIvoiceStatus (i, item) {
+      // item.showInvoice = !item.showInvoice
+      // this.$set(this.item, 'showInvoice', item.showInvoice)
+      this.$bus.$emit('order/showInvoice', {
+        order: item,
+        orderId: item.id,
+        data: this.getItemInvoice(item),
+        invoiceId: item.invoice&&(item.invoice.id)
+      })
+    },
+    saveInvoice (data) {
+      this.$set(this.item, 'invoice', data)
+    },
+    getItemInvoice (item) {
+      let invoice = item.invoice
+      console.log(item)
+      if (!invoice) {
+        return ''
+      }
+      invoice['typeName'] = this.$t(`manage.invoiceTypeName.${invoice.type}`)
+      return invoice
+    },
+    getStatus (item) {
+      let temp = ''
+      let sPay = function () {
+        switch (item.shippingStatus) {
+          case 'unshipped':
+            temp = 'unshipped'
+            break
+          case 'partShipped':
+            temp = 'partShipped'
+            break
+          case 'shipped':
+            temp = 'shipped'
+            break
+          case 'received':
+            temp = 'received'
+            break
+          default:
+            break
+        }
+      }
+      let pPay = function () {
+        switch (item.paymentStatus) {
+          case 'unpaid':
+            temp = 'unpaid'
+            break
+          case 'paid':
+            sPay()
+            break
+          default:
+            break
+        }
+      }
+
+      switch (item.orderStatus) {
+        case 'unprocessed':
+          pPay()
+          break
+        case 'completed':
+          temp = 'finish'
+          break
+        case 'processed':
+          sPay()
+          break
+        case 'expire':
+          temp = 'expire'
+          break
+        default:
+          break
+      }
+      return temp
+    },
+    toPay (item) {
+      this.$router.push({
+        name: 'pay',
+        query: {
+          payType: 0,
+          orderId: item.id,
+          orderType: 0,
+          orderSn: item.orderSn
+        }
+      })
+    },
+    async cancal (item) {
+      this.$toast.showConfirm('warn', this.$t('toast.15'), async () => {
+        let params = {
+          orderId: item.id
+        }
+        let res = await this.$http({
+          method: 'post',
+          data: params,
+          headers: {
+            token: this.token
+          },
+          url: '/user/order/cancel'
+        })
+        let data = res.data
+        if (data.code === 0) {
+          return this.$toast.show('success', this.$t('toast.37'), () => {
+            this.currentPage = this.currentPage >= this.maxPage ? this.maxPage : this.currentPage
+            this.getList()
+          })
+        }
+        return this.$toast.show('error', this.$t('toast.38'))
+      })
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.order-item {
+    margin-bottom: 40px;
+    border: 1px solid #EBEBEB;
+    .inovice-con{
+      max-height: 0;
+      overflow: hidden;
+    }
+    .ic-active{
+      max-height: 500px;
+      transition: 0.3s ease max-height;
+    }
+    .o-top {
+      color: #68b8f1;
+      line-height: 60px;
+      height: 60px;
+      font-size: 16px;
+      padding: 0 20px;
+      user-select: none;
+      border-bottom: 1px solid #EBEBEB;
+    }
+    .o-title,.o-invoiceTitle {
+      user-select: none;
+      display: flex;
+      height: 32px;
+      padding: 0 20px;
+      align-items: center;
+      line-height: 32px;
+      // border-bottom: 1px solid #EBEBEB;
+      background: #F7F7F7;
+      span {
+        font-size: 14px;
+        flex: 1;
+        text-align: center;
+        &:first-child {
+          flex: 5;
+          text-align: left;
+        }
+      }
+    }
+    .orderSn {
+      color: #323233;
+      margin-right: 15px;
+    }
+    .o-invoiceTitle{
+      align-items: center;
+      .iconfont{
+        vertical-align: middle;
+        font-size: 20px;
+        margin-right: 5px;
+      }
+      .icon-edit{
+        color: #15BEC8;
+      }
+      .icon-choice{
+        color: #02e430;
+      }
+      span {
+        display: inline-block;
+        vertical-align: middle;
+        &:last-child{
+          transform: translateX(11px);
+          cursor: pointer;
+        }
+        &:first-child {
+          flex: 1;
+          transform: translateX(0);
+          text-align: left;
+        }
+      }
+    }
+    .o-invoice{
+      display: flex;
+      align-items: center;
+      padding: 10px 20px 10px 85px;
+      color: #4a4a4a;
+      font-size: 14px;
+      border-bottom: 1px solid #EBEBEB;
+    }
+
+    .o-detail {
+      display: flex;
+      align-items: center;
+      height: 86px;
+      line-height: 86px;
+      padding: 0 20px;
+      color: #4a4a4a;
+      font-size: 14px;
+      border-bottom: 1px solid #EBEBEB;
+      .od-name {
+        display: flex;
+        align-items: center;
+        flex: 5;
+        .thumbnail {
+          width: 55px;
+          margin-right: 10px;
+        }
+        p {
+          line-height: 1.5;
+          font-size: 14px;
+          color: #969696;
+          &:first-of-type{
+           font-weight: bold;
+           color: #2d2d2d;
+          }
+        }
+      }
+      .count {
+        flex: 1;
+        text-align: center;
+      }
+      .sum {
+        flex: 1;
+        text-align: center;
+      }
+    }
+    position: relative;
+    .sum-price {
+      position: absolute;
+      color: #4a4a4a;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      right: 1px;
+      top: 33px;
+      bottom: 51px;
+      background-color: #fff;
+      width: calc(calc(100% - 40px) / 8 + 20px);
+      border-left: 1px solid #EBEBEB;
+      font-weight: 400;
+      color: #202020;
+      font-size: 20px;
+      
+    }
+
+    .bottom-area{
+      position: relative;
+      .bottom-left{
+        position: absolute;
+        top: 50%;
+        left: 20px;
+        color: #a0a0a0;
+        transform: translateY(-50%);
+        font-size: 14px;
+        color: #323233;
+      }
+      .to-pay {
+        text-align: right;
+        height: 50px;
+        line-height: 50px;
+        padding: 0 25px;
+        .cancel {
+          font-size: 14px;
+          // border: 1px solid #ccc;
+          display: inline-block;
+          text-align: center;
+          cursor: pointer;
+          background: #fff;
+          color: #202020;
+          border: 1px solid #323233;
+          width: 104px;
+          height: 32px;
+          line-height: 32px;
+          border-radius: 4px;
+        }
+        .pay {
+          background: #15BEC8;
+          font-size: 14px;
+          color: #fff;
+          display: inline-block;
+          width: 104px;
+          height: 32px;
+          line-height: 32px;
+          text-align: center;
+          cursor: pointer;
+          border-radius: 4px;
+        }
+        .expreeNum {
+          margin-right: 60px;
+          color: #323233;
+          
+        }
+      }
+    }
+
+  }
+
+  .table-header {
+    font-weight: 600;
+    color: #202020;
+
+  }
+</style>

+ 400 - 0
src/views/pc/order/components/rechargeItem.vue

@@ -0,0 +1,400 @@
+<template>
+  <div class="order-item" :key="i">
+        <!-- <div class="o-top"></div> -->
+        <div class="o-title">
+          <span>
+            <span class="orderSn table-header">{{$t('manage.myOrders.numbers')}}{{item.orderSn}}</span>
+            <span class="orderTime">{{ item.tradeTime }}</span>
+          </span>
+          <span class="table-header">{{$t('manage.myOrders.total1')}}</span>
+        </div>
+        <div class="o-detail">
+          <div class="od-name">
+            <div>
+              <p>{{ item.status }}{{$t('manage.myOrders.recname')}}</p>
+              <p>{{$t('manage.Spending.rechargeLabel.type')}}:{{ item.status }}</p>
+              <p>{{$t('manage.Spending.rechargeLabel.deviceName')}}:{{ item.orderSn }}</p>
+            </div>
+          </div>
+          <div class="sum total-momey">{{item.amount || 0}}</div>
+        </div>
+
+        <div class="inovice-con" :class="{'ic-active':item.showInvoice}">
+          <div class="o-invoiceTitle">
+            <span>{{$t('manage.myOrders.invoice')}}</span>
+            <span v-if="getStatus(item) !== 'shipped'" @click="edit"><i class="iconfont icon-edit"></i>{{$t('manage.myOrders.edit')}}</span>
+            <!-- <span v-else><i class="iconfont icon-choice"></i>发票已寄出</span> -->
+          </div>
+          <div class="o-invoice">
+            <editInvoice :data="getItemInvoice(item)" :orderId='item.id' :invoiceId="item.invoice&&(item.invoice.id)"/>
+          </div>
+        </div>
+        <div class="bottom-area">
+          <div class="to-pay">
+            <template v-if="getStatus(item) !== 'expire'">
+              <span class="cancel btns" @click="changeIvoiceStatus(i,item)">
+                {{item.invoice && item.invoice.type ? $t('manage.myOrders.invoiceInfo') : $t('manage.myOrders.invoice')}}
+              </span>
+            </template>
+          </div>
+        </div>
+      </div>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+import editInvoice from '@/components/editInvoice'
+import MallConfig from '@/config/mall'
+
+export default {
+  props: {
+    item: Object,
+    i: Number
+  },
+  provide () {
+    return {
+      hideInvoice: this.hideInvoice,
+      saveInvoiceData: this.saveInvoice
+    }
+  },
+  data () {
+    return {
+      PAYSIDMAP: MallConfig.PAYSIDMAP,
+      showInvoice: true
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token,
+      language: state => state.language.current,
+      myorder: state => {
+        let type = Object.prototype.toString.call(state.user.myorder)
+        if (type === '[object Object]') {
+          return state.user.myorder
+        }
+        let condition = state.user.myorder && state.user.myorder !== 'null' && type !== '[object Array]'
+        return condition ? JSON.parse(state.user.myorder) : {}
+      }
+    })
+  },
+  components: {
+    editInvoice
+  },
+  mounted () {
+    this.$set(this.item, 'showInvoice', false)
+  },
+  methods: {
+    edit () {
+      this.showInvoice = false
+    },
+    hideInvoice () {
+      this.showInvoice = true
+    },
+    changeIvoiceStatus (i, item) {
+      // item.showInvoice = !item.showInvoice
+      // this.$set(this.item, 'showInvoice', item.showInvoice)
+      // this.$bus.emit('order/showInvoice', item)
+
+      
+      this.$bus.$emit('order/showInvoice', {
+        order: item,
+        orderId: item.id,
+        data: this.getItemInvoice(item),
+        invoiceId: item.invoice&&(item.invoice.id)
+      })
+    },
+    saveInvoice (data) {
+      this.$set(this.item, 'invoice', data)
+    },
+    getItemInvoice (item) {
+      let invoice = item.invoice
+      if (!invoice) {
+        return ''
+      }
+      invoice['typeName'] = this.$t(`manage.invoiceTypeName.${invoice.type}`)
+      return invoice
+    },
+    getStatus (item) {
+      let temp = ''
+      let sPay = function () {
+        switch (item.shippingStatus) {
+          case 'unshipped':
+            temp = 'unshipped'
+            break
+          case 'partShipped':
+            temp = 'partShipped'
+            break
+          case 'shipped':
+            temp = 'shipped'
+            break
+          case 'received':
+            temp = 'received'
+            break
+          default:
+            break
+        }
+      }
+      let pPay = function () {
+        switch (item.paymentStatus) {
+          case 'unpaid':
+            temp = 'unpaid'
+            break
+          case 'paid':
+            sPay()
+            break
+          default:
+            break
+        }
+      }
+
+      switch (item.orderStatus) {
+        case 'unprocessed':
+          pPay()
+          break
+        case 'completed':
+          temp = 'finish'
+          break
+        case 'processed':
+          sPay()
+          break
+        case 'expire':
+          temp = 'expire'
+          break
+        default:
+          break
+      }
+      return temp
+    },
+    toPay (item) {
+      this.$router.push({
+        name: 'pay',
+        query: {
+          payType: 0,
+          orderId: item.id,
+          orderType: 0,
+          orderSn: item.orderSn
+        }
+      })
+    },
+    async cancal (item) {
+      this.$toast.showConfirm('warn', this.$t('toast.15'), async () => {
+        let params = {
+          orderId: item.id
+        }
+        let res = await this.$http({
+          method: 'post',
+          data: params,
+          headers: {
+            token: this.token
+          },
+          url: '/user/order/cancel'
+        })
+        let data = res.data
+        if (data.code === 0) {
+          return this.$toast.show('success', this.$t('toast.37'), () => {
+            this.currentPage = this.currentPage >= this.maxPage ? this.maxPage : this.currentPage
+            this.getList()
+          })
+        }
+        return this.$toast.show('error', this.$t('toast.38'))
+      })
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.order-item {
+    margin-bottom: 40px;
+    border: 1px solid #EBEBEB;
+    .inovice-con{
+      max-height: 0;
+      overflow: hidden;
+    }
+    .ic-active{
+      max-height: 500px;
+      transition: 0.3s ease max-height;
+    }
+    .o-top {
+      color: #68b8f1;
+      line-height: 60px;
+      height: 60px;
+      font-size: 16px;
+      padding: 0 20px;
+      user-select: none;
+      border-bottom: 1px solid #EBEBEB;
+    }
+    .o-title,.o-invoiceTitle {
+      user-select: none;
+      display: flex;
+      height: 32px;
+      padding: 0 20px;
+      align-items: center;
+      line-height: 32px;
+      // border-bottom: 1px solid #EBEBEB;
+      background: #F7F7F7;
+      span {
+        font-size: 14px;
+        flex: 1;
+        text-align: center;
+        &:first-child {
+          flex: 5;
+          text-align: left;
+        }
+      }
+    }
+    .orderSn {
+      color: #323233;
+      margin-right: 15px;
+    }
+    .o-invoiceTitle{
+      align-items: center;
+      .iconfont{
+        vertical-align: middle;
+        font-size: 20px;
+        margin-right: 5px;
+      }
+      .icon-edit{
+        color: #15BEC8;
+      }
+      .icon-choice{
+        color: #02e430;
+      }
+      span {
+        display: inline-block;
+        vertical-align: middle;
+        &:last-child{
+          transform: translateX(11px);
+          cursor: pointer;
+        }
+        &:first-child {
+          flex: 1;
+          transform: translateX(0);
+          text-align: left;
+        }
+      }
+    }
+    .o-invoice{
+      display: flex;
+      align-items: center;
+      padding: 10px 20px 10px 85px;
+      color: #4a4a4a;
+      font-size: 14px;
+      border-bottom: 1px solid #EBEBEB;
+    }
+
+    .o-detail {
+      display: flex;
+      align-items: center;
+      height: 86px;
+      line-height: 86px;
+      padding: 0 20px;
+      color: #4a4a4a;
+      font-size: 14px;
+      border-bottom: 1px solid #EBEBEB;
+      .od-name {
+        display: flex;
+        align-items: center;
+        flex: 5;
+        .thumbnail {
+          width: 55px;
+          margin-right: 10px;
+        }
+        p {
+          line-height: 1.5;
+          font-size: 14px;
+          color: #969696;
+          &:first-of-type{
+           font-weight: bold;
+           color: #2d2d2d;
+          }
+        }
+      }
+      .count {
+        flex: 1;
+        text-align: center;
+      }
+      .sum {
+        flex: 1;
+        text-align: center;
+      }
+    }
+    .sum-price {
+      display: flex;
+      height: 40px;
+      line-height: 40px;
+      padding: 0 40px;
+      border-bottom: 1px solid #EBEBEB;
+      div {
+        flex: 2;
+        color: #4a4a4a;
+        font-size: 14px;
+        &:last-child {
+          flex: 1;
+          text-align: right;
+        }
+      }
+    }
+
+    .bottom-area{
+      position: relative;
+      .bottom-left{
+        position: absolute;
+        top: 50%;
+        left: 20px;
+        color: #a0a0a0;
+        transform: translateY(-50%);
+        font-size: 14px;
+        color: #323233;
+      }
+      .to-pay {
+        text-align: right;
+        height: 50px;
+        line-height: 50px;
+        padding: 0 25px;
+        .cancel {
+          font-size: 14px;
+          // border: 1px solid #ccc;
+          display: inline-block;
+          text-align: center;
+          cursor: pointer;
+          background: #fff;
+          color: #202020;
+          border: 1px solid #323233;
+          width: 104px;
+          height: 32px;
+          line-height: 32px;
+          border-radius: 4px;
+        }
+        .pay {
+          background: #15BEC8;
+          font-size: 14px;
+          color: #fff;
+          display: inline-block;
+          width: 104px;
+          height: 32px;
+          line-height: 32px;
+          text-align: center;
+          cursor: pointer;
+        }
+        .expreeNum {
+          margin-right: 60px;
+          color: #323233;
+          
+        }
+      }
+    }
+
+  }
+
+  .table-header {
+    font-weight: 600;
+    color: #202020;
+
+  }
+
+  .total-momey {
+    font-weight: 400;
+    color: #202020;
+    font-size: 20px;
+  }
+</style>

+ 395 - 0
src/views/pc/order/components/rechargeOrder.vue

@@ -0,0 +1,395 @@
+<template>
+  <div>
+    <div v-if="total">
+      <div class="order-item" v-for="(item,i) in data" :key="item.orderSn">
+        <InterestsItem :item="item" :i="i"  />
+      </div>
+    </div>
+    <div class="scene-nothing" v-else>
+      <img :src="`${$cdn}images/nothing.png`" alt>
+      <div>{{$t('manage.myOrders.norecord')}} 
+        <!-- <a class="gotoBuy" >{{$t('manage.gotoBuy')}}</a> -->
+      </div>
+    </div>
+    <div class="paging" v-if="total">
+      <Paging @clickHandle="pageChange" @maxPage="data=>maxPage=data" :current="currentPage" :total="total" :equable="pageSize"/>
+    </div>
+  </div>
+</template>
+
+<script>
+
+import InterestsItem from './rechargeItem'
+import { mapState } from 'vuex'
+import tableList from '@/components/table'
+import {capacity, recharge, invoice} from './iconsumption'
+import Paging from '@/components/Paging'
+import vcenter from '@/components/vcenter'
+import MemberApi from '@/apis/member'
+import MallConfig from '@/config/mall'
+import { i18n } from '@/lang'
+
+let AMOUNTSTR = {
+  0: '¥',
+  1: '¥',
+  2: '$'
+}
+
+let methodStr = {
+  0: 'getMemberOrderList',
+  1: 'getChargeList',
+  2: 'getInvoiceList'
+}
+let rechargeType = {
+  0: i18n.t('manage.Spending.rechargeValue.0'),
+  '-1': i18n.t('manage.Spending.rechargeValue.-1'),
+  1: i18n.t('manage.Spending.rechargeValue.1'),
+  2: i18n.t('manage.Spending.rechargeValue.2')
+}
+
+let invoceStatusType = {
+  0: '未开票',
+  1: '已开票'
+}
+
+let invoiceType = {
+  1: '不需要发票',
+  2: '增值税普通发票',
+  3: '增值税专用发票'
+}
+
+export default {
+  components: {
+    tableList,
+    Paging,
+    vcenter,
+    InterestsItem
+  },
+  data () {
+    let cameraList = [
+      {
+        name: '全部',
+        id: ''
+      },
+      {
+        name: '二目充值',
+        id: 0
+      },
+      {
+        name: '会员权益',
+        id: 4
+      }
+    ]
+    return {
+      PAYSIDMAP: MallConfig.PAYSIDMAP,
+      tabHeader: capacity,
+      data: [],
+      cameraList,
+      active: 1,
+      recharge,
+      total: 30,
+      pageSize: 5,
+      currentPage: 1,
+      tabActive: false,
+      deviceActive: false,
+      max: 0,
+      activeDevice: '',
+      activeType: '全部',
+      activeId: '',
+      activeTypeId: '',
+      tabList: [
+        {
+          name: this.$t('manage.Spending.tabListMember')
+        },
+        {
+          name: this.$t('manage.Spending.tabListRecharge')
+        },
+        {
+          name: this.$t('manage.Spending.tabListInvoice')
+        },
+      ]
+    }
+  },
+  computed: {
+    ...mapState({
+      token: state => state.user.token,
+      language: state => state.language.current,
+      deviceLogin: state => state.user.deviceLogin,
+      // 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 : [])
+      },
+      searchKey () {
+        return this.$parent.searchKey
+      }
+    })
+  },
+  watch: {
+    currentPage (newVal) {
+      this.getList()
+    },
+    language (newVal) {
+      this.active = 0
+      this.data.forEach(item => {
+        let condition = item['validDate'] === '终身有效' ? (newVal === 'en' ? 'N/A' : '终身有效') : item['validDate']
+        item['validDateStr'] = condition
+        item['unitSize1'] = item['unitSize'] + item['unit'] + '/' + this.$t(`manage.shixian.${item['month']}`)
+        item['channel'] = this.$t(`manage.channelType.${item['status']}`)
+        item['amount1'] = AMOUNTSTR[item['payType']] + item['amount']
+        item['payTypeStr'] = this.$t(`manage.PAYSSTR.${item['payType']}`)
+      })
+    },
+    activeId (newVal) {
+      if (this.active === 2) {
+        this.getList()
+      }
+      this.getInvoiceMax()
+    },
+    activeTypeId (newVal) {
+      if (this.active === 2) {
+        this.getList()
+      }
+    },
+    active (newVal) {
+      switch (newVal) {
+        case 1:
+          this.tabHeader = recharge
+          break
+        case 2:
+          !this.deviceLogin && this.getAllDevice()
+          this.tabHeader = invoice
+          break
+        default:
+          this.tabHeader = capacity
+          break
+      }
+      if (newVal !== 1) {
+        this.$emit('changeSearchShow', false)
+      } else {
+        this.$emit('changeSearchShow', true)
+      }
+      this.currentPage === 1 ? this.getList() : this.currentPage = 1
+    }
+  },
+  methods: {
+    pageChange (data) {
+      this.currentPage = data
+    },
+    selectInId (item) {
+      this.activeDevice = item.childName
+      this.activeId = item.id
+    },
+    selectCamTy (item) {
+      this.activeType = item.name
+      this.activeTypeId = item.id
+    },
+    showDetail (item) {
+      this.$toast.showInvoiceDetail(item)
+    },
+    getList (searchKey = '') {
+      window.scrollTo(0, 0)
+      let str = methodStr[this.active]
+      this[str](searchKey)
+    },
+    openInvice () {
+      let params = {
+        max: this.max,
+        cameraId: this.activeId
+      };
+      (this.max && !this.deviceLogin) && this.$toast.showInvoice(params)
+    },
+    async getAllDevice (searchKey = '') {
+      let params = {
+        cameraType: ''
+      }
+      await this.$store.dispatch('getInvoiceDevice', params)
+      this.activeDevice = this.invoicedevice[0].childName
+      this.activeId = this.invoicedevice[0].id
+    },
+
+    // 扩容记录
+    async getConsumpList (searchKey = '') {
+      if (this.deviceLogin) {
+        searchKey = this.deviceLogin
+      }
+      let data = {
+        params: {
+          childName: searchKey.trim(),
+          pageNum: searchKey ? 1 : this.currentPage,
+          pageSize: this.pageSize
+        },
+        url: this.deviceLogin ? '/device/virtualOrder/expansionList' : '/user/virtualOrder/expansionList'
+      }
+      await this.$store.dispatch('getUserExpansion', data)
+      if (!this.myexpansion.total && searchKey && !this.deviceLogin) {
+        return this.$toast.show('warn', this.$t('toast.25'), () => {
+          this.getList()
+        })
+      }
+      console.log(this.myexpansion, 'this.myexpansion')
+      this.pageSize = this.myexpansion.pageSize
+      this.total = this.myexpansion.total || 0
+      this.data = this.myexpansion.list
+      this.data.forEach(item => {
+        let condition = item['validDate'] === '终身有效' ? (this.language === 'en' ? 'N/A' : '终身有效') : item['validDate']
+        item['validDateStr'] = condition
+        item['statusStr'] = this.$t(`manage.myOrders.${item['status']}`)
+        item['unitSize1'] = item['unitSize'] + item['unit'] + '/' + this.$t(`manage.shixian.${item['month']}`)
+        item['channel'] = this.$t(`manage.channelType.${item['status']}`)
+        item['amount1'] = AMOUNTSTR[item['payType']] + item['amount']
+        item['payTypeStr'] = this.$t(`manage.PAYSSTR.${item['payType']}`)
+      })
+    },
+    getMemberOrderList () {
+      let data = {
+        snCode: this.searchKey,
+        pageNum: this.currentPage,
+        pageSize: this.pageSize
+      }
+      MemberApi.getVirtualOrderList(data).then(res => {
+        this.data = res.data.data.list
+        console.log(this.data)
+        this.total = res.data.data.total
+      })
+    },
+    async getInvoiceMax () {
+      let res = await this.$http({
+        method: 'post',
+        data: {
+          cameraId: this.activeId
+        },
+        headers: {
+          token: this.token
+        },
+        url: '/user/invoice/max'
+      })
+
+      let data = res.data
+      if (data.code !== 0) return
+      this.max = data.data.maxInvoice
+    },
+
+    // 充值记录
+    async getChargeList (searchKey = '') {
+      if (this.deviceLogin) {
+        searchKey = this.deviceLogin
+      }
+      let data = {
+        params: {
+          childName: searchKey,
+          pageNum: searchKey ? 1 : this.currentPage,
+          pageSize: this.pageSize
+        },
+        url: this.deviceLogin ? '/device/virtualOrder/chargeList' : '/user/virtualOrder/chargeList'
+      }
+      await this.$store.dispatch('getChargeList', data)
+      if (!this.mycharge.total && searchKey && !this.deviceLogin) {
+        return this.$toast.show('warn', this.$t('toast.25'), () => {
+          this.getList()
+        })
+      }
+      this.pageSize = this.mycharge.pageSize
+      this.total = this.mycharge.total || 0
+      this.data = this.mycharge.list
+      this.data.forEach(item => {
+        item['status'] = rechargeType[item['status']]
+      })
+
+      console.log(this.data)
+    },
+
+    // 发票记录
+    async getInvoiceList () {
+      let data = {
+        params: {
+          cameraId: this.activeId,
+          pageNum: this.currentPage,
+          pageSize: this.pageSize,
+          type: this.activeTypeId
+        },
+        url: this.deviceLogin ? '/device/invoice/list' : '/user/invoice/list'
+      }
+
+      await this.$store.dispatch('getInvoiceList', data)
+      this.pageSize = this.myinvoicelist.pageSize
+      this.total = this.myinvoicelist.total || 0
+      this.data = this.myinvoicelist.list
+      this.data.forEach(item => {
+        item['detail'] = '详细'
+        item['money'] = '¥' + item['money']
+        item['finish'] = invoceStatusType[item['finish']]
+        item['type'] = invoiceType[item['type']]
+      })
+    },
+    handleSearch (keyword) {
+      this.getList(keyword)
+    }
+  },
+  mounted () {
+    this.getList()
+
+    this.$bus.$off('refreshInvoice')
+    this.$bus.$on('refreshInvoice', () => {
+      if (this.active === 2) {
+        this.getList()
+      }
+      this.getInvoiceMax()
+    })
+
+    document.addEventListener('click', (e) => {
+      if (this.$refs.invoiceMenu) {
+        if (!this.$refs.invoiceMenu.contains(e.target)) {
+          this.tabActive = false
+        }
+      }
+      if (this.$refs.deviceMenu) {
+        if (!this.$refs.deviceMenu.contains(e.target)) {
+          this.deviceActive = false
+        }
+      }
+    })
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.scene-nothing {
+  text-align: center;
+  padding: 42px 0 210px 0;
+  img {
+    padding-bottom: 22px;
+  }
+  div {
+    font-size: 16px;
+    color: #969696;
+  }
+}
+</style>

+ 230 - 0
src/views/pc/order/components/showInvoice.vue

@@ -0,0 +1,230 @@
+<template>
+  <div class="invoice-edit-layer">
+    <div class="invoice-body">
+      <h2>
+        {{invoice.data ? $t('manage.myOrders.invoiceInfo') : $t('manage.myOrders.invoice')}}
+        <div class="memeber-intro" v-if="!invoice.data">
+          <h-icon type="register_help"></h-icon>
+          <div class="intro-w">
+            <p>{{$t('manage.myOrders.invoiceTip0')}}</p>
+            <p>{{$t('manage.myOrders.invoiceTip1')}}</p>
+            <p>{{$t('manage.myOrders.invoiceTip2')}}</p>
+          </div>
+        </div>
+      </h2>
+      <i class="iconfont icon-vip_false" @click="hideInvoice"></i>
+      <div class="invoice-content">
+        <editInvoice :data="invoice.data" :consumeType="consumeType" :orderId="invoice.orderId" :invoiceId="invoice.invoiceId" v-if="!invoice.data" />
+        <div class="invoice-info" v-else>
+          <p v-for="(item,i) in invoiceData" :key="i">
+            <span>{{item['name']}}</span>
+            {{invoice.data[item['key']]||'--'}}
+          </p>
+          <p class="maker">
+            {{invoice.data.type === 3 ? $t('manage.myOrders.typeStip0') : $t('manage.myOrders.typeStip1')}}
+          </p>
+        </div>
+      </div>
+      <div class="bottom-floot" v-if="invoice.data">
+        <div @click="hideInvoice" class="btn parmary">{{$t('manage.sceneAdmin.filterFormModule.enter')}}</div>
+      </div>
+
+    </div>
+    
+
+  </div>
+</template>
+
+<script>
+import editInvoice from './editInvoice'
+import { normal, zengzhi } from '@/components/editInvoice/invoice'
+
+
+export default {
+  components: {
+    editInvoice
+  },
+  provide () {
+    return {
+      hideInvoice: this.hideInvoice,
+      saveInvoiceData: this.saveInvoice
+    }
+  },
+  props: ['invoice', 'consumeType'],
+  methods: {
+    hideInvoice() {
+      this.$emit('cancle')
+    },
+    saveInvoice(data) {
+      this.$set(this.invoice.order, 'invoice', data)
+    }
+  },
+  computed: {
+    invoiceData () {
+      if (!this.invoice.data) {
+        return ''
+      }
+      return this.invoice.data.type === 2 ? normal : zengzhi
+    },
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.invoice-edit-layer {
+  position: fixed;
+  left: 0;
+  top: 0;
+  bottom: 0;
+  right: 0;
+  z-index: 999999;
+  background: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.invoice-body {
+  width: 540px;
+  background: #FFFFFF;
+  border-radius: 4px;
+  position: relative;
+
+  > h2 {
+    font-size: 16px;
+    font-family: PingFangSC-Semibold, PingFang SC;
+    font-weight: 600;
+    color: #202020;
+    line-height: 22px;
+    padding: 13px 0 11px 30px;
+    border-bottom: 1px solid #EBEBEB;;
+  }
+
+  .icon-vip_false {
+    position: absolute;
+    top: 16px;
+    right: 20px;
+    color: #909090;
+    font-size: 14px;
+    cursor: pointer;
+  }
+}
+
+.invoice-content {
+  padding: 14px 48px 20px 30px;
+}
+
+.invoice-info {
+  p {
+    position: relative;
+    padding-left: 130px;
+    margin: 10px 0;
+    font-size: 14px;
+    font-family: PingFangSC-Regular, PingFang SC;
+    font-weight: 400;
+    color: #202020;
+    line-height: 40px;
+    
+    &.maker {
+      color: #15BEC8;
+      padding-left: 0;
+    }
+
+    > span {
+      position: absolute;
+      left: 0;
+      top: 50%;
+      width: 100px;
+      text-align: left;
+      transform: translateY(-50%);
+      font-size: 14px;
+      font-family: PingFangSC-Regular, PingFang SC;
+      font-weight: 400;
+      color: #202020;
+      line-height: 20px;
+    }
+  }
+
+}
+
+
+$theme-color: #15BEC8;
+$border-color: #e7e7e7;
+.bottom-floot {
+  border-top: 1px solid #EBEBEB;
+  padding: 20px;
+  text-align: center;
+
+  .btn {
+    text-align: center;
+    cursor: pointer;
+    width: 126px;
+    height: 36px;
+    line-height: 36px;
+    margin: 10px 25px 0 0;
+    display: inline-block;
+    border: solid 1px #ccc;
+  }
+  .parmary {
+    background-color: $theme-color;
+    border: solid 1px $theme-color;
+  }
+
+  .btn {
+    border-radius: 4px;
+    margin: 0;
+    font-size: 14px;
+    font-family: PingFangSC-Semibold, PingFang SC;
+    font-weight: 600;
+    color: #202020;
+
+    &.parmary {
+      color: #fff;
+    }
+    &:first-child {
+      margin-right: 20px;
+    }
+  }
+}
+
+.memeber-intro {
+      position: relative;
+      display: inline-block;
+      margin-left: 9px;
+      cursor: pointer;
+      font-weight: normal;
+      &:hover {
+        .intro-w {
+          display: block;
+        }
+      }
+      .intro-w {
+        position: absolute;
+        z-index: 1;
+        bottom: -15px;
+        left: -50px;
+        transform: translateY(100%);
+        padding: 20px;
+        line-height: 16px;
+        background: #ebebeb;
+        border-radius: 4px;
+        font-size: 12px;
+        display: none;
+        &::before {
+          content: "";
+          display: block;
+          position: absolute;
+          border: 7px solid transparent;
+          border-bottom: 7px solid #ebebeb;
+          top: -14px;
+          left: 50px;
+        }
+        & > p {
+          white-space: nowrap;
+        }
+        & > p:not(:first-child) {
+          margin-top: 20px;
+        }
+      }
+    }
+</style>

+ 38 - 2
src/views/pc/order/index.vue

@@ -8,11 +8,47 @@ import { GetRequest, getWeChatCode, getRemark } from '@/utils/index'
 import { useI18n } from 'vue-i18n'
 const route = useRoute()
 const { locale: language, t } = useI18n()
+const tabs = [
+          {
+          name: t('manage.myOrders.tabs0'),
+          component: 'deviceOrder'
+        },
+        {
+          name: t('manage.myOrders.tabs1'),
+          component: 'interestsOrder'
+        },
+        {
+          name: t('manage.myOrders.tabs2'),
+          component: 'rechargeOrder'
+        },
+        {
+          name: t('manage.myOrders.tabs3'),
+          component: 'downOrder'
+        }
+]
 const userStore = useUserStore();
-const isEur = userStore.isEur
+// const isEur = userStore.isEur
+const tabComponent = ref('deviceOrder')
+const searchKey = ref('')
+const searchShow = ref(false)
+const invoice = ref(null)
 </script>
 <template>
-  <div class="pcPage">mobilePage
+  <div class="order-layout">
+    <!-- <showInvoice :invoice="invoice" :consumeType="consumeType" v-if="invoice" @cancle="invoice = null" /> -->
+    <div class="order-header">
+      <ul class="tab-list">
+        <li :class="{active: tabComponent === item.component}" v-for="item in tabs" :key="item.component" @click="handleTabChange(item)">{{ item.name }}</li>
+      </ul>
+      <div class="search-w" v-show="tabComponent === 'consumption' && searchShow">
+        <input type="text" v-model="searchKey" @keyup.enter="handleSearch" :placeholder="$t('manage.Spending.placeholdersearchID')">
+        <h-icon type="search" class="search-icon" @click="handleSearch" />
+      </div>
+    </div>
+    <!-- <keep-alive>
+      <component :is="tabComponent" ref="liveComponent" @changeSearchShow="changeSearchShow" />
+    </keep-alive> -->
+
   </div>
 </template>