Просмотр исходного кода

2306商品列表、2285报单列表、2286订单列表

kevin_zhangl 3 лет назад
Родитель
Сommit
87d557222e

+ 2 - 0
.env.production

@@ -3,5 +3,7 @@ ENV = 'production'
 
 # base api
 VUE_APP_BASE_API = '/prod-api'
+VUE_APP_CDN_API = '/'
+VUE_APP_PAY_STACK_PUBLIC_KEY = 'pk_live_fae524f9d073d877beeb661fd825a37a9bc91f0a'
 ACCESS_TOKEN_PREFIX = 'Bearer '
 

+ 5 - 2
.env.staging

@@ -4,5 +4,8 @@ NODE_ENV = production
 ENV = 'staging'
 
 # base api
-VUE_APP_BASE_API = '/stage-api'
-
+# VUE_APP_BASE_API = '/stage-api'
+VUE_APP_BASE_API = 'http://16.163.228.151:8026'
+VUE_APP_CDN_API = 'http://16.163.228.151:8029'
+VUE_APP_PAY_STACK_PUBLIC_KEY = 'pk_test_2eed10135c4a958c5073795b22854ded9d1a6c55'
+VUE_APP_ACCESS_TOKEN_PREFIX = 'Bearer '

+ 2 - 0
.gitignore

@@ -21,3 +21,5 @@ selenium-debug.log
 
 package-lock.json
 yarn.lock
+
+.env.development

+ 2 - 1
package.json

@@ -36,9 +36,10 @@
     "script-loader": "0.7.2",
     "sortablejs": "1.8.4",
     "tui-editor": "1.3.3",
-    "vue": "2.6.10",
+    "vue": "^2.6.10",
     "vue-count-to": "1.0.13",
     "vue-i18n": "7.3.2",
+    "vue-paystack": "^2.0.4",
     "vue-router": "3.0.2",
     "vue-splitpane": "1.0.4",
     "vuedraggable": "2.20.0",

+ 62 - 0
src/api/shop.js

@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+// 商品列表
+export function fetchProductList(query) {
+  return request({
+    url: '/v1/shop/index',
+    method: 'get',
+    params: query
+  })
+}
+
+// 商品详情
+export function fetchProduct(id) {
+  return request({
+    url: '/v1/shop/detail',
+    method: 'get',
+    params: { id }
+  })
+}
+
+// 报单列表
+export function fetchDecOrderList(query) {
+  return request({
+    url: '/v1/shop/dec-order-list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 订单列表
+export function fetchOrderList(query) {
+  return request({
+    url: '/v1/shop/order-list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 下载订单PDF
+export function downloadOrder(orderSn) {
+  return request({
+    url: `/v1/shop/order-export/${orderSn}`,
+    method: 'get',
+    params: { }
+  })
+}
+
+export function createArticle(data) {
+  return request({
+    url: '/v1/article/create',
+    method: 'post',
+    data
+  })
+}
+
+export function updateArticle(data) {
+  return request({
+    url: '/v1/article/update',
+    method: 'post',
+    data
+  })
+}

+ 18 - 0
src/api/user.js

@@ -62,3 +62,21 @@ export function getInfo(token) {
 //     method: 'post'
 //   })
 // }
+
+// 修改用户
+export function updateInfo(data) {
+  return request({
+    url: '/v1/user/edit',
+    method: 'post',
+    data
+  })
+}
+
+// 修改登录密码
+export function updateLoginPassword(data) {
+  return request({
+    url: '/v1/user/password',
+    method: 'post',
+    data
+  })
+}

+ 10 - 1
src/components/Pagination/index.vue

@@ -1,11 +1,12 @@
 <template>
-  <div :class="{'hidden':hidden}" class="pagination-container">
+  <div :class="{'hidden':hidden}" :style="{'float':float}" class="pagination-container">
     <el-pagination
       :background="background"
       :current-page.sync="currentPage"
       :page-size.sync="pageSize"
       :layout="layout"
       :page-sizes="pageSizes"
+      :hide-on-single-page="hideOnSinglePage"
       :total="total"
       v-bind="$attrs"
       @size-change="handleSizeChange"
@@ -53,6 +54,14 @@ export default {
     hidden: {
       type: Boolean,
       default: false
+    },
+    float: {
+      type: String,
+      default: 'right'
+    },
+    hideOnSinglePage: {
+      type: Boolean,
+      default: true
     }
   },
   computed: {

+ 55 - 1
src/lang/en.js

@@ -3,7 +3,7 @@ export default {
     dashboard: 'Dashboard',
     shop: 'Mall management',
     indexShop: 'Products list',
-    shopReconsume:'Reconsume List',
+    shopReconsume: 'Reconsume List',
     memberManagement: 'Member management',
     personalInfo: 'Personal Info',
     documentation: 'Documentation',
@@ -203,5 +203,59 @@ export default {
     activeDeadline: 'Active Deadline Date',
     more: 'more',
     articleNotification: 'System Notification'
+  },
+  currency: {
+    unit: 'Naira',
+    sign: '₦'
+  },
+
+  common: {
+    save: 'Save',
+    modify: 'Modify',
+    submit: 'Submit'
+  },
+
+  shop: {
+    productCode: 'Product Code',
+    productName: 'Product Name',
+    productPicture: 'Product Picture',
+    productPrice: 'Product Price',
+    productBV: 'Product BV',
+    qty: 'Qty',
+    taxRate: 'Tax Rate',
+    taxAmount: 'Tax',
+    totalPrice: 'Total Price',
+    orderCode: 'Order Code',
+    orderType: 'Order Type',
+    memberCode: 'Member Code',
+    memberName: 'Member Name',
+    recipientName: 'Recipient Name',
+    phoneNumber: 'Phone Number',
+    shippingAddress: 'Shipping Address',
+    payment: 'Payment',
+    createdTime: 'Created Time',
+    payTime: 'Pay Time',
+    payStatus: 'Pay Status',
+    action: 'Action',
+    download: 'Download',
+    sponsorCode: 'Sponsor Code',
+    inventory: 'Inventory',
+    checkOut: 'Check Out',
+    unPaid: '待支付',
+    paid: '已支付'
+  },
+
+  user: {
+    email: 'Email'
+  },
+
+  profile: {
+    personalInformation: 'Personal Information',
+    account: 'Account',
+    loginPassword: 'Login Password',
+    paymentPassword: 'Payment Password',
+    originalPassword: 'Original Password',
+    newPassword: 'New Password',
+    confirmPassword: 'Confirm Password'
   }
 }

+ 56 - 1
src/lang/zh.js

@@ -203,5 +203,60 @@ export default {
     activeDeadline: '活跃日期截止',
     more: '更多',
     articleNotification: '系统通知'
-  }
+  },
+
+  currency: {
+    unit: '元',
+    sign: '¥'
+  },
+
+  common: {
+    save: '保存',
+    modify: '修改',
+    submit: '提交'
+  },
+
+  shop: {
+    productCode: '商品编号',
+    productName: '商品名称',
+    productPrice: '商品价格',
+    productPicture: '商品图片',
+    productBV: '商品BV',
+    qty: '数量',
+    taxRate: '税率',
+    taxAmount: '税额',
+    totalPrice: '商品总价',
+    orderCode: '订单编号',
+    orderType: '订单类型',
+    memberCode: '会员编号',
+    memberName: '会员姓名',
+    recipientName: '收货人',
+    phoneNumber: '收货电话',
+    shippingAddress: '收货地址',
+    payment: '支付方式',
+    createdTime: '下单时间',
+    payTime: '支付时间',
+    payStatus: '支付状态',
+    action: '操作',
+    download: '下载',
+    sponsorCode: '接点人编号',
+    inventory: '库存',
+    checkOut: '结算',
+    unPaid: '待支付',
+    paid: '已支付'
+  },
+
+  user: {
+    email: '电子邮箱'
+  },
+
+  profile: {
+    personalInformation: '个人资料',
+    account: '账户',
+    loginPassword: '登录密码',
+    paymentPassword: '支付密码',
+    originalPassword: '原密码',
+    newPassword: '新密码',
+    confirmPassword: '重复新密码'
+  },
 }

+ 1 - 1
src/layout/components/Sidebar/Logo.vue

@@ -24,7 +24,7 @@ export default {
   },
   data() {
     return {
-      title: 'Vue Element Admin',
+      title: 'Member Management System',
       logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png'
     }
   }

+ 169 - 202
src/router/index.js

@@ -11,6 +11,8 @@ import componentsRouter from './modules/components'
 import chartsRouter from './modules/charts'
 import tableRouter from './modules/table'
 import nestedRouter from './modules/nested'
+import shopRouter from '@/router/modules/shop'
+import profileRouter from '@/router/modules/profileRouter'
 
 /**
  * Note: sub-menu only appear when route children.length >= 1
@@ -83,7 +85,7 @@ export const constantRoutes = [
         meta: { title: 'dashboard', icon: 'dashboard', affix: true }
       }
     ]
-  },
+  }
   // {
   //   path: '/dashboard/index',
   //   component: Layout,
@@ -122,20 +124,6 @@ export const constantRoutes = [
   //     }
   //   ]
   // },
-  {
-    path: '/profile',
-    component: Layout,
-    redirect: '/profile/index',
-    hidden: true,
-    children: [
-      {
-        path: 'index',
-        component: () => import('@/views/profile/index'),
-        name: 'Profile',
-        meta: { title: 'profile', icon: 'user', noCache: true }
-      }
-    ]
-  }
 ]
 
 /**
@@ -143,29 +131,6 @@ export const constantRoutes = [
  * the routes that need to be dynamically loaded based on user roles
  */
 export const asyncRoutes = [
-  {
-    path: '/shop',
-    component: Layout,
-    redirect: '/shop/index',
-    // alwaysShow: true,
-    name: 'Shop',
-    meta: {
-      title: 'shop',
-      icon: 'edit',
-      // roles: ['admin', 'editor']
-    },
-    children: [
-      {
-        path: '/shop/index',
-        component: () => import('@/views/shop/index'),
-        name: 'IndexShop',
-        meta: {
-          title: 'indexShop',
-          roles: ['admin', 'editor'] // or you can only set roles in sub nav
-        }
-      }
-    ]
-  },
   {
     path: '/permission',
     component: Layout,
@@ -226,51 +191,53 @@ export const asyncRoutes = [
   chartsRouter,
   nestedRouter,
   tableRouter,
+  shopRouter,
+  profileRouter,
 
-  {
-    path: '/example',
-    component: Layout,
-    redirect: '/example/list',
-    name: 'Example',
-    meta: {
-      title: 'example',
-      icon: 'el-icon-s-help'
-    },
-    children: [
-      {
-        path: 'create',
-        component: () => import('@/views/example/create'),
-        name: 'CreateArticle',
-        meta: { title: 'createArticle', icon: 'edit' }
-      },
-      {
-        path: 'edit/:id(\\d+)',
-        component: () => import('@/views/example/edit'),
-        name: 'EditArticle',
-        meta: { title: 'editArticle', noCache: true, activeMenu: '/example/list' },
-        hidden: true
-      },
-      {
-        path: 'list',
-        component: () => import('@/views/example/list'),
-        name: 'ArticleList',
-        meta: { title: 'articleList', icon: 'list' }
-      }
-    ]
-  },
+  // {
+  //   path: '/example',
+  //   component: Layout,
+  //   redirect: '/example/list',
+  //   name: 'Example',
+  //   meta: {
+  //     title: 'example',
+  //     icon: 'el-icon-s-help'
+  //   },
+  //   children: [
+  //     {
+  //       path: 'create',
+  //       component: () => import('@/views/example/create'),
+  //       name: 'CreateArticle',
+  //       meta: { title: 'createArticle', icon: 'edit' }
+  //     },
+  //     {
+  //       path: 'edit/:id(\\d+)',
+  //       component: () => import('@/views/example/edit'),
+  //       name: 'EditArticle',
+  //       meta: { title: 'editArticle', noCache: true, activeMenu: '/example/list' },
+  //       hidden: true
+  //     },
+  //     {
+  //       path: 'list',
+  //       component: () => import('@/views/example/list'),
+  //       name: 'ArticleList',
+  //       meta: { title: 'articleList', icon: 'list' }
+  //     }
+  //   ]
+  // },
 
-  {
-    path: '/tab',
-    component: Layout,
-    children: [
-      {
-        path: 'index',
-        component: () => import('@/views/tab/index'),
-        name: 'Tab',
-        meta: { title: 'tab', icon: 'tab' }
-      }
-    ]
-  },
+  // {
+  //   path: '/tab',
+  //   component: Layout,
+  //   children: [
+  //     {
+  //       path: 'index',
+  //       component: () => import('@/views/tab/index'),
+  //       name: 'Tab',
+  //       meta: { title: 'tab', icon: 'tab' }
+  //     }
+  //   ]
+  // },
 
   {
     path: '/error',
@@ -310,128 +277,128 @@ export const asyncRoutes = [
     ]
   },
 
-  {
-    path: '/excel',
-    component: Layout,
-    redirect: '/excel/export-excel',
-    name: 'Excel',
-    meta: {
-      title: 'excel',
-      icon: 'excel'
-    },
-    children: [
-      {
-        path: 'export-excel',
-        component: () => import('@/views/excel/export-excel'),
-        name: 'ExportExcel',
-        meta: { title: 'exportExcel' }
-      },
-      {
-        path: 'export-selected-excel',
-        component: () => import('@/views/excel/select-excel'),
-        name: 'SelectExcel',
-        meta: { title: 'selectExcel' }
-      },
-      {
-        path: 'export-merge-header',
-        component: () => import('@/views/excel/merge-header'),
-        name: 'MergeHeader',
-        meta: { title: 'mergeHeader' }
-      },
-      {
-        path: 'upload-excel',
-        component: () => import('@/views/excel/upload-excel'),
-        name: 'UploadExcel',
-        meta: { title: 'uploadExcel' }
-      }
-    ]
-  },
-
-  {
-    path: '/zip',
-    component: Layout,
-    redirect: '/zip/download',
-    alwaysShow: true,
-    name: 'Zip',
-    meta: { title: 'zip', icon: 'zip' },
-    children: [
-      {
-        path: 'download',
-        component: () => import('@/views/zip/index'),
-        name: 'ExportZip',
-        meta: { title: 'exportZip' }
-      }
-    ]
-  },
-
-  {
-    path: '/pdf',
-    component: Layout,
-    redirect: '/pdf/index',
-    children: [
-      {
-        path: 'index',
-        component: () => import('@/views/pdf/index'),
-        name: 'PDF',
-        meta: { title: 'pdf', icon: 'pdf' }
-      }
-    ]
-  },
-  {
-    path: '/pdf/download',
-    component: () => import('@/views/pdf/download'),
-    hidden: true
-  },
-
-  {
-    path: '/theme',
-    component: Layout,
-    children: [
-      {
-        path: 'index',
-        component: () => import('@/views/theme/index'),
-        name: 'Theme',
-        meta: { title: 'theme', icon: 'theme' }
-      }
-    ]
-  },
-
-  {
-    path: '/clipboard',
-    component: Layout,
-    children: [
-      {
-        path: 'index',
-        component: () => import('@/views/clipboard/index'),
-        name: 'ClipboardDemo',
-        meta: { title: 'clipboardDemo', icon: 'clipboard' }
-      }
-    ]
-  },
-
-  {
-    path: '/i18n',
-    component: Layout,
-    children: [
-      {
-        path: 'index',
-        component: () => import('@/views/i18n-demo/index'),
-        name: 'I18n',
-        meta: { title: 'i18n', icon: 'international' }
-      }
-    ]
-  },
+  // {
+  //   path: '/excel',
+  //   component: Layout,
+  //   redirect: '/excel/export-excel',
+  //   name: 'Excel',
+  //   meta: {
+  //     title: 'excel',
+  //     icon: 'excel'
+  //   },
+  //   children: [
+  //     {
+  //       path: 'export-excel',
+  //       component: () => import('@/views/excel/export-excel'),
+  //       name: 'ExportExcel',
+  //       meta: { title: 'exportExcel' }
+  //     },
+  //     {
+  //       path: 'export-selected-excel',
+  //       component: () => import('@/views/excel/select-excel'),
+  //       name: 'SelectExcel',
+  //       meta: { title: 'selectExcel' }
+  //     },
+  //     {
+  //       path: 'export-merge-header',
+  //       component: () => import('@/views/excel/merge-header'),
+  //       name: 'MergeHeader',
+  //       meta: { title: 'mergeHeader' }
+  //     },
+  //     {
+  //       path: 'upload-excel',
+  //       component: () => import('@/views/excel/upload-excel'),
+  //       name: 'UploadExcel',
+  //       meta: { title: 'uploadExcel' }
+  //     }
+  //   ]
+  // },
+  //
+  // {
+  //   path: '/zip',
+  //   component: Layout,
+  //   redirect: '/zip/download',
+  //   alwaysShow: true,
+  //   name: 'Zip',
+  //   meta: { title: 'zip', icon: 'zip' },
+  //   children: [
+  //     {
+  //       path: 'download',
+  //       component: () => import('@/views/zip/index'),
+  //       name: 'ExportZip',
+  //       meta: { title: 'exportZip' }
+  //     }
+  //   ]
+  // },
+  //
+  // {
+  //   path: '/pdf',
+  //   component: Layout,
+  //   redirect: '/pdf/index',
+  //   children: [
+  //     {
+  //       path: 'index',
+  //       component: () => import('@/views/pdf/index'),
+  //       name: 'PDF',
+  //       meta: { title: 'pdf', icon: 'pdf' }
+  //     }
+  //   ]
+  // },
+  // {
+  //   path: '/pdf/download',
+  //   component: () => import('@/views/pdf/download'),
+  //   hidden: true
+  // },
+  //
+  // {
+  //   path: '/theme',
+  //   component: Layout,
+  //   children: [
+  //     {
+  //       path: 'index',
+  //       component: () => import('@/views/theme/index'),
+  //       name: 'Theme',
+  //       meta: { title: 'theme', icon: 'theme' }
+  //     }
+  //   ]
+  // },
+  //
+  // {
+  //   path: '/clipboard',
+  //   component: Layout,
+  //   children: [
+  //     {
+  //       path: 'index',
+  //       component: () => import('@/views/clipboard/index'),
+  //       name: 'ClipboardDemo',
+  //       meta: { title: 'clipboardDemo', icon: 'clipboard' }
+  //     }
+  //   ]
+  // },
 
-  {
-    path: 'external-link',
-    component: Layout,
-    children: [
-      {
-        path: 'https://github.com/PanJiaChen/vue-element-admin',
-        meta: { title: 'externalLink', icon: 'link' }
-      }
-    ]
-  },
+  // {
+  //   path: '/i18n',
+  //   component: Layout,
+  //   children: [
+  //     {
+  //       path: 'index',
+  //       component: () => import('@/views/i18n-demo/index'),
+  //       name: 'I18n',
+  //       meta: { title: 'i18n', icon: 'international' }
+  //     }
+  //   ]
+  // },
+  //
+  // {
+  //   path: 'external-link',
+  //   component: Layout,
+  //   children: [
+  //     {
+  //       path: 'https://github.com/PanJiaChen/vue-element-admin',
+  //       meta: { title: 'externalLink', icon: 'link' }
+  //     }
+  //   ]
+  // },
 
   // 404 page must be placed at the end !!!
   { path: '*', redirect: '/404', hidden: true }

+ 17 - 0
src/router/modules/profileRouter.js

@@ -0,0 +1,17 @@
+import Layout from '@/layout'
+
+const profileRouter = {
+  path: '/profile',
+  component: Layout,
+  redirect: '/profile/index',
+  hidden: true,
+  children: [
+    {
+      path: 'index',  // 用户中心
+      component: () => import('@/views/profile/index'),
+      name: 'Profile',
+      meta: { title: 'profile', icon: 'user', noCache: true }
+    },
+  ]
+}
+export default profileRouter

+ 52 - 0
src/router/modules/shop.js

@@ -0,0 +1,52 @@
+import Layout from '@/layout'
+
+const shopRouter = {
+  path: '/shop',
+  component: Layout,
+  redirect: '/shop/standard-products',
+  name: 'Shopping Mall',
+  meta: {
+    title: 'shop',
+    icon: 'el-icon-s-goods'
+  },
+  children: [
+    {
+      path: 'standard-products', // 普通商品列表
+      component: () => import('@/views/shop/standard-products'),
+      name: 'StandardProducts',
+      meta: { title: 'standardProducts', icon: 'el-icon-goods' }
+    },
+    {
+      path: 'car-fund-products',  // 车奖商品列表
+      component: () => import('@/views/shop/car-fund-products'),
+      name: 'CarFundProducts',
+      meta: { title: 'carFundProducts', icon: 'el-icon-goods' }
+    },
+    {
+      path: 'villa-fund-products',  // 房奖商品列表
+      component: () => import('@/views/shop/villa-fund-products'),
+      name: 'VillaFundProducts',
+      meta: { title: 'villaFundProducts', icon: 'el-icon-goods' }
+    },
+    {
+      path: 'shopping-cart',  // 购物车
+      component: () => import('@/views/shop/shopping-cart'),
+      name: 'ShoppingCart',
+      meta: { title: 'shoppingCart', icon: 'el-icon-shopping-cart-full' },
+      hidden: true
+    },
+    {
+      path: 'dec-order-list', // 报单列表
+      component: () => import('@/views/shop/dec-order-list'),
+      name: 'DecOrderList',
+      meta: { title: 'DecOrderList', icon: 'el-icon-goods' }
+    },
+    {
+      path: 'order-list', // 订单列表
+      component: () => import('@/views/shop/order-list'),
+      name: 'OrderList',
+      meta: { title: 'orderList', icon: 'el-icon-goods' }
+    }
+  ]
+}
+export default shopRouter

+ 9 - 1
src/store/getters.js

@@ -11,6 +11,14 @@ const getters = {
   introduction: state => state.user.introduction,
   roles: state => state.user.roles,
   permission_routes: state => state.permission.routes,
-  errorLogs: state => state.errorLog.logs
+  errorLogs: state => state.errorLog.logs,
+  email: state => state.user.email,
+  mobile: state => state.user.mobile,
+  realName: state => state.user.realName,
+  decLv: state => state.user.decLv,
+  empLv: state => state.user.empLv,
+  crownLv: state => state.user.crownLv,
+  remainBV: state => state.user.remainBV,
+  joinAt: state => state.user.joinAt
 }
 export default getters

+ 19 - 8
src/store/modules/user.js

@@ -1,7 +1,11 @@
-import { login, logout, getInfo, isLoginVerify, getUserInfo, getBaseInfo, getMessageData } from '@/api/user'
+import { login, isLoginVerify, getUserInfo, getBaseInfo, getMessageData } from '@/api/user'
 import { getToken, setToken, removeToken } from '@/utils/auth'
 import router, { resetRouter } from '@/router'
 import usersInfo from '@/utils/usersInfo'
+import {
+  clearBaseInfo,
+  setBaseInfo
+} from '@/utils/localUserInfo'
 
 const state = {
   token: getToken(),
@@ -60,9 +64,9 @@ const actions = {
       })
     })
   },
-  isLoginVerify( { commit }, data ) {
+  isLoginVerify({ commit }, data) {
     return new Promise((resolve, reject) => {
-      isLoginVerify({userName: data.userName}).then(response => {
+      isLoginVerify({ userName: data.userName }).then(response => {
         resolve(response.data)
       }).catch(error => {
         reject(error)
@@ -75,14 +79,21 @@ const actions = {
         let ret = response.data
         usersInfo.userId(ret.ID)
         usersInfo.userName(ret.USER_NAME)
+        usersInfo.userEmail(ret.EMAIL)
         usersInfo.baseData({
           AVATAR: ret.AVATAR,
           VERIFIED: ret.VERIFIED,
           DEC_LV: ret.DEC_LV,
           EMP_LV: ret.EMP_LV,
+          CROWN_LV: ret.CROWN_LV,
           PROVINCE: ret.PROVINCE,
           CITY: ret.CITY,
-          COUNTY: ret.COUNTY
+          COUNTY: ret.COUNTY,
+          EMAIL: ret.EMAIL,
+          BANK_NO: ret.BANK_NO,
+          MOBILE: ret.MOBILE,
+          CREATED_AT: ret.CREATED_AT,
+          REAL_NAME: ret.REAL_NAME
         })
         resolve(response)
       }).catch(error => {
@@ -96,6 +107,8 @@ const actions = {
         let ret = response.data
         usersInfo.clearBaseInfo()
         usersInfo.setBaseInfo(ret)
+        clearBaseInfo()
+        setBaseInfo(ret)
         resolve(response)
       }).catch(error => {
         reject(error)
@@ -108,6 +121,8 @@ const actions = {
         let ret = response.data
         usersInfo.clearBaseInfo()
         usersInfo.setBaseInfo(ret)
+        clearBaseInfo()
+        setBaseInfo(ret)
         resolve(response)
       }).catch(error => {
         reject(error)
@@ -124,8 +139,6 @@ const actions = {
       usersInfo.baseData()
       removeToken()
       resetRouter()
-      // reset visited views and cached views
-      // to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485
       dispatch('tagsView/delAllViews', null, { root: true })
       resolve()
     })
@@ -159,8 +172,6 @@ const actions = {
   //   })
   // },
 
-  
-
   // // user logout
   // logout({ commit, state, dispatch }) {
   //   return new Promise((resolve, reject) => {

+ 1 - 1
src/utils/get-page-title.js

@@ -1,7 +1,7 @@
 import defaultSettings from '@/settings'
 import i18n from '@/lang'
 
-const title = defaultSettings.title || 'Vue Element Admin'
+const title = defaultSettings.title || 'Member Management System'
 
 export default function getPageTitle(key) {
   const hasKey = i18n.te(`route.${key}`)

+ 16 - 16
src/utils/request.js

@@ -9,7 +9,7 @@ const service = axios.create({
   baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
 
   // withCredentials: true, // send cookies when cross-domain requests
-  timeout: 5000 // request timeout
+  timeout: 12000 // request timeout
 })
 // request interceptor
 service.interceptors.request.use(
@@ -77,27 +77,27 @@ service.interceptors.request.use(
 // response interceptor
 service.interceptors.response.use(
   response => {
-  const responseData = response.data
-  const data = responseData.data
-  if (responseData.success === false) {
+    const responseData = response.data
+    const data = responseData.data
+    if (responseData.success === false) {
     // const err = new Error(data.message)
     // err.data = data
     // err.message = data.message
     // err.response = response
     // throw err
-    Message({
-      message: data.message || 'Error',
-      type: 'error',
-      duration: 5 * 1000
-    })
-    return
-  } else {
-    if (!data) {
-      return {data: responseData}
+      Message({
+        message: data.message || 'Error',
+        type: 'error',
+        duration: 5 * 1000
+      })
+      return
+    } else {
+      if (!data) {
+        return { data: responseData }
+      }
+      return data
     }
-    return data
-  }
-},
+  },
   err => {
     if (err && err.response && err.response.data && err.response.data.message) {
       err.message = err.response.data.message

+ 57 - 50
src/utils/tool.js

@@ -2,8 +2,9 @@
 // import baseInfo from './baseInfo'
 // import {PRICE_IS_ROUND,SERVER_API_HTTP_TYPE,SERVER_API_DOMAIN,CDN_BASE_URL} from './config'
 import usersInfo from '@/utils/usersInfo'
+import errorCode from "core-js/internals/internal-state";
 
-let tool = {
+const tool = {
   /**
    * 设置JS存在客户端的Storage值
    * @param key
@@ -42,19 +43,19 @@ let tool = {
     return Math.round(dateObj.getTime() / 1000 + (days * 86400))
   },
   formatDate(timestamp, withTime = true) {
-    let newDate = new Date()
+    const newDate = new Date()
     timestamp = parseInt(timestamp)
     if (timestamp) {
       newDate.setTime(timestamp * 1000)
     } else {
       return ''
     }
-    let Y = newDate.getFullYear() + '-'
-    let M = (newDate.getMonth() + 1 < 10 ? '0' + (newDate.getMonth() + 1) : newDate.getMonth() + 1) + '-'
-    let D = (newDate.getDate() < 10 ? '0' + (newDate.getDate()) : newDate.getDate()) + ' '
-    let h = (newDate.getHours() < 10 ? '0' + newDate.getHours() : newDate.getHours()) + ':'
-    let m = (newDate.getMinutes() < 10 ? '0' + newDate.getMinutes() : newDate.getMinutes()) + ':'
-    let s = (newDate.getSeconds() < 10 ? '0' + newDate.getSeconds() : newDate.getSeconds())
+    const Y = newDate.getFullYear() + '-'
+    const M = (newDate.getMonth() + 1 < 10 ? '0' + (newDate.getMonth() + 1) : newDate.getMonth() + 1) + '-'
+    const D = (newDate.getDate() < 10 ? '0' + (newDate.getDate()) : newDate.getDate()) + ' '
+    const h = (newDate.getHours() < 10 ? '0' + newDate.getHours() : newDate.getHours()) + ':'
+    const m = (newDate.getMinutes() < 10 ? '0' + newDate.getMinutes() : newDate.getMinutes()) + ':'
+    const s = (newDate.getSeconds() < 10 ? '0' + newDate.getSeconds() : newDate.getSeconds())
     if (withTime) return Y + M + D + h + m + s
     return Y + M + D
   },
@@ -68,7 +69,7 @@ let tool = {
     let status = 0
     let todo
     if (errorCode.has(error)) {
-      let errorResult = errorCode.get(error)
+      const errorResult = errorCode.get(error)
       message = errorResult.message
       status = errorResult.status ? errorResult.status : 0
       todo = errorResult.todo
@@ -85,7 +86,7 @@ let tool = {
       message = todo?'长时间未进行操作,请重新登录':(message==='Connection not operated for too long' ?'长时间未进行操作,请重新登录' :message)
       usersInfo.logout()
     }
-    return {message, todo, status}
+    return { message, todo, status }
   },
   /**
    * 解析URL地址
@@ -104,7 +105,7 @@ let tool = {
    * @returns {{source: *, protocol: string, host: string, port: string, query: string, params, file: string | *, hash: string, path: string, relative: string | *, segments: string[]}}
    */
   parseURL(url) {
-    let a = document.createElement('a')
+    const a = document.createElement('a')
     a.href = url
     return {
       source: url,
@@ -112,13 +113,13 @@ let tool = {
       host: a.hostname,
       port: a.port,
       query: a.search,
-      params: (function () {
-        let waitUrl = a.hash.replace(/^#\/[\-_a-zA-Z0-9]+\?/, '\?') || a.search
-        let ret = {},
-          seg = waitUrl.replace(/^\?/, '').split('&'),
-          len = seg.length,
-          i = 0,
-          s
+      params: (function() {
+        const waitUrl = a.hash.replace(/^#\/[\-_a-zA-Z0-9]+\?/, '\?') || a.search
+        const ret = {}
+        const seg = waitUrl.replace(/^\?/, '').split('&')
+        const len = seg.length
+        let i = 0
+        let s
         for (; i < len; i++) {
           if (!seg[i]) {
             continue
@@ -144,7 +145,7 @@ let tool = {
     }
   },
   isInArray(arr, value) {
-    for (let i in arr) {
+    for (const i in arr) {
       if (value === arr[i]) {
         return true
       }
@@ -161,12 +162,7 @@ let tool = {
    */
   formatPrice(val) {
     val = Number.parseFloat(val)
-    if (PRICE_IS_ROUND) {
-      return val.toFixed(2)
-    } else {
-      val = val.toFixed(3)
-      return val.substring(0, val.lastIndexOf('.') + 3)
-    }
+    return val.toFixed(2)
   },
   /**
    * 根据状态返回颜色
@@ -177,57 +173,68 @@ let tool = {
     switch (val) {
       case '0':
         return 'info'
-        break
       case '1':
         return ''
-        break
       case '2':
         return 'danger'
-        break
       case '3':
         return 'warning'
-        break
       case '4':
         return 'success'
-        break
       default:
         return 'info'
     }
   },
-  sum(arr) {//求数组总和
-    var s = 0;
-    for (var i=arr.length-1; i>=0; i--) {
-        s += arr[i];
+  sum(arr) { // 求数组总和
+    var s = 0
+    for (var i = arr.length - 1; i >= 0; i--) {
+      s += arr[i]
     }
-    return s;
+    return s
   },
-    /**
+  /**
      * 获取table显示高度
      * @param hasStatusBar
      * @returns {number}
      */
-    getTableHeight(hasStatusBar = false) {
-        if (hasStatusBar) return window.innerHeight - 320
-        return window.innerHeight - 260
-    },
+  getTableHeight(hasStatusBar = false) {
+    if (hasStatusBar) return window.innerHeight - 320
+    return window.innerHeight - 260
+  },
 
-  /**
-   * 拼装图片地址.
-   * @param imageUrl
-   * @param path
-   * @returns {string}
-   */
-  getLocaleLink(imageUrl, path = '') {
-      return imageUrl.indexOf('http') > -1 ? imageUrl : `${CDN_BASE_URL}${path}${imageUrl}`;
+  // /**
+  //  * 拼装图片地址.
+  //  * @param imageUrl
+  //  * @param path
+  //  * @returns {string}
+  //  */
+  // getLocaleLink(imageUrl, path = '') {
+  //   return imageUrl.indexOf('http') > -1 ? imageUrl : `${process.env.VUE_APP_CDN_API}${path}${imageUrl}`
+  // },
+
+  // 计算商品税额
+  calculateTax(amount, taxRate, count = 1) {
+    const taxAmount = (amount - amount / (1 + taxRate / 100)) * count
+    return Math.round(taxAmount * 100) / 100
+  },
+
+  // 计算商品BV
+  calculateBV(amount, count = 1) {
+    return Math.round(amount * count)
   },
+
   /**
    * 拼装图片
    * @param imageUrl 图片
    * @param path 路径
    * @returns {string}
    */
-   getArImage(imageUrl, path) {
-    return `${process.env.VUE_APP_BASE_CDN}${path}${imageUrl}`;
+  getArImage(imageUrl, path) {
+    return process.env.VUE_APP_CDN_API + `/${path}${imageUrl}`
+  },
+
+  getEmpLv(id) {
+    // return id.length > 0 ? getBaseInfo().empLevels : 'No Rank';
   }
 }
 

+ 10 - 0
src/utils/usersInfo.js

@@ -139,6 +139,16 @@ let usersInfo = {
         }
         localStorage.setItem('userName', arg[0])
       },
+      userEmail (...arg) {
+        if (arg.length === 0) {
+          return localStorage.getItem('userEmail')
+        }
+        if (arg[0] === '') {
+          localStorage.removeItem('userEmail')
+          return
+        }
+        localStorage.setItem('userEmail', arg[0])
+      },
       updateLoginAllInfo (response) {
         // 更新本地accessToken
         this.accessToken(response.accessToken)

+ 229 - 0
src/views/shop/car-fund-products.vue

@@ -0,0 +1,229 @@
+<template>
+	<div class="app-container">
+		<el-table
+			:key="tableKey"
+			v-loading="listLoading"
+			:data="tableData"
+			border
+			fit
+			highlight-current-row
+			style="width: 100%;"
+			ref="multipleTable"
+			@selection-change="handleSelectionChange"
+		>
+			<el-table-column type="selection" width="70" align="center"></el-table-column>
+			<el-table-column :label="$t('shop.productName')" align="center" prop="GOODS_NAME">
+				<template slot-scope="{row}">
+					<span>{{ row.GOODS_NAME }}</span>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.productPicture')" align="center" min-width="70px" prop="GOODS_NAME">
+				<template slot-scope="{row}">
+					<el-image
+						style="width: 70px; height: 70px"
+						:src="tool.getArImage(row.COVER, '/files/')"
+						:preview-src-list="[tool.getArImage(row.COVER, '/files/')]"
+					>
+					</el-image>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.productPrice')" align="center" prop="SELL_PRICE">
+				<template slot-scope="{row}">
+					<span>{{ row.SELL_PRICE }}</span>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.productBV')" align="center" prop="PRICE_PV">
+				<template slot-scope="{row}">
+					<span>{{ row.PRICE_PV }}</span>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.taxRate')" align="center" prop="TAX_RATE">
+				<template slot-scope="{row}">
+					<span>{{ row.TAX_RATE / 100  }}</span>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.taxAmount')" align="center">
+				<template slot-scope="{row}">
+					<span>{{ row | taxAmountFilter }}</span>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.inventory')" align="center" prop="STORE_NUMS">
+				<template slot-scope="{row}">
+					<span>{{ row.STORE_NUMS }}</span>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.inventory')" min-width="90" align="center">
+				<template slot-scope="scope">
+					<el-input-number size="mini" v-model="storeNums[scope.$index]" :min="0" :max="Number(scope.row.STORE_NUMS)" @change="(val)=>{handleInputNumber(val, scope.row)}"></el-input-number>
+				</template>
+			</el-table-column>
+		</el-table>
+
+		<pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
+
+		<div class="white-box-footer" v-show="display" style="margin-top: 15px;">
+			<div class="flex data" style="float: left; display: inline-block; margin-top: 20px;">
+				<el-button type="primary" size="small" @click="settlement()" style="float: left;">{{ $t('shop.checkOut') }}</el-button>
+			</div>
+			<div class="flex data" style="float: right; display: inline-block; line-height: 35px; font-size: 14px; margin-top: 20px; border: 1px solid #dcdfe6; border-radius: 4px; padding: 0 15px;">
+				<div style="margin-right: 2rem; display: inline-block;">{{ $t('shop.productPrice') }}:{{ $t('currency.sign') }} {{ sellPriceSum }}</div>
+				<div style="margin-right: 2rem; display: inline-block;">{{ $t('shop.productBV') }}:{{ $t('currency.sign') }} {{ pricePvSum }}</div>
+				<div style="display: inline-block;">{{ $t('shop.taxAmount') }}:{{ $t('currency.sign') }} {{ taxSum }}</div>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+import { fetchProductList, fetchProduct } from '@/api/shop'
+import waves from '@/directive/waves'
+import { parseTime } from '@/utils'
+import tool from '@/utils/tool'
+import Pagination from '@/components/Pagination'
+
+export default {
+	name: 'carFundProducts',
+	components: { Pagination },
+	directives: { waves },
+	filters: {
+		priceFilter(price) {
+			return tool.formatPrice(price)
+		},
+		taxAmountFilter(row) {
+			return tool.calculateTax(row.SELL_PRICE, row.TAX_RATE)
+		},
+		statusFilter(status) {
+			const statusMap = {
+				Unpaid: 'info',
+				Paid: 'success',
+			}
+			return statusMap[status]
+		},
+	},
+	data() {
+		return {
+			tableKey: 0,
+			list: [],
+			total: 0,
+			tableData: [],
+			listLoading: true,
+			listQuery: {
+				categoryType: 5,
+				page: 1,
+				limit: 20,
+			},
+			tool: tool,
+			multipleSelection: [],
+			sellPriceSum: 0.00,
+			pricePvSum: 0.00,
+			taxSum: 0.00,
+			storeNums: [],
+			display: false,
+			currentPage: 1,
+		}
+	},
+	created() {
+		// 商品列表查询
+		this.getList()
+	},
+	methods: {
+		// 商品类别
+		getList() {
+			this.listLoading = true
+			fetchProductList(this.listQuery).then(response => {
+				this.list = response.data.list
+				this.total = parseInt(response.data.totalCount)
+
+				setTimeout(() => {
+					this.listLoading = false
+				}, 1.5 * 1000)
+
+				let settingObj = this.list
+				for (let i in this.list) {
+					this.storeNums[i] = 1
+					settingObj[i].chose_num = 0
+				}
+
+				this.tableData = Object.values(settingObj)
+				let pageList = this.multipleSelection[this.currentPage]
+				this.$nextTick(function () {
+					for (let i in this.tableData) {
+						for( let j in  pageList) {
+							if( pageList[j].ID === this.tableData[i].ID ) {
+								this.$data.storeNums[i] = pageList[j].chose_num
+								this.tableData[i].chose_num = pageList[j].chose_num
+								break
+							}
+						}
+					}
+				})
+			})
+		},
+		// 选择商品计数
+		handleInputNumber(val, row){
+			let pageList = this.multipleSelection[this.currentPage]
+			let selectStatus = false
+			for (let i in pageList) {
+				if( pageList[i].ID === row.ID ) {
+					pageList[i].chose_num = val
+					selectStatus = true
+					break
+				}
+			}
+
+			if (selectStatus) {
+				this.multipleSelection[this.currentPage] = pageList
+				this.handleSureChange()
+			}
+		},
+		// 统计商品
+		handleSureChange() {
+			if (this.multipleSelection.length > 0) {
+				let accumulatorSellPrice = 0, accumulatorPricePv = 0, accumulatorTax = 0
+				this.multipleSelection.forEach(item => {
+					item.forEach(accumulator => { accumulatorSellPrice += accumulator.SELL_PRICE * accumulator.chose_num * accumulator.DISCOUNT / 100; })
+					item.forEach(accumulator => { accumulatorPricePv += Number(accumulator.PRICE_PV) * Number(accumulator.chose_num) * (Number(accumulator.DISCOUNT) / 100); })
+					item.forEach(accumulator => { accumulatorTax += tool.calculateTax(Number(accumulator.SELL_PRICE), Number(accumulator.TAX_RATE), Number(accumulator.chose_num)); })
+				})
+
+				this.sellPriceSum = tool.formatPrice(accumulatorSellPrice)
+				this.pricePvSum = tool.formatPrice(accumulatorPricePv)
+				this.taxSum = tool.formatPrice(accumulatorTax)
+
+				this.display = true
+			} else {
+				this.sellPriceSum = this.pricePvSum = this.taxSum = 0.00
+				this.display = true
+			}
+		},
+		handleSelectionChange(val) {
+			let idx = -1, num
+			for (let i in this.tableData) {
+				for (let v in val) {
+					if (val[v].ID === this.tableData[i].ID) {
+						idx = i
+						num = this.storeNums[idx]
+						val[v]["chose_num"] = num
+						break
+					}
+				}
+			}
+			this.multipleSelection[this.currentPage] = val
+
+			// 计算统计
+			this.handleSureChange()
+		},
+		// 结算商品
+		settlement() {
+
+		}
+	},
+	watch: {
+		// 监听多选按钮,判断结算按钮是否可用
+		multipleSelection: function (modern) {
+			console.log(modern, modern.length)
+			this.$data.display = modern.length > 0
+		},
+	},
+}
+</script>

+ 193 - 0
src/views/shop/dec-order-list.vue

@@ -0,0 +1,193 @@
+<template>
+  <div class="app-container">
+    <el-table
+      :key="tableKey"
+      v-loading="listLoading"
+      :data="list"
+      border
+      fit
+      highlight-current-row
+      style="width: 100%;"
+    >
+      <el-table-column width="120px" align="center" :label="$t('shop.productCode')" prop="SKU_CODE">
+        <template slot-scope="{row}">
+          <span>{{ row.SKU_CODE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="130px" align="center" :label="$t('shop.productName')" prop="GOODS_TITLE">
+        <template slot-scope="{row}">
+          <span>{{ row.GOODS_TITLE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="130px" align="center" :label="$t('shop.orderType')" prop="ORDER_TYPE">
+        <template slot-scope="{row}">
+          <span>{{ row.ORDER_TYPE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="120px" align="center" :label="$t('shop.productPrice')" prop="REAL_PRICE">
+        <template slot-scope="{row}">
+          <span>{{ row.REAL_PRICE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="120px" align="center" :label="$t('shop.productBV')" prop="REAL_PV">
+        <template slot-scope="{row}">
+          <span>{{ row | bvFilter }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="80px" align="center" :label="$t('shop.qty')" prop="BUY_NUMS">
+        <template slot-scope="{row}">
+          <span>{{ row.BUY_NUMS }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="80px" align="center" :label="$t('shop.taxRate')" prop="TAX_RATE">
+        <template slot-scope="{row}">
+          <span>{{ row.TAX_RATE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="120px" align="center" :label="$t('shop.taxAmount')" prop="TAX_AMOUNT">
+        <template slot-scope="{row}">
+          <span>{{ row.TAX_AMOUNT }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="120px" align="center" :label="$t('shop.totalPrice')" prop="TOTAL_AMOUNT">
+        <template slot-scope="{row}">
+          <span>{{ row.TOTAL_AMOUNT }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="150px" align="center" :label="$t('shop.orderCode')" prop="SN">
+        <template slot-scope="{row}">
+          <span>{{ row.SN }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="120px" align="center" :label="$t('shop.memberCode')" prop="USER_NAME">
+        <template slot-scope="{row}">
+          <span>{{ row.USER_NAME }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="130px" align="center" :label="$t('shop.memberName')" prop="REAL_NAME">
+        <template slot-scope="{row}">
+          <span>{{ row.REAL_NAME }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="130px" align="center" :label="$t('shop.recipientName')" prop="CONSIGNEE">
+        <template slot-scope="{row}">
+          <span>{{ row.CONSIGNEE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="130px" align="center" :label="$t('shop.phoneNumber')" prop="MOBILE">
+        <template slot-scope="{row}">
+          <span>{{ row.MOBILE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="150px" align="center" :label="$t('shop.shippingAddress')" prop="FULL_ADDRESS">
+        <template slot-scope="{row}">
+          <span>{{ row.FULL_ADDRESS }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="130px" align="center" :label="$t('shop.sponsorCode')" prop="CON_USER_NAME">
+        <template slot-scope="{row}">
+          <span>{{ row.CON_USER_NAME }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="130px" align="center" :label="$t('shop.payment')" prop="PAY_TYPE">
+        <template slot-scope="{row}">
+          <span>{{ row.PAY_TYPE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="150px" align="center" :label="$t('shop.createdTime')" prop="CREATED_AT">
+        <template slot-scope="{row}">
+          <span>{{ row.CREATED_AT | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="150px" align="center" :label="$t('shop.payTime')" prop="PAY_AT">
+        <template slot-scope="{row}">
+          <span>{{ row.PAY_AT | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column class-name="status-col" align="center" width="100" :label="$t('shop.payStatus')" prop="STATUS">
+        <template slot-scope="{row}">
+          <el-tag :type="row.STATUS | statusFilter">
+            {{ row.STATUS }}
+          </el-tag>
+        </template>
+      </el-table-column>
+
+      <el-table-column width="100px" align="center" :label="$t('shop.action')" class-name="small-padding fixed-width">
+        <template slot-scope="{row}">
+          <el-button type="primary" size="mini" @click="handleDownload(row.SN)">{{ $t('shop.download') }}</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
+  </div>
+</template>
+
+<script>
+import { fetchDecOrderList, downloadOrder } from '@/api/shop'
+import waves from '@/directive/waves'
+import { parseTime } from '@/utils'
+import tool from '@/utils/tool'
+import Pagination from '@/components/Pagination'
+
+export default {
+  name: 'OrderList',
+  components: { Pagination },
+  directives: { waves },
+  filters: {
+    bvFilter(row) {
+      return tool.calculateTax(row.REAL_PV, row.BUY_NUMS)
+    },
+    statusFilter(status) {
+      const statusMap = {
+        Unpaid: 'info',
+        Paid: 'success'
+      }
+      return statusMap[status]
+    }
+  },
+  data() {
+    return {
+      tableKey: 0,
+      list: null,
+      total: 0,
+      listLoading: true,
+      downloadLoading: false,
+      listQuery: {
+        page: 1,
+        pageSize: 20
+      }
+    }
+  },
+  created() {
+    // 订单列表查询
+    this.getList()
+  },
+  methods: {
+    getList() {
+      this.listLoading = true
+      fetchDecOrderList(this.listQuery).then(response => {
+        this.list = response.data.list
+        this.total = parseInt(response.data.totalCount)
+
+        setTimeout(() => {
+          this.listLoading = false
+        }, 1.5 * 1000)
+      })
+    },
+    handleDownload(orderSn) {
+      this.downloadLoading = true
+      downloadOrder(orderSn).then(response => {
+        const { fileUrl, targetName } = response.data
+        const downloadElement = document.createElement('a')
+        downloadElement.target = '_blank'
+        downloadElement.href = process.env.VUE_APP_BASE_API + '/' + fileUrl
+        downloadElement.download = targetName
+        downloadElement.click()
+      })
+
+      this.downloadLoading = false
+    }
+  }
+}
+</script>

+ 249 - 0
src/views/shop/order-list.vue

@@ -0,0 +1,249 @@
+<template>
+  <div class="app-container">
+    <el-table
+      :key="tableKey"
+      v-loading="listLoading"
+      :data="list"
+      border
+      fit
+      highlight-current-row
+      style="width: 100%;"
+      :span-method="objectSpanMethod"
+    >
+      <el-table-column width="120px" align="center" :label="$t('shop.productCode')" prop="SKU_CODE">
+        <template slot-scope="{row}">
+          <span>{{ row.SKU_CODE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="250px" align="center" :label="$t('shop.productName')" prop="GOODS_TITLE">
+        <template slot-scope="{row}">
+          <span>{{ row.GOODS_TITLE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="130px" align="center" :label="$t('shop.orderType')" prop="ORDER_TYPE">
+        <template slot-scope="{row}">
+          <span>{{ row.ORDER_TYPE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="120px" align="center" :label="$t('shop.productBV')" prop="REAL_PV">
+        <template slot-scope="{row}">
+          <span>{{ row | bvFilter }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="120px" align="center" :label="$t('shop.productPrice')" prop="REAL_PRICE">
+        <template slot-scope="{row}">
+          <span>{{ row.REAL_PRICE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="80px" align="center" :label="$t('shop.qty')" prop="BUY_NUMS">
+        <template slot-scope="{row}">
+          <span>{{ row.BUY_NUMS }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="120px" align="center" :label="$t('shop.totalPrice')" prop="TOTAL_AMOUNT">
+        <template slot-scope="{row}">
+          <span>{{ row.TOTAL_AMOUNT }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="80px" align="center" :label="$t('shop.taxRate')" prop="TAX_RATE">
+        <template slot-scope="{row}">
+          <span>{{ row.TAX_RATE / 100 }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="120px" align="center" :label="$t('shop.taxAmount')" prop="TAX_AMOUNT">
+        <template slot-scope="{row}">
+          <span>{{ row.TAX_AMOUNT }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="200px" align="center" :label="$t('shop.orderCode')" prop="SN">
+        <template slot-scope="{row}">
+          <span>{{ row.SN }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="120px" align="center" :label="$t('shop.memberCode')" prop="USER_NAME">
+        <template slot-scope="{row}">
+          <span>{{ row.USER_NAME }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="130px" align="center" :label="$t('shop.memberName')" prop="REAL_NAME">
+        <template slot-scope="{row}">
+          <span>{{ row.REAL_NAME }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="130px" align="center" :label="$t('shop.recipientName')" prop="CONSIGNEE">
+        <template slot-scope="{row}">
+          <span>{{ row.CONSIGNEE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="130px" align="center" :label="$t('shop.phoneNumber')" prop="MOBILE">
+        <template slot-scope="{row}">
+          <span>{{ row.MOBILE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="150px" align="center" :label="$t('shop.shippingAddress')" prop="FULL_ADDRESS">
+        <template slot-scope="{row}">
+          <span>{{ row.FULL_ADDRESS }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="130px" align="center" :label="$t('shop.payment')" prop="PAY_TYPE">
+        <template slot-scope="{row}">
+          <span>{{ row.PAY_TYPE }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="150px" align="center" :label="$t('shop.createdTime')" prop="CREATED_AT">
+        <template slot-scope="{row}">
+          <span>{{ row.CREATED_AT | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="150px" align="center" :label="$t('shop.payTime')" prop="PAY_AT">
+        <template slot-scope="{row}">
+          <span>{{ row.PAY_AT | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column class-name="status-col" align="center" width="100" :label="$t('shop.payStatus')" prop="STATUS">
+        <template slot-scope="{row}">
+          <el-tag :type="row.STATUS | statusFilter">
+            {{ row.STATUS }}
+          </el-tag>
+        </template>
+      </el-table-column>
+
+      <el-table-column width="100px" align="center" :label="$t('shop.action')" class-name="small-padding fixed-width">
+        <template slot-scope="{row}">
+          <el-button type="primary" size="mini" @click="handleDownload(row.SN)">{{ $t('shop.download') }}</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
+  </div>
+</template>
+
+<script>
+import { fetchOrderList, downloadOrder } from '@/api/shop'
+import waves from '@/directive/waves'
+import { parseTime } from '@/utils'
+import tool from '@/utils/tool'
+import Pagination from '@/components/Pagination'
+
+export default {
+  name: 'OrderList',
+  components: { Pagination },
+  directives: { waves },
+  filters: {
+    bvFilter(row) {
+      return tool.calculateBV(row.REAL_PV, row.BUY_NUMS)
+    },
+    taxAmountFilter(row) {
+      return tool.calculateTax(row.REAL_PV, row.BUY_NUMS)
+    },
+    statusFilter(status) {
+      const statusMap = {
+        Unpaid: 'info',
+        Paid: 'success'
+      }
+      return statusMap[status]
+    }
+  },
+  data() {
+    return {
+      tableKey: 0,
+      list: null,
+      tableData: null,
+      total: 0,
+      listLoading: true,
+      downloadLoading: false,
+      listQuery: {
+        page: 1,
+        pageSize: 20
+      },
+      spanArr: [],
+      pos: 0
+    }
+  },
+  created() {
+    // 订单列表查询
+    this.getList()
+  },
+  mounted() {
+    // 第1步,根据表体信息,计算合并单元格的信息
+    // this.computeCell(this.list)
+  },
+  methods: {
+    getList() {
+      this.listLoading = true
+      fetchOrderList(this.listQuery).then(response => {
+        this.list = response.data.list
+        this.total = parseInt(response.data.totalCount)
+        const settingObj = this.list
+        const settingArr = Object.keys(this.list).map(key => {
+          return settingObj[key]
+        })
+
+        this.tableData = settingArr
+        this.getSpanArr(this.tableData)
+
+        setTimeout(() => {
+          this.listLoading = false
+        }, 1.5 * 1000)
+      })
+    },
+    handleDownload(orderSn) {
+      this.downloadLoading = true
+      downloadOrder(orderSn).then(response => {
+        const { fileUrl, targetName } = response.data
+        const downloadElement = document.createElement('a')
+        downloadElement.target = '_blank'
+        downloadElement.href = process.env.VUE_APP_BASE_API + '/' + fileUrl
+        downloadElement.download = targetName
+        downloadElement.click()
+      })
+
+      this.downloadLoading = false
+    },
+    objectSpanMethod(obj) {
+      if (obj.columnIndex > 8) {
+        const _row = this.spanArr[obj.rowIndex]
+        const _col = _row > 0 ? 1 : 0
+        return {
+          rowspan: _row,
+          colspan: _col
+        }
+      } else {
+        return false
+      }
+    },
+    getSpanArr(orderList) {
+      this.pos = 0
+      orderList.forEach((item, index) => {
+        // 判断是否是第⼀项
+        if (index === 0) {
+          this.spanArr.push(1)
+          this.pos = 0
+        } else {
+          // 不是第⼀项时,就根据标识去存储
+          if (
+            orderList[index].ORDER_SN === orderList[index - 1].ORDER_SN &&
+							orderList[index].USER_NAME === orderList[index - 1].USER_NAME &&
+							orderList[index].REAL_NAME === orderList[index - 1].REAL_NAME &&
+							orderList[index].CONSIGNEE === orderList[index - 1].CONSIGNEE &&
+							orderList[index].MOBILE === orderList[index - 1].MOBILE &&
+							orderList[index].PAY_AT === orderList[index - 1].PAY_AT &&
+							orderList[index].STATUS === orderList[index - 1].STATUS &&
+							orderList[index].PAY_TYPE === orderList[index - 1].PAY_TYPE &&
+							orderList[index].CREATED_AT === orderList[index - 1].CREATED_AT
+          ) {
+            // 查找到符合条件的数据时每次要把之前存储的数据+1
+            this.spanArr[this.pos] += 1
+            this.spanArr.push(0)
+          } else {
+            // 没有符合的数据时,要记住当前的index
+            this.spanArr.push(1)
+            this.pos = index
+          }
+        }
+      })
+    }
+  }
+}
+</script>

+ 229 - 0
src/views/shop/standard-products.vue

@@ -0,0 +1,229 @@
+<template>
+<div class="app-container">
+  <el-table
+    :key="tableKey"
+    v-loading="listLoading"
+    :data="tableData"
+    border
+    fit
+    highlight-current-row
+    style="width: 100%;"
+		ref="multipleTable"
+		@selection-change="handleSelectionChange"
+  >
+		<el-table-column type="selection" width="70" align="center"></el-table-column>
+    <el-table-column :label="$t('shop.productName')" align="center" prop="GOODS_NAME">
+      <template slot-scope="{row}">
+        <span>{{ row.GOODS_NAME }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column :label="$t('shop.productPicture')" align="center" min-width="70px" prop="GOODS_NAME">
+      <template slot-scope="{row}">
+				<el-image
+					style="width: 70px; height: 70px"
+					:src="tool.getArImage(row.COVER, '/files/')"
+					:preview-src-list="[tool.getArImage(row.COVER, '/files/')]"
+				>
+				</el-image>
+      </template>
+    </el-table-column>
+    <el-table-column :label="$t('shop.productPrice')" align="center" prop="SELL_PRICE">
+      <template slot-scope="{row}">
+        <span>{{ row.SELL_PRICE }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column :label="$t('shop.productBV')" align="center" prop="PRICE_PV">
+      <template slot-scope="{row}">
+        <span>{{ row.PRICE_PV }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column :label="$t('shop.taxRate')" align="center" prop="TAX_RATE">
+      <template slot-scope="{row}">
+				<span>{{ row.TAX_RATE / 100  }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column :label="$t('shop.taxAmount')" align="center">
+      <template slot-scope="{row}">
+				<span>{{ row | taxAmountFilter }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column :label="$t('shop.inventory')" align="center" prop="STORE_NUMS">
+      <template slot-scope="{row}">
+				<span>{{ row.STORE_NUMS }}</span>
+      </template>
+    </el-table-column>
+		<el-table-column :label="$t('shop.inventory')" min-width="90" align="center">
+			<template slot-scope="scope">
+				<el-input-number size="mini" v-model="storeNums[scope.$index]" :min="0" :max="Number(scope.row.STORE_NUMS)" @change="(val)=>{handleInputNumber(val, scope.row)}"></el-input-number>
+			</template>
+		</el-table-column>
+  </el-table>
+
+	<pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
+
+	<div class="white-box-footer" v-show="display" style="margin-top: 15px;">
+		<div class="flex data" style="float: left; display: inline-block; margin-top: 20px;">
+			<el-button type="primary" size="small" @click="settlement()" style="float: left;">{{ $t('shop.checkOut') }}</el-button>
+		</div>
+		<div class="flex data" style="float: right; display: inline-block; line-height: 35px; font-size: 14px; margin-top: 20px; border: 1px solid #dcdfe6; border-radius: 4px; padding: 0 15px;">
+			<div style="margin-right: 2rem; display: inline-block;">{{ $t('shop.productPrice') }}:{{ $t('currency.sign') }} {{ sellPriceSum }}</div>
+			<div style="margin-right: 2rem; display: inline-block;">{{ $t('shop.productBV') }}:{{ $t('currency.sign') }} {{ pricePvSum }}</div>
+			<div style="display: inline-block;">{{ $t('shop.taxAmount') }}:{{ $t('currency.sign') }} {{ taxSum }}</div>
+		</div>
+	</div>
+</div>
+</template>
+
+  <script>
+  import { fetchProductList, fetchProduct } from '@/api/shop'
+  import waves from '@/directive/waves'
+  import { parseTime } from '@/utils'
+	import tool from '@/utils/tool'
+  import Pagination from '@/components/Pagination'
+
+  export default {
+    name: 'standardProducts',
+    components: { Pagination },
+    directives: { waves },
+		filters: {
+			priceFilter(price) {
+				return tool.formatPrice(price)
+			},
+			taxAmountFilter(row) {
+				return tool.calculateTax(row.SELL_PRICE, row.TAX_RATE)
+			},
+			statusFilter(status) {
+				const statusMap = {
+					Unpaid: 'info',
+					Paid: 'success',
+				}
+				return statusMap[status]
+			},
+		},
+    data() {
+      return {
+        tableKey: 0,
+        list: [],
+        total: 0,
+				tableData: [],
+        listLoading: true,
+        listQuery: {
+					categoryType: 1,
+          page: 1,
+          limit: 20,
+        },
+				tool: tool,
+				multipleSelection: [],
+				sellPriceSum: 0.00,
+				pricePvSum: 0.00,
+				taxSum: 0.00,
+				storeNums: [],
+				display: false,
+				currentPage: 1,
+      }
+    },
+    created() {
+			// 商品列表查询
+      this.getList()
+    },
+    methods: {
+			// 商品类别
+      getList() {
+        this.listLoading = true
+				fetchProductList(this.listQuery).then(response => {
+          this.list = response.data.list
+          this.total = parseInt(response.data.totalCount)
+
+					setTimeout(() => {
+						this.listLoading = false
+					}, 1.5 * 1000)
+
+					let settingObj = this.list
+					for (let i in this.list) {
+						this.storeNums[i] = 1
+						settingObj[i].chose_num = 0
+					}
+
+					this.tableData = Object.values(settingObj)
+					let pageList = this.multipleSelection[this.currentPage]
+					this.$nextTick(function () {
+						for (let i in this.tableData) {
+							for( let j in  pageList) {
+								if( pageList[j].ID === this.tableData[i].ID ) {
+									this.$data.storeNums[i] = pageList[j].chose_num
+									this.tableData[i].chose_num = pageList[j].chose_num
+									break
+								}
+							}
+						}
+					})
+        })
+      },
+			// 选择商品计数
+			handleInputNumber(val, row){
+				let pageList = this.multipleSelection[this.currentPage]
+				let selectStatus = false
+				for (let i in pageList) {
+					if( pageList[i].ID === row.ID ) {
+						pageList[i].chose_num = val
+						selectStatus = true
+						break
+					}
+				}
+
+				if (selectStatus) {
+					this.multipleSelection[this.currentPage] = pageList
+					this.handleSureChange()
+				}
+			},
+			// 统计商品
+			handleSureChange() {
+				if (this.multipleSelection.length > 0) {
+					let accumulatorSellPrice = 0, accumulatorPricePv = 0, accumulatorTax = 0
+					this.multipleSelection.forEach(item => {
+						item.forEach(accumulator => { accumulatorSellPrice += accumulator.SELL_PRICE * accumulator.chose_num * accumulator.DISCOUNT / 100; })
+						item.forEach(accumulator => { accumulatorPricePv += Number(accumulator.PRICE_PV) * Number(accumulator.chose_num) * (Number(accumulator.DISCOUNT) / 100); })
+						item.forEach(accumulator => { accumulatorTax += tool.calculateTax(Number(accumulator.SELL_PRICE), Number(accumulator.TAX_RATE), Number(accumulator.chose_num)); })
+					})
+
+					this.sellPriceSum = tool.formatPrice(accumulatorSellPrice)
+					this.pricePvSum = tool.formatPrice(accumulatorPricePv)
+					this.taxSum = tool.formatPrice(accumulatorTax)
+
+					this.display = true
+				} else {
+					this.sellPriceSum = this.pricePvSum = this.taxSum = 0.00
+					this.display = true
+				}
+			},
+			handleSelectionChange(val) {
+				let idx = -1, num
+				for (let i in this.tableData) {
+					for (let v in val) {
+						if (val[v].ID === this.tableData[i].ID) {
+							idx = i
+							num = this.storeNums[idx]
+							val[v]["chose_num"] = num
+							break
+						}
+					}
+				}
+				this.multipleSelection[this.currentPage] = val
+
+				// 计算统计
+				this.handleSureChange()
+			},
+			// 结算商品
+			settlement() {
+
+			}
+    },
+		watch: {
+			// 监听多选按钮,判断结算按钮是否可用
+			multipleSelection: function (modern) {
+				console.log(modern, modern.length)
+				this.$data.display = modern.length > 0
+			},
+		},
+  }
+</script>

+ 229 - 0
src/views/shop/villa-fund-products.vue

@@ -0,0 +1,229 @@
+<template>
+	<div class="app-container">
+		<el-table
+			:key="tableKey"
+			v-loading="listLoading"
+			:data="tableData"
+			border
+			fit
+			highlight-current-row
+			style="width: 100%;"
+			ref="multipleTable"
+			@selection-change="handleSelectionChange"
+		>
+			<el-table-column type="selection" width="70" align="center"></el-table-column>
+			<el-table-column :label="$t('shop.productName')" align="center" prop="GOODS_NAME">
+				<template slot-scope="{row}">
+					<span>{{ row.GOODS_NAME }}</span>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.productPicture')" align="center" min-width="70px" prop="GOODS_NAME">
+				<template slot-scope="{row}">
+					<el-image
+						style="width: 70px; height: 70px"
+						:src="tool.getArImage(row.COVER, '/files/')"
+						:preview-src-list="[tool.getArImage(row.COVER, '/files/')]"
+					>
+					</el-image>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.productPrice')" align="center" prop="SELL_PRICE">
+				<template slot-scope="{row}">
+					<span>{{ row.SELL_PRICE }}</span>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.productBV')" align="center" prop="PRICE_PV">
+				<template slot-scope="{row}">
+					<span>{{ row.PRICE_PV }}</span>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.taxRate')" align="center" prop="TAX_RATE">
+				<template slot-scope="{row}">
+					<span>{{ row.TAX_RATE / 100  }}</span>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.taxAmount')" align="center">
+				<template slot-scope="{row}">
+					<span>{{ row | taxAmountFilter }}</span>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.inventory')" align="center" prop="STORE_NUMS">
+				<template slot-scope="{row}">
+					<span>{{ row.STORE_NUMS }}</span>
+				</template>
+			</el-table-column>
+			<el-table-column :label="$t('shop.inventory')" min-width="90" align="center">
+				<template slot-scope="scope">
+					<el-input-number size="mini" v-model="storeNums[scope.$index]" :min="0" :max="Number(scope.row.STORE_NUMS)" @change="(val)=>{handleInputNumber(val, scope.row)}"></el-input-number>
+				</template>
+			</el-table-column>
+		</el-table>
+
+		<pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
+
+		<div class="white-box-footer" v-show="display" style="margin-top: 15px;">
+			<div class="flex data" style="float: left; display: inline-block; margin-top: 20px;">
+				<el-button type="primary" size="small" @click="settlement()" style="float: left;">{{ $t('shop.checkOut') }}</el-button>
+			</div>
+			<div class="flex data" style="float: right; display: inline-block; line-height: 35px; font-size: 14px; margin-top: 20px; border: 1px solid #dcdfe6; border-radius: 4px; padding: 0 15px;">
+				<div style="margin-right: 2rem; display: inline-block;">{{ $t('shop.productPrice') }}:{{ $t('currency.sign') }} {{ sellPriceSum }}</div>
+				<div style="margin-right: 2rem; display: inline-block;">{{ $t('shop.productBV') }}:{{ $t('currency.sign') }} {{ pricePvSum }}</div>
+				<div style="display: inline-block;">{{ $t('shop.taxAmount') }}:{{ $t('currency.sign') }} {{ taxSum }}</div>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+import { fetchProductList, fetchProduct } from '@/api/shop'
+import waves from '@/directive/waves'
+import { parseTime } from '@/utils'
+import tool from '@/utils/tool'
+import Pagination from '@/components/Pagination'
+
+export default {
+	name: 'villaFundProducts',
+	components: { Pagination },
+	directives: { waves },
+	filters: {
+		priceFilter(price) {
+			return tool.formatPrice(price)
+		},
+		taxAmountFilter(row) {
+			return tool.calculateTax(row.SELL_PRICE, row.TAX_RATE)
+		},
+		statusFilter(status) {
+			const statusMap = {
+				Unpaid: 'info',
+				Paid: 'success',
+			}
+			return statusMap[status]
+		},
+	},
+	data() {
+		return {
+			tableKey: 0,
+			list: [],
+			total: 0,
+			tableData: [],
+			listLoading: true,
+			listQuery: {
+				categoryType: 6,
+				page: 1,
+				limit: 20,
+			},
+			tool: tool,
+			multipleSelection: [],
+			sellPriceSum: 0.00,
+			pricePvSum: 0.00,
+			taxSum: 0.00,
+			storeNums: [],
+			display: false,
+			currentPage: 1,
+		}
+	},
+	created() {
+		// 商品列表查询
+		this.getList()
+	},
+	methods: {
+		// 商品类别
+		getList() {
+			this.listLoading = true
+			fetchProductList(this.listQuery).then(response => {
+				this.list = response.data.list
+				this.total = parseInt(response.data.totalCount)
+
+				setTimeout(() => {
+					this.listLoading = false
+				}, 1.5 * 1000)
+
+				let settingObj = this.list
+				for (let i in this.list) {
+					this.storeNums[i] = 1
+					settingObj[i].chose_num = 0
+				}
+
+				this.tableData = Object.values(settingObj)
+				let pageList = this.multipleSelection[this.currentPage]
+				this.$nextTick(function () {
+					for (let i in this.tableData) {
+						for( let j in  pageList) {
+							if( pageList[j].ID === this.tableData[i].ID ) {
+								this.$data.storeNums[i] = pageList[j].chose_num
+								this.tableData[i].chose_num = pageList[j].chose_num
+								break
+							}
+						}
+					}
+				})
+			})
+		},
+		// 选择商品计数
+		handleInputNumber(val, row){
+			let pageList = this.multipleSelection[this.currentPage]
+			let selectStatus = false
+			for (let i in pageList) {
+				if( pageList[i].ID === row.ID ) {
+					pageList[i].chose_num = val
+					selectStatus = true
+					break
+				}
+			}
+
+			if (selectStatus) {
+				this.multipleSelection[this.currentPage] = pageList
+				this.handleSureChange()
+			}
+		},
+		// 统计商品
+		handleSureChange() {
+			if (this.multipleSelection.length > 0) {
+				let accumulatorSellPrice = 0, accumulatorPricePv = 0, accumulatorTax = 0
+				this.multipleSelection.forEach(item => {
+					item.forEach(accumulator => { accumulatorSellPrice += accumulator.SELL_PRICE * accumulator.chose_num * accumulator.DISCOUNT / 100; })
+					item.forEach(accumulator => { accumulatorPricePv += Number(accumulator.PRICE_PV) * Number(accumulator.chose_num) * (Number(accumulator.DISCOUNT) / 100); })
+					item.forEach(accumulator => { accumulatorTax += tool.calculateTax(Number(accumulator.SELL_PRICE), Number(accumulator.TAX_RATE), Number(accumulator.chose_num)); })
+				})
+
+				this.sellPriceSum = tool.formatPrice(accumulatorSellPrice)
+				this.pricePvSum = tool.formatPrice(accumulatorPricePv)
+				this.taxSum = tool.formatPrice(accumulatorTax)
+
+				this.display = true
+			} else {
+				this.sellPriceSum = this.pricePvSum = this.taxSum = 0.00
+				this.display = true
+			}
+		},
+		handleSelectionChange(val) {
+			let idx = -1, num
+			for (let i in this.tableData) {
+				for (let v in val) {
+					if (val[v].ID === this.tableData[i].ID) {
+						idx = i
+						num = this.storeNums[idx]
+						val[v]["chose_num"] = num
+						break
+					}
+				}
+			}
+			this.multipleSelection[this.currentPage] = val
+
+			// 计算统计
+			this.handleSureChange()
+		},
+		// 结算商品
+		settlement() {
+
+		}
+	},
+	watch: {
+		// 监听多选按钮,判断结算按钮是否可用
+		multipleSelection: function (modern) {
+			console.log(modern, modern.length)
+			this.$data.display = modern.length > 0
+		},
+	},
+}
+</script>

+ 1 - 1
vue.config.js

@@ -6,7 +6,7 @@ function resolve(dir) {
   return path.join(__dirname, dir)
 }
 
-const name = defaultSettings.title || 'vue Element Admin' // page title
+const name = defaultSettings.title || 'Member Management System' // page title
 
 // If your port is set to 80,
 // use administrator privileges to execute the command line.