joway пре 2 година
родитељ
комит
3e66459670
43 измењених фајлова са 5093 додато и 151 уклоњено
  1. 17 0
      .env.development
  2. 4 2
      .env.production
  3. 2 0
      .env.staging
  4. 348 0
      src/api/member.js
  5. 180 0
      src/api/shop.js
  6. 19 0
      src/api/upload.js
  7. 10 0
      src/api/user.js
  8. 232 0
      src/components/ExcelUploader/index.vue
  9. 2 2
      src/components/FilterUser.vue
  10. 157 4
      src/lang/en.js
  11. 150 4
      src/lang/zh.js
  12. 4 4
      src/layout/components/Navbar.vue
  13. 5 0
      src/layout/index.vue
  14. 2 4
      src/permission.js
  15. 48 0
      src/router/index.js
  16. 25 2
      src/router/modules/member.js
  17. 0 7
      src/store/modules/user.js
  18. 23 0
      src/utils/importScript.js
  19. 115 0
      src/utils/region.js
  20. 0 3
      src/views/ad/edit.vue
  21. 0 1
      src/views/ad/list.vue
  22. 2 2
      src/views/config/dec-level-config.vue
  23. 0 1
      src/views/dashboard/admin/index.vue
  24. 0 1
      src/views/log/admin-handle.vue
  25. 0 1
      src/views/log/admin-login.vue
  26. 0 1
      src/views/log/system.vue
  27. 0 1
      src/views/log/user-handle.vue
  28. 0 1
      src/views/log/user-login.vue
  29. 13 3
      src/views/login/index.vue
  30. 108 0
      src/views/login/modify-password.vue
  31. 107 0
      src/views/shop/flow-remain-pv.vue
  32. 309 0
      src/views/shop/goods-add.vue
  33. 514 0
      src/views/shop/index.vue
  34. 165 0
      src/views/shop/order-dec-list.vue
  35. 245 0
      src/views/shop/order-list.vue
  36. 174 0
      src/views/shop/order-shop-list.vue
  37. 113 0
      src/views/shop/remain-pv.vue
  38. 222 0
      src/views/user/dec-level-list.vue
  39. 299 0
      src/views/user/empty-order-operation.vue
  40. 552 107
      src/views/user/member-list.vue
  41. 656 0
      src/views/user/member-network-move.vue
  42. 137 0
      src/views/user/modify-stockist-level.vue
  43. 134 0
      vue.config.js

+ 17 - 0
.env.development

@@ -0,0 +1,17 @@
+# just a flag
+ENV='development'
+
+# api请求地址
+VUE_APP_BASE_API=''
+# 文件下载地址
+VUE_APP_BASE_DO_API='http://local.ng.backend.api.com'
+# CDN文件地址
+VUE_APP_CDN_API='http://172.19.124.45:9970'
+# 页面地址
+VUE_APP_BASE_WEBSITE='http://local.ng.backend.ele.com'
+# 会员端地址
+VUE_APP_FRONTEND_WEBSITE='http://local.ng.frontend.ele.com'
+# PayStack
+VUE_APP_BASE_PAY_STACK_PUBLIC_KEY='pk_test_2eed10135c4a958c5073795b22854ded9d1a6c55'
+# 请求token前缀
+VUE_APP_ACCESS_TOKEN_PREFIX='Bearer '

+ 4 - 2
.env.production

@@ -7,8 +7,10 @@ VUE_APP_BASE_API=''
 VUE_APP_BASE_DO_API='https://ng-frontend-api.elken.com'
 # CDN文件地址
 VUE_APP_CDN_API='http://ng-upload.elken.com'
-# 页面地址
-VUE_APP_BASE_WEBSITE='https://ngds.elken.com'
+# 结算页面地址
+VUE_APP_BASE_WEBSITE='https://ngmanager.elken.com'
+# 会员页面地址
+VUE_APP_FRONTEND_WEBSITE='https://ngds.elken.com'
 # PayStack支付key
 VUE_APP_BASE_PAY_STACK_PUBLIC_KEY='pk_live_fae524f9d073d877beeb661fd825a37a9bc91f0a'
 # 请求token前缀

+ 2 - 0
.env.staging

@@ -11,6 +11,8 @@ VUE_APP_BASE_DO_API='http://16.163.228.151:8039'
 VUE_APP_CDN_API='http://16.163.228.151:8041'
 # 页面地址
 VUE_APP_BASE_WEBSITE='http://16.163.228.151:8035'
+# 会员页面地址
+VUE_APP_FRONTEND_WEBSITE='http://16.163.228.151:8037'
 # PayStack支付key
 VUE_APP_BASE_PAY_STACK_PUBLIC_KEY='pk_test_2eed10135c4a958c5073795b22854ded9d1a6c55'
 # 请求token前缀

+ 348 - 0
src/api/member.js

@@ -11,3 +11,351 @@ export function fetchMemberList(data) {
     params: data
   })
 }
+
+/**
+ * 会员列表导出
+ * @returns {*}
+ */
+export function fetchMemberExport(data) {
+  return request({
+    url: '/v1/user/index-export',
+    method: 'get',
+    params: data
+  })
+}
+
+/**
+ * 会员列表导出
+ * @returns {*}
+ */
+export function fetchProfileGet(data) {
+  return request({
+    url: '/v1/user/profile-get',
+    method: 'get',
+    params: data
+  })
+}
+
+/**
+ * 设为报单中心
+ * @param data
+ * @returns {*}
+ */
+export function updateSetAsStockist(data) {
+  return request({
+    url: '/v1/user/is-dec',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 显示报单网络图谱
+ * @param data
+ * @returns {*}
+ */
+export function updateSetChartDisplay(data) {
+  return request({
+    url: '/v1/user/is-atlas',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 显示充值功能
+ * @param data
+ * @returns {*}
+ */
+export function updateSetRechargeDisplay(data) {
+  return request({
+    url: '/v1/user/is-recharge',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 设为报单中心
+ * @param data
+ * @returns {*}
+ */
+export function updateSetActive(data) {
+  return request({
+    url: '/v1/user/modify-status',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 设为报单中心
+ * @param data
+ * @returns {*}
+ */
+export function updateModifyPassword(data) {
+  return request({
+    url: '/v1/user/modify-password',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 设为报单中心
+ * @param data
+ * @returns {*}
+ */
+export function updateModifyProfile(data) {
+  return request({
+    url: '/v1/user/modify-profile',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 设为报单中心
+ * @param data
+ * @returns {*}
+ */
+export function updateSetLock(data) {
+  return request({
+    url: '/v1/user/modify-status',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 设为报单中心
+ * @param data
+ * @returns {*}
+ */
+export function updateSetModifyPassword(data) {
+  return request({
+    url: '/v1/user/is-modify-password-status',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 查询会员信息
+ * @returns {*}
+ */
+export function fetchMemberFullInfo(data) {
+  return request({
+    url: '/v1/user/full-info',
+    method: 'get',
+    params: data
+  })
+}
+
+/**
+ * 查询会员信息
+ * @returns {*}
+ */
+export function fetchCloseLoginGet() {
+  return request({
+    url: '/v1/user/close-login-get',
+    method: 'get',
+  })
+}
+
+/**
+ * 查询会员信息
+ * @returns {*}
+ */
+export function fetchCloseDecGet() {
+  return request({
+    url: '/v1/user/close-dec-get',
+    method: 'get',
+  })
+}
+
+/**
+ * 查询会员信息
+ * @returns {*}
+ */
+export function fetchCloseDec() {
+  return request({
+    url: '/v1/user/close-dec',
+    method: 'get',
+  })
+}
+
+/**
+ * 修改报单中心级别
+ * @param data
+ * @returns {*}
+ */
+export function updateUserStockistLevel(data) {
+  return request({
+    url: '/v1/user/change-user-dec-role',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 查询会员等级调整信息
+ * @returns {*}
+ */
+export function fetchEntryLevelList(data) {
+  return request({
+    url: '/v1/user/dec-level-list',
+    method: 'get',
+    params: data
+  })
+}
+
+/**
+ * 修改会员报单级别
+ * @param data
+ * @returns {*}
+ */
+export function updateUserEntryLevel(data) {
+  return request({
+    url: '/v1/user/change-user-dec-level',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 查询移网类型
+ * @returns {*}
+ */
+export function fetchNetworkType(data) {
+  return request({
+    url: '/v1/user/move-net-type',
+    method: 'get',
+    params: data
+  })
+}
+
+/**
+ * 查询移网数据
+ * @returns {*}
+ */
+export function fetchNetworkMoveList(data) {
+  return request({
+    url: '/v1/user/move',
+    method: 'get',
+    params: data
+  })
+}
+
+/**
+ * 移网导出
+ * @returns {*}
+ */
+export function fetchNetworkMoveExport(data) {
+  return request({
+    url: '/v1/user/move-export',
+    method: 'get',
+    params: data
+  })
+}
+
+/**
+ * 移网审核通过
+ * @param data
+ * @returns {*}
+ */
+export function updateNetworkMovePass(data) {
+  return request({
+    url: '/v1/user/move-pass',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 移网信息
+ * @returns {*}
+ */
+export function fetchNetworkMoveGet(data) {
+  return request({
+    url: '/v1/user/move-get',
+    method: 'get',
+    params: data
+  })
+}
+
+/**
+ * 移网审核编辑
+ * @param data
+ * @returns {*}
+ */
+export function updateNetworkMoveEdit(data) {
+  return request({
+    url: '/v1/user/move-edit',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 移网审核
+ * @param data
+ * @returns {*}
+ */
+export function updateNetworkMoveAudit(data) {
+  return request({
+    url: '/v1/user/move-audit',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 移网删除
+ * @param data
+ * @returns {*}
+ */
+export function updateNetworkMoveDelete(data) {
+  return request({
+    url: '/v1/user/move-delete',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 发起移网
+ * @param data
+ * @returns {*}
+ */
+export function updateNetworkMoveApply(data) {
+  return request({
+    url: '/v1/user/move-add',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 空单操作查询
+ * @returns {*}
+ */
+export function fetchUserAdd() {
+  return request({
+    url: '/v1/user/user-add',
+    method: 'get',
+  })
+}
+
+/**
+ * 空单添加会员
+ * @param data
+ * @returns {*}
+ */
+export function updateUserAdd(data) {
+  return request({
+    url: '/v1/user/user-add',
+    method: 'post',
+    data
+  })
+}

+ 180 - 0
src/api/shop.js

@@ -0,0 +1,180 @@
+import request from '@/utils/request'
+
+// 商品列表
+export function shopList(query) {
+    return request({
+      url: '/v1/shop/index',
+      method: 'get',
+      data: query,
+      params: query
+    })
+}
+
+// 导出
+export function goodsListExport(query) {
+    return request({
+      url: '/v1/shop/goods-list-export',
+      method: 'get',
+      data: query,
+      params: query
+    })
+}
+
+// 商品上下架
+export function updateGoodsStatus(query) {
+    return request({
+      url: '/v1/shop/goods-status',
+      method: 'post',
+      data: query
+    })
+}
+
+// 删除商品
+export function goodsDelete(query) {
+    return request({
+      url: '/v1/shop/goods-delete',
+      method: 'post',
+      data: query
+    })
+}
+
+// 编辑商品-获取详情
+export function getGoodsDetail(query) {
+    return request({
+      url: '/v1/shop/goods-edit',
+      method: 'get',
+      data: query,
+      params: query
+    })
+}
+
+// 提交表单,编辑商品信息
+export function editGoodsData(query) {
+  return request({
+    url: '/v1/shop/goods-edit',
+    method: 'post',
+    data: query
+  })
+}
+
+// 添加商品,获取参数配置
+export function getAddGoodsConfig(query) {
+  return request({
+    url: '/v1/shop/goods-add',
+    method: 'get',
+    data: query,
+    params: query
+  })
+}
+
+// 添加商品,获取上传token
+export function getUploadToken(query) {
+  return request({
+    url: '/v1/shop/upload',
+    method: 'get',
+    data: query,
+    params: query
+  })
+}
+
+// 添加商品,提交到后台
+export function addGoods(query) {
+  return request({
+    url: '/v1/shop/goods-add',
+    method: 'post',
+    data: query
+  })
+}
+
+//外部商城报单列表
+export function orderDecList(query) {
+  return request({
+    url: '/v1/shop/order-dec-list',
+    method: 'get',
+    data: query,
+    params: query
+  })
+}
+
+// 外部商城订单列表
+export function orderShopList(query) {
+  return request({
+    url: '/v1/shop/order-shop-list',
+    method: 'get',
+    data: query,
+    params: query
+  })
+}
+
+// 剩余bv流水列表
+export function flowRemainPvList(query) {
+  return request({
+    url: '/v1/shop/flow-remain-pv',
+    method: 'get',
+    data: query,
+    params: query
+  })
+}
+
+//shop/remain-pv 列表
+export function remainPv(query) {
+  return request({
+    url: '/v1/shop/remain-pv',
+    method: 'get',
+    data: query,
+    params: query
+  })
+}
+
+// 订单列表
+export function orderList(query) {
+  return request({
+    url: '/v1/shop/order-list',
+    method: 'get',
+    data: query,
+    params: query
+  })
+}
+
+// 订单列表导出
+export function orderListExport(query) {
+  return request({
+    url: '/v1/shop/order-list-export',
+    method: 'get',
+    data: query,
+    params: query
+  })
+}
+
+// 订单导出pdf
+export function orderListExportPdf(query) {
+  return request({
+    url: '/v1/shop/order-list-export-pdf/'+query,
+    method: 'get',
+    data: query,
+    params: query
+  })
+}
+
+// 删除订单
+export function deleteOrder(query) {
+  return request({
+    url: '/v1/shop/delete-order',
+    method: 'post',
+    data: query
+  })
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 19 - 0
src/api/upload.js

@@ -14,3 +14,22 @@ export function upload(data) {
     data
   })
 }
+
+
+// 上传excel,报单订单——分页导入excel文件到待导入数据的表中
+export function apiImportOrderDecToExcelTable(path, data) {
+  return request({
+    url: '/v1/'+path,
+    method: 'post',
+    data
+  })
+}
+
+// 上传execl,报单订单导入完成标记
+export function apiImportOrderDec(path, data) {
+  return request({
+    url: '/v1/'+path,
+    method: 'post',
+    data
+  })
+}

+ 10 - 0
src/api/user.js

@@ -39,3 +39,13 @@ export function getUserInfo(token) {
     params: { token }
   })
 }
+
+// 未登录修改密码
+export function noLoginModifyPassword(data) {
+  return request({
+    url: '/v1/oauth/no-login-modify-password',
+    method: 'post',
+    data
+  })
+}
+

+ 232 - 0
src/components/ExcelUploader/index.vue

@@ -0,0 +1,232 @@
+<template>
+    <div class="leo-excel-uploader">
+      <el-upload
+          class="excel-uploader-box"
+          v-show="uploaderShow"
+          :action="uploaderRequestUrl"
+          name="file"
+          :headers="uploaderHeaders"
+          :data="uploaderFormData"
+          :show-file-list="false"
+          :before-upload="uploaderHandleBefore"
+          :on-success="uploaderHandleSuccess"
+          :disabled="uploaderDisabled"
+          v-loading="uploaderLoading"
+      >
+        <el-button type="primary">{{uploadBtnTitle}}</el-button>
+      </el-upload>
+      <el-dialog
+          title="进度提示"
+          :visible.sync="dialogVisible"
+          :close-on-click-modal="false"
+          :close-on-press-escape="false"
+          :show-close="false"
+          width="30%">
+        <el-progress :percentage="importPercent"></el-progress>
+      </el-dialog>
+    </div>
+  </template>
+  
+  <script>
+    import { getToken, apiImportOrderDecToExcelTable, apiImportOrderDec } from '@/api/upload'
+    export default {
+      name: 'LeoExcelUploader',
+      props: {
+        uploadBtnTitle: {
+          type: String,
+          default: 'Upload',
+        },
+        requestUploadRoute: {
+          type: String,
+          required: true,
+        },
+        requestImportToExcelTableRoute: {
+          type: String,
+          required: true,
+        },
+        requestImportExcelTableToDataRoute: {
+          type: String,
+          required: true,
+        },
+        importRowCount: {
+          required: true,
+        },
+        uploaderSuccessCanChange: {
+          type: Boolean,
+          default: true,
+        },
+        otherParams: {
+          type: Object,
+          default: {},
+        },
+        finishCallbackFunc: {
+          type:Function,
+          default:null,
+        },
+        excelOption: {
+          type: String,
+        },
+      },
+      data() {
+        return {
+          uploaderShow: true,
+          uploaderLoading: false,
+          uploaderFormData: {
+            'uploadToken': '',
+            'excelOption': this.excelOption,
+          },
+          uploaderRequestUrl: `${this.requestUploadRoute}`,
+          importRequestUrl: `${this.requestImportRoute}`,
+          uploaderHeaders: {
+            'Device-Type': 'pc',
+            'Suppress-Response-Code': '1',
+            'Authorization': '',
+          },
+          uploaderDisabled: false,
+          successImageUrl: null,
+          dialogVisible: false,
+          importPercent: 0,
+        }
+      },
+      methods: {
+        uploaderHandleBefore() {
+          if (!this.importRowCount || this.importRowCount <= 1) {
+            this.$message({
+              message: '请填写文件总行数,并且总行数大于1',
+              type: 'warning'
+            })
+            return false;
+          }
+          const auth_token = localStorage.accessToken
+          this.uploaderHeaders.Authorization = 'Bearer  ' + auth_token
+          return new Promise((resolve, reject) => {
+            getToken().then(response => {
+              this.uploaderFormData.uploadToken = response.data
+              this.uploaderLoading = true
+              resolve(true)
+            }).catch(() => {
+              this.uploaderLoading = true
+              this.$message({
+                message: err,
+                type: 'error'
+              })
+              reject(false)
+            })
+          })
+        },
+        uploaderHandleSuccess(response, file) {
+          if (response.success) {
+            this.$message({
+              message: 'Successful',
+              type: 'success'
+            })
+            // 显示进度框
+            this.dialogVisible = true
+            this.importPercent = 0
+            // 导入excel
+            this.importToExcelTable(response.data.excelImportId, 1, 1000)
+  
+            if (!this.uploaderSuccessCanChange) {
+              this.uploaderShow = false
+              this.uploaderDisabled = true
+              this.uploaderLoading = false
+            }
+            this.$emit('on-success', response.data)
+          } else {
+            this.$message({
+              message: response.data,
+              type: 'warning'
+            })
+            this.uploaderLoading = false
+          }
+        },
+        importToExcelTable(excelImportId, startRow = 0, limit = 1000) {
+          let _this = this
+          let importRowCount = Number.parseInt(_this.importRowCount)
+          let postParams = {
+            excelImportId: excelImportId,
+            rowCount: importRowCount,
+            startRow: startRow,
+            limit: limit > importRowCount ? importRowCount : limit,
+          }
+          for (let key in _this.otherParams ) {
+            postParams[key] = _this.otherParams[key]
+          }
+
+          apiImportOrderDecToExcelTable(_this.requestImportToExcelTableRoute, postParams).then(response => {
+            if (!response.data.finish) {
+              // 完成一次的进度占50%的多少
+              let percent = parseInt(startRow / importRowCount * 50)
+              if (_this.importPercent + percent >= 50) {
+                _this.importPercent = 50
+              } else {
+                if (_this.importPercent + percent >= 100) {
+                  _this.importPercent = 100
+                } else {
+                  _this.importPercent += percent
+                }
+              }
+              _this.importToExcelTable(excelImportId, startRow + limit, limit)
+            } else {
+              _this.importPercent = 50
+              _this.importExcelTableToData(excelImportId, 0, 2)
+            }
+          }).catch(err => {
+            _this.importPercent = 0
+            _this.dialogVisible = false
+            _this.uploaderLoading = false
+            this.$message({
+              message: err,
+              type: 'error'
+            })
+          })
+        },
+        importExcelTableToData(excelImportId, offset = 0, limit = 100) {
+          let _this = this
+          let postParams = {
+            excelImportId: excelImportId,
+            offset: offset,
+            limit: limit,
+          }
+          for (let key in this.otherParams ) {
+            postParams[key] = this.otherParams[key]
+          }
+          apiImportOrderDec(_this.requestImportExcelTableToDataRoute, postParams).then(response => {
+            if (!response.data.finish) {
+              let percent = Number.parseInt(offset / _this.importRowCount * 50)
+              if (_this.importPercent + percent >= 100) {
+                _this.importPercent = 100
+              } else {
+                _this.importPercent += percent
+              }
+              _this.importExcelTableToData(excelImportId, offset + limit, limit)
+            } else {
+              _this.importPercent = 100
+              _this.dialogVisible = false
+              _this.uploaderLoading = false
+              if( _this.finishCallbackFunc !== null ) {
+                _this.finishCallbackFunc()
+              }
+              _this.$message({
+                message: '导入完成',
+                type: 'success'
+              })
+            }
+          }).catch(err=>{
+            _this.importPercent = 0
+            _this.dialogVisible = false
+            _this.uploaderLoading = false
+            this.$message({
+              message: err,
+              type: 'error'
+            })
+          })
+        }
+      }
+    }
+  </script>
+  
+  <style scoped>
+  
+  </style>
+  

+ 2 - 2
src/components/FilterUser.vue

@@ -82,9 +82,9 @@
         <el-option v-for="(item,key) in filterRelations" :key="key" :label="item" :value="key" />
       </el-select>
       <el-button class="filter-item" icon="el-icon-plus" @click="handleOptionPlus" />
-      <el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilterUser">{{ filterBtnName }}</el-button>
+      <el-button class="filter-item" type="primary" @click="handleFilterUser">{{ filterBtnName }}</el-button>
       <el-button class="filter-item" type="" @click="handleFilterClear">{{ $t('common.reset') }}</el-button>
-      <!-- <el-button class="down-button" type="text"><i class="el-icon-arrow-down" /></el-button> -->
+<!--      <el-button class="down-button" type="text"><i class="el-icon-arrow-down" /></el-button>-->
     </div>
     <div v-show="filterSelected.length > 0" class="filter-selected">
       <el-tag

+ 157 - 4
src/lang/en.js

@@ -70,14 +70,21 @@ export default {
     logOut: 'Log Out',
     profile: 'Profile',
     theme: 'Theme',
-    size: 'Global Size'
+    size: 'Global Size',
+    resetPassword: 'Reset password'
   },
   login: {
     title: 'LOGIN',
     logIn: 'Login',
     username: 'UserName',
     password: 'Password',
-    verifyCode: 'Verification Code'
+    verifyCode: 'Verification Code',
+    resetPassword: 'Reset password',
+    adminModifyPasswd: 'Changing the Password of Administrator',
+    adminCode: 'Administrator Code',
+    originLoginPassword: 'Original login password',
+    newLoginPassword: 'New login password',
+    confirmLoginPassword: 'Confirm login password'
   },
   ad: {
     ad: 'Ad',
@@ -308,8 +315,10 @@ export default {
     relation: '关系',
     reset: '重置',
     exportExcel: 'Export Excel',
+    exportPDF: 'Export PDF',
     desc: '描述',
     upload: 'Upload',
+    modifyData: 'Modifying data',
     hide: 'Hide',
     unhide: 'Unhide',
     selectData: 'Select Data',
@@ -322,7 +331,7 @@ export default {
   },
 
   filter: {
-    memberSelect: '会员筛选',
+    memberSelect: 'Select',
     memberNumber: '会员编号',
     name: '姓名',
     idNumber: '证件号码',
@@ -423,8 +432,115 @@ export default {
   },
 
   // 会员
-  user: {
+  member: {
+    memberCode: 'Member Code',
+    memberName: 'Member Name',
+    currentLevel: 'Current Level',
+    stockistLevel: 'Stockist Level',
+    entryLevel: 'Entry Level',
+    pleaseSelectStockistLevel: 'Please Select The Stockist Level',
+    remark: 'Remark',
+    modifyEntryLevelHits: 'Do you want to modify the current member entry level?',
+    modifyMemberLevel: 'Modify member level',
+    selectEntryLevelHint: 'Please Select The Entry Level',
+    modifyMemberEntryLevelHits: 'Do you want to modify the current member level?',
+    all: 'All',
+    reviewed: 'To be reviewed',
+    approved: 'Approved',
+    rejected: 'Rejected',
+    selectedData: 'Selected data',
+    deleteData: 'Delete data',
+    batchesDelete: 'Delete in batches',
+    applyNetworkMove: 'New network transfer application',
+    exportExcel: 'Export Excel',
+    exportExcelHint: 'Are you sure you want to export the current data?',
+    passingAudit: 'Passing Audit',
+    modifyingData: 'Modifying data',
+    selectedNonData: 'Please select the record to operate',
+    passAuditNote: 'Are you sure you want to pass the audit? note:',
+    rejectAuditNote: 'Are you sure you want to reject the approval? note:',
+    operationInProcess: 'Operation in progress, please wait',
+    deleteHint: 'Are you sure to delete the selected data?',
+    applyNetworkTransfer: 'Apply for moving network',
+    modifyNetworkTransfer: 'Modify network transfer information',
+    reviewNetworkTransfer: 'Review network transfer information',
+    networkTransferType: 'Network transfer type',
+    selectNetworkTransferType: 'Please select a network transfer type',
+    mobileMemberCode: 'Mobile member code',
+    mobileMemberName: 'Mobile member name',
+    originalSuperiorNo: 'Original superior No',
+    originalSuperiorName: 'Original superior name',
+    moveToPlacementMemberCode: 'Move to placement member code',
+    moveToPlacementMemberName: 'Move to placement member name',
+    originalDeveloperNo: 'Original developer No',
+    nameOfOriginalDeveloper: 'Name of original developer',
+    moveToSponsorMemberCode: 'Move to sponsor member code',
+    moveToSponsorMemberName: 'Move to sponsor member name',
+    moveToLocation: 'Move to location',
+    oneMarket: 'I. Market',
+    twoMarket: 'II. Market',
+    adopted: 'Adopted',
+    stockistOrNot: 'Stockist or not',
+    accountInformation: 'Account Information',
+    networkInformation: 'Network Information',
+    otherInformation: 'Other Information',
+    bankInformation: 'Bank Information',
+    stockistNo: 'Stockist No',
+    autoDetectMember: 'After entering the number, click the blank space to detect the member name of the number',
+    contactPerson: 'Contact Person',
+    resettlementLocation: 'Resettlement Location',
+    left: 'Left',
+    right: 'Right',
+    sponsor: 'Sponsor',
+    personalData: 'Personal Data',
+    phoneNumber: 'Phone Number',
+    bankName: 'Bank Name',
+    selectBankDeposit: 'Please select the Bank of deposit',
+    subBankName: 'Account opening sub branch',
+    bankAccount: 'Bank Account',
+    bankRegion: 'Bank Region',
+    addManually: 'Add manually',
+    quickLogon: 'Quick Logon',
+    changePassword: 'Change Password',
+    modifyPersonalData: 'Modify personal data',
+    statusActivation: 'Status Activation',
+    statusLock: 'Status Lock',
+    openPasswordModification: 'Open password modification',
+    turnOffPasswordModification: 'Turn off password modification',
+    stockistManagement: 'Stockist Management',
+    setAsStockist: 'Set as Stockist',
+    cancelStockist: 'Cancel Stockist',
+    chartManagement: 'Chart Management',
+    displayChart: 'Display Chart',
+    hiddenChart: 'Hidden Chart',
+    rechargeManagement: 'Recharge Management',
+    displayRecharge: 'Display Recharge',
+    hideRecharge: 'Display Recharge',
+    type: 'Type',
+    selectType: 'Please select a type',
+    password: 'Password',
+    identityNo: 'Identity No.',
+    selectBankName: 'Please select a bank name',
+    bankAddress: 'Bank Address',
+
+    loginManagement: 'Login Management',
+    entryManage: 'Manage entry',
+    loginPassword: 'Login Password',
+    paymentPassword: 'Payment Password',
+    selectMemberData: 'Please check the member to be operated',
+    sureWant: 'Are you sure you want to',
+    byDesignatedMember: 'By designated member',
+    expandNetworkBy: 'Expand network by',
+    byPlacementNetwork: 'By placement network',
+    byMembershipSystem: 'By membership system',
+    byProvinceAndRegion: 'By province and region',
+    exportDataHint: 'Are you sure you want to export the current data?'
+  },
 
+  // 网络
+  network: {
+    placementNetwork: 'Placement Network',
+    sponsorNetwork: 'Sponsor Network'
   },
 
   // 配置
@@ -581,6 +697,43 @@ export default {
     placementNetworkList: 'Placement network list'
   },
 
+  // 商品管理
+  shop: {
+    onSale: 'On sale',
+    soldOut: 'Sold out',
+    addProduct: 'Add Product',
+    editProducts: 'Edit Products',
+    productName: 'Product Name',
+    memberDiscount: 'Member discount',
+    productType: 'Product type',
+    bvSplit: 'BV split',
+    productCategory: 'Product Category',
+    productCode: 'Product Code',
+    unit: 'Unit',
+    taxRate: 'Tax Rate',
+    uSPrice: 'US Price($)',
+    salesPrice: 'Sales Price(₦)',
+    marketPrice: 'Market Price(₦)',
+    priceBV: 'Price BV',
+    inventory: 'Inventory',
+    productDetails: 'Product details',
+    enterContentNotice: 'Please enter the content',
+    order: 'Order',
+    uploadImages: 'Upload Images',
+    orderImport: 'Order import',
+    currentImportOrderDate: 'Current import order date',
+    selectDate: 'Select date',
+    currentImportOrderPeriods: 'Current import order periods',
+    totalRowsExcel: 'Total rows of Excel file',
+    deliverGoods: 'deliver goods',
+    deleteOrder: 'Delete order',
+    courierCompany: 'Courier Services Company',
+    courierNumber: 'courier number',
+    selectOrderExportNotice: 'Please select an order to export',
+    pdfOnlyOneOrderExported: 'Only one order can be exported at a time',
+    sureDeleteOrder: '确定要删除订单吗?订单编号:'
+  },
+
   // 管理员管理
   Administrator: {
     role: '角色',

+ 150 - 4
src/lang/zh.js

@@ -70,14 +70,20 @@ export default {
     logOut: '退出登录',
     profile: '个人中心',
     theme: '换肤',
-    size: '布局大小'
+    size: '布局大小',
+    resetPassword: '重置密码'
   },
   login: {
     title: '系统登录',
     logIn: '登录',
     username: '账号',
     password: '密码',
-    verifyCode: '验证码'
+    verifyCode: '验证码',
+    adminModifyPasswd: '管理员密码修改',
+    adminCode: '用户编号',
+    originLoginPassword: '原登录密码',
+    newLoginPassword: '新登录密码',
+    confirmLoginPassword: '确认新密码'
   },
   ad: {
     ad: '广告名称',
@@ -311,6 +317,9 @@ export default {
     reset: '重置',
     desc: '描述',
     exportExcel: '导出Excel',
+    exportPDF: '导出PDF',
+    upload: '上传',
+    modifyData: '正在修改数据',
     upload: '上传',
     hide: '展示',
     unhide: '不展示',
@@ -324,7 +333,7 @@ export default {
   },
 
   filter: {
-    memberSelect: '会员筛选',
+    memberSelect: '筛选',
     memberNumber: '会员编号',
     name: '姓名',
     idNumber: '证件号码',
@@ -426,8 +435,108 @@ export default {
   },
 
   // 会员
-  user: {
+  member: {
+    memberCode: '会员编号',
+    memberName: '会员名字',
+    currentLevel: '当前级别',
+    stockistLevel: '报单中心级别',
+    entryLevel: '报单级别',
+    pleaseSelectStockistLevel: '请选择报单中心级别',
+    remark: '备注',
+    modifyEntryLevelHits: '是否要修改当前会员报单级别?',
+    modifyMemberLevel: '修改会员级别',
+    selectEntryLevelHint: '请选择报单级别',
+    modifyMemberEntryLevelHits: '是否要修改当前会员级别',
+    all: '全部',
+    reviewed: '待审核',
+    approved: '审核通过',
+    rejected: '审核拒绝',
+    selectedData: '所选数据',
+    batchesDelete: '批量删除',
+    applyNetworkMove: '新建移网申请',
+    exportExcel: '表格导出',
+    exportExcelHint: '确定导出选中的数据?',
+    passingAudit: '审核中',
+    modifyingData: '正在修改数据',
+    selectedNonData: '请选择要操作的记录',
+    passAuditNote: '确定要通过审核?备注:',
+    rejectAuditNote: '确定要拒绝审核?备注:',
+    operationInProcess: '正在操作,请稍后',
+    deleteHint: '确定删除选定的数据',
+    applyNetworkTransfer: '发起移网信息',
+    modifyNetworkTransfer: '修改移网信息',
+    reviewNetworkTransfer: '审核移网信息',
+    networkTransferType: '移网类型',
+    selectNetworkTransferType: '请选择移网类型',
+    mobileMemberCode: '移动会员编号',
+    mobileMemberName: '移动会员姓名',
+    originalSuperiorNo: '原上级编号',
+    originalSuperiorName: '原上级姓名',
+    moveToPlacementMemberCode: '移动到节点会员编号',
+    moveToPlacementMemberName: '移动到节点会员姓名',
+    originalDeveloperNo: '原开拓人编号',
+    nameOfOriginalDeveloper: '原开拓人姓名',
+    moveToSponsorMemberCode: '移动到开拓会员编号',
+    moveToSponsorMemberName: '移动到开拓会员姓名',
+    moveToLocation: '移动到区位',
+    oneMarket: '一市场',
+    twoMarket: '二市场',
+    adopted: '通过',
+    stockistOrNot: '是否报单中心',
+    accountInformation: '账号信息',
+    networkInformation: '网络信息',
+    otherInformation: '其他信息',
+    bankInformation: '银行信息',
+    stockistNo: '报单中心编号',
+    autoDetectMember: '输入编号后点击空白处,可检测该编号的会员姓名',
+    contactPerson: '接点人',
+    resettlementLocation: '安置区位',
+    left: '左区',
+    right: '中区',
+    sponsor: '开拓人',
+    personalData: '个人资料',
+    phoneNumber: '手机号',
+    bankName: '开户行',
+    selectBankDeposit: '请选择开户行',
+    subBankName: '开户支行',
+    bankAccount: '银行账号',
+    bankRegion: '银行所在地区',
+    addManually: '手动添加',
+    quickLogon: '快速登录',
+    changePassword: '修改密码',
+    modifyPersonalData: '修改个人资料',
+    statusActivation: '状态激活',
+    statusLock: '状态锁定',
+    openPasswordModification: '开启密码修改',
+    turnOffPasswordModification: '关闭密码修改',
+    stockistManagement: '报单中心管理',
+    setAsStockist: '设为报单中心',
+    cancelStockist: '取消报单中心',
+    chartManagement: '图谱管理',
+    displayChart: '显示图谱',
+    hiddenChart: '隐藏图谱',
+    rechargeManagement: '充值管理',
+    displayRecharge: '显示充值',
+    hideRecharge: '隐藏充值',
+    type: '类型',
+    selectType: '请选择类型',
+    password: '密码',
+    identityNo: '身份证号',
+    selectBankName: '请选择银行',
+    bankAddress: '银行地址',
+    loginManagement: '登录管理',
+    entryManage: '管理报单',
+    loginPassword: '登录密码',
+    paymentPassword: '支付密码',
+    selectMemberData: '请勾选要操作的会员',
+    sureWant: '确定要对所选会员',
+    exportDataHint: '确定要导出所选数据?'
+  },
 
+  // 网络
+  network: {
+    placementNetwork: '安置网络',
+    sponsorNetwork: '推荐网路'
   },
 
   // 配置
@@ -584,6 +693,43 @@ export default {
     placementNetworkList: '安置网络列表'
   },
 
+  // 商品管理
+  shop: {
+    onSale: '商品上架',
+    soldOut: '商品下架',
+    addProduct: '商品添加',
+    editProducts: '修改商品',
+    productName: '商品名称',
+    memberDiscount: '会员折扣',
+    productType: '商品类型',
+    bvSplit: 'BV 分期',
+    productCategory: '商品分类',
+    productCode: '商品编号',
+    unit: '单位',
+    taxRate: '税率',
+    uSPrice: '美元价格($)',
+    salesPrice: '销售价格(₦)',
+    marketPrice: '市场价格(₦)',
+    priceBV: '价格BV',
+    inventory: '库存',
+    productDetails: '商品详情',
+    enterContentNotice: '请输入内容',
+    order: '排序',
+    uploadImages: '上传图片',
+    orderImport: '订单导入',
+    currentImportOrderDate: '当前导入订单日期',
+    selectDate: '选择日期',
+    currentImportOrderPeriods: '当前导入订单期数',
+    totalRowsExcel: 'Excel 文件总行数',
+    deliverGoods: '发货',
+    deleteOrder: '删除订单',
+    courierCompany: '快递公司',
+    courierNumber: '快递单号',
+    selectOrderExportNotice: '请选择一条订单导出',
+    pdfOnlyOneOrderExported: '每次只能导出一条订单',
+    sureDeleteOrder: '确定要删除订单吗?订单编号:'
+  },
+
   // 管理员管理
   Administrator: {
     role: '角色',

+ 4 - 4
src/layout/components/Navbar.vue

@@ -26,14 +26,14 @@
           <i class="el-icon-caret-bottom" />
         </div>
         <el-dropdown-menu slot="dropdown">
-          <router-link to="/profile/index">
+          <router-link to="/dashboard/index">
             <el-dropdown-item>
-              {{ $t('navbar.profile') }}
+              {{ $t('navbar.dashboard') }}
             </el-dropdown-item>
           </router-link>
-          <router-link to="/dashboard/index">
+          <router-link to="/admin/change-password">
             <el-dropdown-item>
-              {{ $t('navbar.dashboard') }}
+              {{ $t('navbar.resetPassword') }}
             </el-dropdown-item>
           </router-link>
 <!--          <a target="_blank" href="https://github.com/PanJiaChen/vue-element-admin/">-->

+ 5 - 0
src/layout/index.vue

@@ -20,9 +20,14 @@ import RightPanel from '@/components/RightPanel'
 import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
 import ResizeMixin from './mixin/ResizeHandler'
 import { mapState } from 'vuex'
+import initRegion from "@/utils/region"
 
 export default {
   name: 'Layout',
+	beforeCreate() {
+		// 获取地区信息
+		initRegion(this)
+	},
   components: {
     AppMain,
     Navbar,

+ 2 - 4
src/permission.js

@@ -7,7 +7,7 @@ import usersInfo from '@/utils/usersInfo'
 
 NProgress.configure({ showSpinner: false }) // NProgress Configuration
 
-const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist
+const whiteList = ['/login', '/auth-redirect', '/modify-password'] // no redirect whitelist
 
 router.beforeEach(async(to, from, next) => {
   // start progress bar
@@ -18,7 +18,6 @@ router.beforeEach(async(to, from, next) => {
 
   // determine whether the user has logged in
   const hasToken = usersInfo.hasLogin()
-
   if (hasToken) {
     if (to.path === '/login') {
       // if is logged in, redirect to the home page
@@ -52,8 +51,7 @@ router.beforeEach(async(to, from, next) => {
     }
   } else {
     /* has no token*/
-
-    if (whiteList.indexOf(to.path) !== -1) {
+    if ((whiteList.indexOf(to.path) !== -1) || (to.path.indexOf('/modify-password/') !== -1)) {
       // in the free login whitelist, go directly
       next()
     } else {

+ 48 - 0
src/router/index.js

@@ -147,6 +147,54 @@ export const constantRoutes = [
       },
     ]
   },
+  {
+    path: '/shop',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: '/shop/index', // 商品列表
+        component: () => import('@/views/shop/index'),
+        name: 'shop_index',
+      },
+      {
+        path: '/shop/goods-add', // 商品添加
+        component: () => import('@/views/shop/goods-add'),
+        name: 'shop_goods-add',
+      },
+      {
+        path: '/shop/order-dec-list', // 外部商城报单列表
+        component: () => import('@/views/shop/order-dec-list'),
+        name: 'shop_order_dec-list',
+      },
+      {
+        path: '/shop/order-shop-list', // 外部商城订单列表
+        component: () => import('@/views/shop/order-shop-list'),
+        name: 'shop_order_shop-list',
+      },
+      {
+        path: '/shop/flow-remain-pv', // 剩余BV流水
+        component: () => import('@/views/shop/flow-remain-pv'),
+        name: 'shop_flow-remain-pv',
+      },
+      {
+        path: '/shop/remain-pv',
+        component: () => import('@/views/shop/remain-pv'),
+        name: 'shop_remain-pv',
+      },
+      {
+        path: '/shop/order-list',
+        component: () => import('@/views/shop/order-list'),
+        name: 'shop_order-list',
+      },
+    ]
+  },
+  {
+    path: '/modify-password/:adminName', 
+    hidden: true,
+    component: () => import('@/views/login/modify-password'),
+    name: 'modify-password'
+  },
   {
     path: '/login',
     component: () => import('@/views/login/index'),

+ 25 - 2
src/router/modules/member.js

@@ -17,8 +17,31 @@ const memberRouter = {
       component: () => import('@/views/user/member-list'),
       name: 'memberList',
       meta: { title: 'Member List', icon: 'el-icon-user-solid' }
-    }
-
+    },
+    {
+      path: 'user-add-opt', // 空单操作
+      component: () => import('@/views/user/empty-order-operation'),
+      name: 'emptyOrderOperation',
+      meta: { title: 'Empty Order Operation', icon: 'el-icon-user-solid' }
+    },
+    {
+      path: 'move', // 会员移网
+      component: () => import('@/views/user/member-network-move'),
+      name: 'memberNetworkMove',
+      meta: { title: 'Move Network Management', icon: 'el-icon-user-solid' }
+    },
+    {
+      path: 'dec-level-list', // 会员等级调整
+      component: () => import('@/views/user/dec-level-list'),
+      name: 'decLevelList',
+      meta: { title: 'Member Level Adjustment List', icon: 'el-icon-user-solid' }
+    },
+    {
+      path: 'change-user-dec-role', // 修改报单中心级别
+      component: () => import('@/views/user/modify-stockist-level'),
+      name: 'modifyStockistLevel',
+      meta: { title: 'Modify Stockist Level', icon: 'el-icon-user-solid' }
+    },
   ]
 }
 

+ 0 - 7
src/store/modules/user.js

@@ -52,13 +52,6 @@ const actions = {
         commit('SET_INTRODUCTION', 'introduction')
         resolve()
       }).catch(error => {
-        Message({
-          message: error.message,
-          type: 'error',
-          duration: 5 * 1000
-        })
-
-        usersInfo.clear()
         reject(error)
       })
     })

+ 23 - 0
src/utils/importScript.js

@@ -0,0 +1,23 @@
+const importScript = function (path, success, error) {
+	let isLoaded = false
+	let scriptElements = document.getElementsByTagName('script')
+	for(let i in scriptElements){
+		if(scriptElements[i].src === path){
+			isLoaded = true
+		}
+	}
+	if(isLoaded === false){
+		let oS = document.createElement('script')
+		oS.src = path
+		document.getElementsByTagName('head')[0].appendChild(oS)
+		oS.onload = function () {
+			success && success()
+		}
+
+		oS.onerror = function () {
+			error && error()
+		}
+	}
+}
+
+export default importScript

+ 115 - 0
src/utils/region.js

@@ -0,0 +1,115 @@
+//ANRAN_REGION_DATA from cdn/jsdata
+// 深拷贝数组
+// let scriptEle = document.createElement('script')
+// scriptEle.setAttribute('src', 'http://upload.ar.wqcms.com/cdn/jsdata/ar_region_data.js?ver=0.1')
+// document.getElementsByTagName('head')[0].appendChild(scriptEle)
+// // document.write("<script language='javascript' src='http://upload.ar.wqcms.com/cdn/jsdata/ar_region_data.js?ver=0.1'></script>");
+// require('http://tool.anran.io/cdn/jsdata/ar_region_data.js')
+import importScript from "@/utils/importScript"
+import regionInfo from "@/store/modules/region";
+
+let regionScriptLoaded = false
+
+const initRegion = function (vueObj) {
+	importScript(process.env.VUE_APP_CDN_API + `/cdn/jsdata/ar_region_data.js?ver=0.1`, () => {
+		if (regionScriptLoaded) return true
+		regionScriptLoaded = true
+		let ANRAN_REGION_DATA = AR_REGION_DATA
+
+		// 汉字转code大对象
+		const rootCode = '234'
+
+		vueObj.$set(regionInfo.regionInfo.CodeToText, '', '全部')
+		// 计算省
+		for (const prop in ANRAN_REGION_DATA[rootCode]) {
+			regionInfo.regionInfo.regionData.push({
+				value: prop,
+				label: ANRAN_REGION_DATA[rootCode][prop]
+			})
+
+			regionInfo.regionInfo.CodeToText[prop] = ANRAN_REGION_DATA[rootCode][prop]
+			regionInfo.regionInfo.TextToCode[ANRAN_REGION_DATA[rootCode][prop]] = {
+				code: prop
+			}
+			regionInfo.regionInfo.TextToCode[ANRAN_REGION_DATA[rootCode][prop]]['全部'] = {
+				code: ''
+			}
+		}
+
+		// 计算市
+		for (let i = 0, len = regionInfo.regionInfo.regionData.length; i < len; i++) {
+			const provinceCode = regionInfo.regionInfo.regionData[i].value
+			const provinceText = regionInfo.regionInfo.regionData[i].label
+			const provinceChildren = []
+			for (const prop in ANRAN_REGION_DATA[provinceCode]) {
+				provinceChildren.push({
+					value: prop,
+					label: ANRAN_REGION_DATA[provinceCode][prop]
+				})
+				regionInfo.regionInfo.CodeToText[prop] = ANRAN_REGION_DATA[provinceCode][prop]
+				regionInfo.regionInfo.TextToCode[provinceText][ANRAN_REGION_DATA[provinceCode][prop]] = {
+					code: prop
+				}
+				regionInfo.regionInfo.TextToCode[provinceText][ANRAN_REGION_DATA[provinceCode][prop]]['全部'] = {
+					code: ''
+				}
+			}
+			if (provinceChildren.length) {
+				regionInfo.regionInfo.regionData[i].children = provinceChildren
+			}
+		}
+
+		regionInfo.regionInfo.provinceAndCityData = cloneArray(regionInfo.regionInfo.regionData)
+
+		// 计算区
+		for (let i = 0, len = regionInfo.regionInfo.regionData.length; i < len; i++) {
+			const province = regionInfo.regionInfo.regionData[i].children
+			const provinceText = regionInfo.regionInfo.regionData[i].label
+			if (province) {
+				for (let j = 0, len = province.length; j < len; j++) {
+					const cityCode = province[j].value
+					const cityText = province[j].label
+					const cityChildren = []
+					for (const prop in ANRAN_REGION_DATA[cityCode]) {
+						cityChildren.push({
+							value: prop,
+							label: ANRAN_REGION_DATA[cityCode][prop]
+						})
+						regionInfo.regionInfo.CodeToText[prop] = ANRAN_REGION_DATA[cityCode][prop]
+						regionInfo.regionInfo.TextToCode[provinceText][cityText][ANRAN_REGION_DATA[cityCode][prop]] = {
+							code: prop
+						}
+					}
+					if (cityChildren.length) {
+						province[j].children = cityChildren
+					}
+				}
+			}
+		}
+
+		// 添加“全部”选项
+		regionInfo.regionInfo.provinceAndCityDataPlus = cloneArray(regionInfo.regionInfo.provinceAndCityData)
+		regionInfo.regionInfo.provinceAndCityDataPlus.unshift({
+			value: '',
+			label: '全部'
+		})
+
+		regionInfo.regionInfo.regionDataPlus = cloneArray(regionInfo.regionInfo.regionData)
+		regionInfo.regionInfo.regionDataPlus.unshift({
+			value: '',
+			label: '全部'
+		})
+	})
+}
+
+
+//let ANRAN_REGION_DATA = AR_REGION_DATA
+const cloneArray = function (obj) {
+	const newArray = []
+	for (const i in obj) {
+		newArray[i] = typeof obj[i] === 'object' ? cloneArray(obj[i]) : obj[i]
+	}
+	return newArray
+}
+
+export default initRegion

+ 0 - 3
src/views/ad/edit.vue

@@ -129,7 +129,6 @@ export default {
       if (this.$route.name === 'ad-edit') {
         fetchEdit(this.$route.params.ID, this.form).then(response => {
           this.submitButtonStat = false
-          console.log(response)
           this.$message({
             message: response.data,
             type: "$t('common.successfully')"
@@ -139,10 +138,8 @@ export default {
            ElementUI.Message({type: 'error', message: error.message, showClose: true, duration: 0})
        })
       } else {
-        console.log(this.form)
         fetchAdd(this.form).then(response => {
           this.submitButtonStat = false
-          console.log(response)
           this.$message({
             message: response.data,
             type: 'success'

+ 0 - 1
src/views/ad/list.vue

@@ -275,7 +275,6 @@ export default {
     },
     getContent(aid) {
       const titles = this.allArticle.filter(article => article.ID === aid).map(article => article.TITLE)
-      console.log(titles)
       return titles.length > 0 ? titles[0] : aid
     },
     getHref(link) {

+ 2 - 2
src/views/config/dec-level-config.vue

@@ -47,7 +47,7 @@
 
     <!-- 编辑	-->
     <el-dialog v-loading="editLoading" :title="$t('common.edit')" :visible.sync="dialog" :width="screenWidth" style="margin-top: -80px">
-      <el-form ref="editForm" :model="editForm" :label-position="labelPosition" label-width="100px" style="width: 100%; margin-top: -30px; margin-bottom: -15px;">
+      <el-form ref="editForm" :model="editForm" :label-position="labelPosition" label-width="150px" style="width: 100%; margin-top: -30px; margin-bottom: -15px;">
         <el-row :gutter="3">
           <el-col :xs="24" :sm="24" :lg="12">
             <el-input v-show="false" v-model="editForm.ID" size="small" type="text" />
@@ -102,7 +102,7 @@ export default {
         PERF: '',
         isAdjustGift: false,
         isDec: false
-      }
+      },
     }
   },
   mounted() {

+ 0 - 1
src/views/dashboard/admin/index.vue

@@ -107,7 +107,6 @@ export default {
 				email: 'admin@test.com',
 				avatar: this.avatar
 			}
-			console.log(this.user)
 		}
   }
 }

+ 0 - 1
src/views/log/admin-handle.vue

@@ -73,7 +73,6 @@ export default {
     },
     getData(page, pageSize) {
       const filterData = this.filterModel
-      console.log(filterData)
       const vueObj = this
       const paramsData = Object.assign({
         page: (page === null || page === undefined) ? 1 : page,

+ 0 - 1
src/views/log/admin-login.vue

@@ -73,7 +73,6 @@ export default {
     },
     getData(page, pageSize) {
       const filterData = this.filterModel
-      console.log(filterData)
       const vueObj = this
       const paramsData = Object.assign({
         page: (page === null || page === undefined) ? 1 : page,

+ 0 - 1
src/views/log/system.vue

@@ -73,7 +73,6 @@ export default {
     },
     getData(page, pageSize) {
       const filterData = this.filterModel
-      console.log(filterData)
       const vueObj = this
       const paramsData = Object.assign({
         page: (page === null || page === undefined) ? 1 : page,

+ 0 - 1
src/views/log/user-handle.vue

@@ -73,7 +73,6 @@ export default {
     },
     getData(page, pageSize) {
       const filterData = this.filterModel
-      console.log(filterData)
       const vueObj = this
       const paramsData = Object.assign({
         page: (page === null || page === undefined) ? 1 : page,

+ 0 - 1
src/views/log/user-login.vue

@@ -75,7 +75,6 @@ export default {
     },
     getData(page, pageSize) {
       const filterData = this.filterModel
-      console.log(filterData)
       const vueObj = this
       const paramsData = Object.assign({
         page: (page === null || page === undefined) ? 1 : page,

+ 13 - 3
src/views/login/index.vue

@@ -193,7 +193,8 @@ export default {
               return false
             })
           }
-
+          const self = this;
+          let loginName = this.loginForm.username;
           // 登录
           this.$store.dispatch('user/login', loginData)
             .then(() => {})
@@ -206,9 +207,18 @@ export default {
               this.$router.push({ path: this.redirect || '/dashboard/index', query: this.otherQuery })
             }).catch(error => {
               this.loading = false
+              let msg = error + '  '
+              console.log('error-------->'+error)
               // 强制修改密码
-              if (error.message === 'ERROR_IS_MODIFY_PASSWORD') {
-                this.$router.push(`/modify-password/${this.loginForm.adminName}`)
+              if (msg.indexOf('ERROR_IS_MODIFY_PASSWORD') != -1) {
+                this.$message({
+                  message: error,
+                  type: 'error'
+                })
+                console.log('loginName--->'+loginName)
+                //  window.location.href=`/modify-password/${loginName}`
+                self.$router.push(`/modify-password/${loginName}`)
+                return false;
               } else {
                 // 清除登录数据
                 usersInfo.clear()

+ 108 - 0
src/views/login/modify-password.vue

@@ -0,0 +1,108 @@
+<template>
+    <div class="modify-wrapper">
+      <el-container>
+        <el-header class="modify-header">{{ $t('login.adminModifyPasswd') }}</el-header> <!-- 管理员密码修改 -->
+        <el-main>
+          <div class="white-box">
+            <el-form ref="form" :model="passwordInfo" label-width="250px" class="">
+              <el-form-item :label="$t('login.adminCode')"> <!-- 用户编号 -->
+                <el-input v-model="passwordInfo.adminName"></el-input>
+              </el-form-item>
+              <el-form-item :label="$t('login.originLoginPassword')"> <!-- 原登录密码 -->
+                <el-input v-model="passwordInfo.oldPassword" show-password></el-input>
+              </el-form-item>
+              <el-form-item :label="$t('login.newLoginPassword')"> <!-- 新登录密码 -->
+                <el-input v-model="passwordInfo.password" show-password></el-input>
+              </el-form-item>
+              <el-form-item :label="$t('login.confirmLoginPassword')"> <!-- 确认新密码 -->
+                <el-input v-model="passwordInfo.surePassword" show-password></el-input>
+              </el-form-item>
+              <el-form-item>
+                <el-button type="primary" @click="handleModifyPasswordSubmit" :loading="modifyPasswordButtonStat">{{ $t("common.confirm") }}</el-button> <!-- 确认修改 -->
+              </el-form-item>
+            </el-form>
+          </div>
+        </el-main>
+      </el-container>
+    </div>
+</template>
+  
+  <script>
+//   import axiosObj from '../../utils/axiosPlugin'
+  import tool from '@/utils/tool'
+  import { noLoginModifyPassword } from '@/api/user'
+  
+  export default {
+    name: 'modify-password',
+    mounted () {
+      this.passwordInfo.adminName = this.$route.params.adminName
+    },
+    data () {
+      return {
+        passwordInfo: {
+          adminName: '',
+          oldPassword: '',
+          password: '',
+          surePassword: ''
+        },
+        modifyPasswordButtonStat: false
+      }
+    },
+    methods: {
+      handleModifyPasswordSubmit () {
+        this.modifyPasswordButtonStat = true
+        let objectThis = this
+        noLoginModifyPassword(this.passwordInfo).then(response => {
+            this.modifyPasswordButtonStat = false
+            this.$message.success(response.data)
+            objectThis.$router.push('/login')
+        }).catch(err => {
+            this.$message.error(err)
+            this.modifyPasswordButtonStat = false
+        })
+        // axiosObj.post(path, this.passwordInfo).then(response => {
+        //   this.$message.success(response)
+        //   this.modifyPasswordButtonStat = false
+        //   this.$router.push('/login')
+        // }).catch(error => {
+        //   this.modifyPasswordButtonStat = false
+        //   error = tool.errorHandle(error)
+        //   this.$message.error(error.message)
+        //   console.log(error)
+        // })
+      }
+    }
+  }
+  </script>
+  
+  <style scoped>
+    .modify-wrapper .white-box {
+      background: #fff;
+      padding: 25px;
+      margin-bottom: 15px;
+      border-radius: 0;box-shadow: 0 0 10px #f2f1f4;
+    }
+  
+    .modify-wrapper .modify-header{
+        text-align: center;
+        line-height: 60px;
+        font-size: 20px;
+    }
+
+    @media (max-width: 760px) {
+        /deep/ .white-box {
+            margin-top: 85px;
+        }
+
+        /deep/ .el-form-item__label {
+            text-align:left;
+            width: 100%;
+        }
+
+        /deep/ .el-form-item__content {
+            margin-left:0px !important;
+            width:100%;
+        }
+    }
+  </style>
+  

+ 107 - 0
src/views/shop/flow-remain-pv.vue

@@ -0,0 +1,107 @@
+<template>
+    <div v-loading="loading">
+      <div class="white-box">
+        <div class="filter-box">
+          <filter-user :filter-types="filterTypes" @select-value="handleFilterUser"></filter-user>
+        </div>
+        <el-table class="table-box" ref="multipleTable" :data="tableData" stripe style="width: 100%;" :height="tool.getTableHeight()">
+          <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header"  :prop="tableHeader.other.prop ? tableHeader.other.prop : null">
+            <template slot-scope="scope">
+              <template v-if="scope.row[tableHeader.index].other.tag" >
+                <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null" >{{scope.row[tableHeader.index].value}}</el-tag>
+              </template>
+              <template v-else>
+                <div v-html="scope.row[tableHeader.index].value"></div>
+              </template>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="white-box-footer">
+          <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange"></pagination>
+        </div>
+      </div>
+    </div>
+  </template>
+  <script>
+  import tool from '@/utils/tool'
+  import baseInfo from '@/utils/baseInfo'
+  import FilterUser from '@/components/FilterUser'
+  import permission from '@/utils/permission'
+  import Pagination from '@/components/Pagination'
+  import filterHelper from '@/utils/filterHelper'
+  import { flowRemainPvList } from '@/api/shop'
+
+  export default {
+    name: 'shop_flow-remain-pv',
+    components: {FilterUser, Pagination},
+    mounted () {
+      this.getData()
+    },
+    data () {
+      return {
+        tableHeaders: null,
+        tableData: null,
+        loading: true,
+        multipleSelection: [],
+        currentPage: 1,
+        totalPages: 1,
+        totalCount: 1,
+        pageSize: 20,
+        tool: tool,
+        permission: permission,
+        baseDecLevels: baseInfo.decLevels(),
+        baseEmpLevels: baseInfo.empLevels(),
+        filterTypes: null,
+        filterModel: {}
+      }
+    },
+    methods: {
+      handleCurrentChange (page) {
+        this.getData(page, this.pageSize)
+      },
+      handleSizeChange (pageSize) {
+        this.getData(this.currentPage, pageSize)
+      },
+      handleFilterUser (filterData) {
+        filterHelper.handleFilterUser(this, filterData)
+      },
+      getData (page, pageSize) {
+        let filterData = this.filterModel
+        let vueObj=this
+        const paramsData = Object.assign({
+        page: (page === null || page == undefined) ? 1 : page,
+        pageSize: (pageSize === null || pageSize == undefined) ? vueObj.pageSize : pageSize
+        }, filterData)
+        flowRemainPvList(paramsData).then(response => {
+            vueObj.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+            vueObj.tableData = response.data.list
+            vueObj.filterTypes = response.data.filterTypes
+            vueObj.currentPage = page
+            vueObj.totalPages = parseInt(response.data.totalPages)
+            vueObj.totalCount = parseInt(response.data.totalCount)
+            vueObj.pageSize = pageSize
+            this.loading = false
+        }).catch(err => {
+            this.loading = false
+            this.$message({
+                message: err,
+                type: 'error'
+            })
+        })
+      }
+    }
+  }
+  
+  </script>
+  <style scoped>
+    .table-box .el-form-item__label {
+      width: 100px;
+      color: #99a9bf;
+    }
+    .table-box .el-form-item {
+      width: 30%;
+      margin-right: 0;
+      margin-bottom: 0;
+    }
+  </style>
+  

+ 309 - 0
src/views/shop/goods-add.vue

@@ -0,0 +1,309 @@
+<template>
+    <div v-loading="loading">
+        <div class="white-box">
+            <el-form ref="form"  label-width="auto" class="form-page">
+                <el-form-item :label="$t('shop.productName')"><!-- 商品名称 -->
+                    <el-input v-model="form.goodsName"></el-input>
+                </el-form-item>
+                <el-form-item :label="$t('shop.memberDiscount')"><!-- 会员折扣 -->
+                    <el-input v-model="form.sellDiscount"></el-input>
+                </el-form-item>
+                <el-form-item :label="$t('shop.productType')"><!-- 商品类型 -->
+                    <el-checkbox  v-for="(value,key) in GiftTypeArr" v-model="form.giftType[key-1]" :key="key" >{{value.name}}</el-checkbox>
+                </el-form-item>
+                <el-form-item :label="$t('shop.bvSplit')">
+                  <el-select v-model="form.pvSplit" placeholder="">
+                    <el-option
+                      v-for="item in pvSplitOptions"
+                      :key="item.value"
+                      :label="item.label"
+                      :value="item.value">
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+                <el-form-item :label="$t('shop.productCategory')"><!-- 商品分类 -->
+                    <el-select v-model="form.categoryType" placeholder="">
+                        <el-option v-for="item in categoryType" :key="item.id" :label="item.name" :value="item.id"></el-option>
+                    </el-select>
+                </el-form-item>
+                <el-form-item :label="$t('shop.productCode')"><!-- 商品编号 -->
+                    <el-input v-model="form.goodsNo"></el-input>
+                </el-form-item>
+                <el-form-item :label="$t('shop.unit')"><!-- 单位 -->
+                    <el-input v-model="form.unit"></el-input>
+                </el-form-item>
+                <el-form-item :label="$t('shop.taxRate')"><!-- 税率 -->
+                  <el-input v-model="form.taxRate">
+                    <template slot="append">%</template>
+                  </el-input>
+                </el-form-item>
+                <el-form-item :label="$t('shop.uSPrice')" p>
+                    <el-input v-model="form.sellPriceStandard"></el-input>
+                </el-form-item>
+                <el-form-item :label="$t('shop.salesPrice')">
+                    <el-input v-model="form.sellPrice"></el-input>
+                </el-form-item>
+                <el-form-item :label="$t('shop.marketPrice')">
+                  <el-input v-model="form.marketPrice"></el-input>
+                </el-form-item>
+                <el-form-item :label="$t('shop.priceBV')" v-show="pvDisabled"><!-- 价格BV -->
+                    <el-input v-model="form.pricePv"></el-input>
+                </el-form-item>
+                <el-form-item :label="$t('shop.inventory')"><!-- 库存 -->
+                    <el-input v-model="form.storeNums"></el-input>
+                </el-form-item>
+                <el-form-item :label="$t('shop.productDetails')"><!-- 商品详情 -->
+                    <el-input
+                            type="textarea"
+                            :rows="2"
+                            :placeholder="$t('shop.enterContentNotice')"
+                            v-model="form.content">
+                    </el-input><!-- 请输入内容 -->
+                </el-form-item>
+                <el-form-item :label="$t('shop.order')"><!-- 排序 -->
+                    <el-input v-model="form.sort"></el-input>
+                </el-form-item>
+                <el-form-item :label="$t('shop.uploadImages')"><!-- 上传图片 -->
+                    <div class='up_load'>
+                        <!-- <leo-uploader
+                            @on-success='upLoadSuccess'
+                            :request-route="'shop/upload'"
+                        ></leo-uploader> -->
+                        <Upload
+                            :request-route="'v1/shop/upload'"
+                            width="400px"
+                            height="160px"
+                            @on-success="upLoadSuccess"
+                            ></Upload>
+                    </div>
+                </el-form-item>
+                <el-form-item>
+                    <el-button type="primary" @click="addSubmit" :loading="submitButtonStat">{{ $t('table.add') }}<!-- 添加 --></el-button>
+                </el-form-item>
+            </el-form>
+        </div>
+    </div>
+</template>
+
+<script>
+import baseInfo from '@/utils/baseInfo'
+import Upload from '@/components/Upload'
+import { getAddGoodsConfig, getUploadToken, addGoods } from '@/api/shop'
+
+export default {
+  name: 'goods-add',
+  components: {Upload},
+  mounted () {
+    this.getData()
+    this.getFileToken()
+  },
+  data () {
+    return {
+      dialogImageUrl: '',
+      dialogVisible: false,
+      disabled: false,
+      loading: false,
+      file: null,
+      uploadToken: '',
+      pvSplitOptions: [
+        {
+          value: '0',
+          label: this.$t('common.no')
+        },
+        {
+          value: '1',
+          label: this.$t('common.yes')
+        }],
+      form: {
+        goodsName: '',
+        type: '',
+        giftType: [false, false, false, false],
+        sellType: [false, false],
+        goodsNo: '',
+        unit: '',
+        marketPrice: '',
+        sellPrice: '',
+        pvSplit: '0',
+        pricePv: '',
+        point: '',
+        storeNums: '',
+        content: '',
+        sort: '',
+        discount: '',
+        cover: '',
+        textarea: '',
+        sellDiscount: '',
+        categoryType: '',
+        sellPriceStandard: '',
+        taxRate: 0
+      },
+      submitButtonStat: false,
+      goodsType: [],
+      GiftTypeArr: [],
+      categoryType: [],
+      sellType: null,
+      width: '100px',
+      height: '100px',
+      pvDisabled: true,
+      exchangeRate: baseInfo.exchangeRate()
+    }
+  },
+  watch: {
+    dialogVisible (newVal, oldVal) {
+      console.log(newVal, oldVal)
+    },
+    // 监听商品分类,控制PV是否展示
+    'form.categoryType': {
+      deep: true,
+      handler (modern, origin) {
+        this.pvDisabled = (parseInt(modern) === 1)
+      }
+    }
+    // 监听商品标准价格,自动计算销售价格
+    // 'form.sellPriceStandard': {
+    //     deep: true,
+    //     handler(modern, origin) {
+    //         this.form.sellPrice = modern * this.exchangeRate
+    //     }
+    // },
+  },
+  methods: {
+    handleRemove (file) {
+      console.log(file)
+    },
+    upLoadSuccess (file) {
+      this.form.cover = file
+    },
+    handlePictureCardPreview (file) {
+      this.dialogImageUrl = file.url
+      this.dialogVisible = true
+      this.file = file
+      // console.log(file);
+    },
+    handleDownload (file) {
+      console.log(file)
+    },
+    getFileToken () {
+        getUploadToken().then(response => {
+            this.uploadToken = response.data
+        }).catch(err => {
+            this.$message({
+                message: this.$t('common.modifyData'),
+                type: 'info'
+            })
+        }) 
+    },
+    getData (page, pageSize) {
+      getAddGoodsConfig(this.filterModel).then(response => {
+        this.categoryType = response.data.categoryType
+        this.goodsType = response.data.goodsType
+        this.GiftTypeArr = response.data.giftType
+        this.sellType = response.data.sellType
+      }).catch(err => {
+        this.$message({
+          message: err, 
+          type: 'error'
+        })
+      })
+    },
+    addSubmit () {
+      this.submitButtonStat = true
+      let path = 'shop/goods-add'
+      let sen_gift = []
+      this.form.giftType.map((item, index) => {
+        if (item) {
+          sen_gift.push((index + 1).toString())
+        }
+      })
+
+      let postData = {
+        goodsName: this.form.goodsName,
+        sellDiscount: this.form.sellDiscount,
+        discount: this.form.type.discount,
+        type: this.form.type,
+        giftType: sen_gift,
+        // sellType: sellType,
+        sellType: this.form.sellType,
+        pvSplit: this.form.pvSplit,
+        categoryType: this.form.categoryType,
+        goodsNo: this.form.goodsNo,
+        unit: this.form.unit,
+        marketPrice: this.form.marketPrice,
+        sellPrice: this.form.sellPrice,
+        sellPriceStandard: this.form.sellPriceStandard,
+        pricePv: this.form.pricePv,
+        // point: this.form.point,
+        storeNums: this.form.storeNums,
+        content: this.form.content,
+        sort: this.form.sort,
+        cover: this.form.cover,
+        taxRate: this.form.taxRate
+      }
+      addGoods(postData).then(response => {
+        this.$message({
+          message: response.data,
+          type: 'success'
+        })
+        this.submitButtonStat = false
+        this.$router.go(-1)
+      }).catch(err => {
+        this.$message({
+          message: err,
+          type: 'error'
+        })
+        this.submitButtonStat = false
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+/* 小于760 */
+ @media (max-width:759px) {
+    
+    /deep/ .el-input {
+        width: 100% !important;
+    }
+    /deep/ .el-select {
+        width: 100% !important;
+    }
+
+    /deep/ .el-textarea {
+        width: 100% !important;
+    }
+    /deep/ .image-uploader {
+        width: 100% !important;
+    }
+    /deep/ i.el-icon-plus.uploader-icon {
+        width:100% !important;
+    }
+    /deep/ .form-page {
+        width:100%;
+        padding-left: 1%;
+    }
+    /deep/ img { 
+        width: 100% !important;
+        height: 100% !important;
+    }
+} 
+
+@media (min-width:760px) {
+    /deep/ .el-input {
+        width: 400px !important;
+    }
+    /deep/ .el-select {
+        width: 400px !important;
+    }
+    /deep/ .el-textarea {
+        width: 400px !important;
+    }
+    /deep/ .upload-container {
+        width: 400px !important;
+    }
+    /deep/ .form-page {
+        width:100%;
+        padding-left: 10%;
+    }
+}
+</style>

+ 514 - 0
src/views/shop/index.vue

@@ -0,0 +1,514 @@
+<template>
+    <div v-loading="loading">
+      <div class="white-box">
+        <div class="filter-box">
+            <filter-user :filter-types="filterTypes" @select-value="handleFilterUser"></filter-user>
+        </div>
+        <el-table class="table-box" ref="multipleTable" :data="tableData" stripe style="width: 100%;" :height="tool.getTableHeight()" @selection-change="handleSelectionChange">
+          <el-table-column type="selection" width="55" v-if="tableHeaders" :selectable="checkSelectable"></el-table-column>
+          <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''" :prop="tableHeader.other.prop ? tableHeader.other.prop : null">
+            <template slot-scope="scope">
+              <template v-if="scope.row[tableHeader.index].other.tag" >
+                <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null" >{{scope.row[tableHeader.index].value}}</el-tag>
+              </template>
+              <template v-else>
+                <div v-html="scope.row[tableHeader.index].value"></div>
+              </template>
+            </template>
+          </el-table-column>
+          <el-table-column :fixed="fixedColumn" :label="$t('common.action')" width="180"><!-- 操作 -->
+            <template slot-scope="scope">
+              <el-dropdown size="small" trigger="click" v-if="permission.hasPermission(`shop/goods-edit`) || permission.hasPermission(`shop/goods-delete`)">
+                <el-button type="primary" size="small" @click.stop="">
+                  {{ $t('common.action') }}<!-- 操作该数据 --><i class="el-icon-arrow-down el-icon--right"></i>
+                </el-button>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item command="goods-edit" @click.native="handleEditShow(scope.row)">{{ $t('common.edit') }}<!-- 修改数据 --> </el-dropdown-item>
+                  <el-dropdown-item command="del" @click.native="handleDel(scope.row.ID)" v-show="permission.hasPermission(`shop/goods-delete`)">
+                    {{ $t('common.delete') }}<!-- 删除数据 -->
+                  </el-dropdown-item>
+                  <el-dropdown-item command="goods-edit" @click.native="handleGoodUp(scope.row.ID)">{{ $t('shop.onSale') }}<!-- 商品上架 --> </el-dropdown-item>
+                  <el-dropdown-item command="goods-edit" @click.native="handleGoodDown(scope.row.ID)">{{ $t('shop.soldOut') }}<!-- 商品下架 --> </el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+            </template>
+          </el-table-column>
+          <!--   <el-table-column label="操作">
+            <template slot-scope="scope">
+              <el-button type="success" size="small" @click="handleGroupManage(scope.row)" >
+                状态管理
+              </el-button>
+            </template></el-table-column>-->
+        </el-table>
+        <div class="white-box-footer">
+  
+         <!-- <el-dropdown size="small" trigger="click">
+              <el-button type="primary" size="small">
+                  所选数据<i class="el-icon-arrow-down el-icon&#45;&#45;right"></i>
+              </el-button>
+              <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item command="delete" @click.native="handleMuliDel()">上架</el-dropdown-item>
+              </el-dropdown-menu>
+          </el-dropdown>-->
+          <el-button type="primary" size="small" @click="handlestate" icon="el-icon-plus" v-if="permission.hasPermission(`shop/goods-add`)">
+            <!-- 商品添加 -->{{ $t('shop.addProduct') }}
+          </el-button>
+  
+          <el-button type="success" size="small" @click="handleExport" v-show="permission.hasPermission(`shop/goods-list-export`)">{{ $t('common.exportExcel') }}</el-button>
+          <!-- <el-button-group>
+            <el-button type="success" size="mini" @click.native="handleup(scope.row.ID)">上架</el-button>
+            <el-button type="danger" size="mini">下架</el-button>
+          </el-button-group> -->
+          <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange"></pagination>
+        </div>
+      </div>
+      <el-dialog :title="$t('shop.editProducts')" :visible.sync="dialogEditFormVisible"><!-- 修改商品 -->
+        <el-form :model="form"  v-loading="dialogEditLoading">
+          <el-form-item :label="$t('shop.productName')"><!-- 商品名称 -->
+            <el-input v-model="form.goodsName"></el-input>
+          </el-form-item>
+            <!-- <el-form-item label="商品来源">
+              <el-select v-model="form.type">
+                  <el-option v-for="(item,index) in goodsType" :key="index" :label="item.name"
+                             :value="index"></el-option>
+              </el-select>
+            </el-form-item> -->
+            <el-form-item :label="$t('shop.memberDiscount')"><!-- 会员折扣 -->
+              <el-input v-model="form.sellDiscount"></el-input>
+            </el-form-item>
+            <el-form-item :label="$t('shop.productType')"><!-- 商品类型 -->
+              <el-checkbox  v-for="(value,index) in GiftTypeArr" v-model="value.checked" :key="index" >{{value.name}}</el-checkbox>
+            </el-form-item>
+            <!-- <el-form-item label="复消购买方式">
+               <el-checkbox  v-for="(value,index) in sell_type" v-model="value.checked" :key="index" >{{value.name}}</el-checkbox>
+            </el-form-item> -->
+            <el-form-item :label="$t('shop.bvSplit')">
+  <!--                      <el-checkbox v-model="form.pvSplit" :checked="form.pvSplit">Yes</el-checkbox>-->
+              <el-select v-model="form.pvSplit" placeholder="">
+                <el-option
+                  v-for="item in pvSplitOptions"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value">
+                </el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item :label="$t('shop.productCategory')"> <!-- 商品分类 -->
+              <el-select v-model="form.categoryType">
+                <el-option v-for="item in categoryType" :key="item.id" :label="item.name" :value="item.id" ></el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item :label="$t('shop.productCode')"><!-- 商品编号 -->
+              <el-input v-model="form.goodsNo"></el-input>
+            </el-form-item>
+            <el-form-item :label="$t('shop.unit')"><!-- 单位 -->
+              <el-input v-model="form.unit"></el-input>
+            </el-form-item>
+            <el-form-item :label="$t('shop.taxRate')"><!-- 税率 -->
+              <el-input v-model="form.taxRate">
+                <template slot="append">%</template>
+              </el-input>
+            </el-form-item>
+            <el-form-item :label="$t('shop.uSPrice')" p>
+              <el-input v-model="form.sellPriceStandard"></el-input>
+            </el-form-item>
+            <el-form-item :label="$t('shop.salesPrice')" p>
+              <el-input v-model="form.sellPrice"></el-input>
+            </el-form-item>
+            <el-form-item :label="$t('shop.marketPrice')">
+              <el-input v-model="form.marketPrice"></el-input>
+            </el-form-item>
+            <el-form-item :label="$t('shop.priceBV')" v-show="pvDisabled"> <!-- 价格BV -->
+              <el-input v-model="form.pricePv"></el-input>
+            </el-form-item>
+  <!--                    <el-form-item label="Exchange points" v-show="false"> &lt;!&ndash; 兑换积分 &ndash;&gt;-->
+  <!--                        <el-input v-model="form.point"></el-input>-->
+  <!--                    </el-form-item>-->
+            <el-form-item :label="$t('shop.inventory')"> <!-- 库存 -->
+              <el-input v-model="form.storeNums"></el-input>
+            </el-form-item>
+            <el-form-item :label="$t('shop.productDetails')"><!-- 商品详情 -->
+              <el-input
+                type="textarea"
+                :rows="2"
+                :placeholder="$t('shop.enterContentNotice')"
+                v-model="form.content">
+              </el-input><!-- 请输入内容 -->
+            </el-form-item>
+            <el-form-item :label="$t('shop.order')"> <!-- 排序 -->
+              <el-input v-model="form.sort"></el-input>
+            </el-form-item>
+            
+            <el-form-item :label="$t('shop.uploadImages')"> <!-- 上传图片 -->
+              <div class='up_load'>
+                <Upload
+                  v-model="form.image"
+                  :request-route="'v1/shop/upload'"
+                  :default-image-url="form.cover"
+                  width="400px"
+                  height="160px"
+                  @on-success="upLoadSuccess"
+                ></Upload>
+              </div>
+            </el-form-item>
+          </el-form>
+          <div slot="footer" class="dialog-footer">
+            <el-button @click="dialogEditFormVisible = false">{{ $t('table.cancel') }}<!-- 取 消 --></el-button>
+            <el-button type="primary" @click.native="handleEdit">{{ $t('table.edit') }}<!-- 修 改 --></el-button>
+          </div>
+      </el-dialog>
+    </div>
+  </template>
+  
+  <script>
+  import {getOperatingSystem} from "@/utils"
+  import tool from '@/utils/tool'
+  import baseInfo from '@/utils/baseInfo'
+  import FilterUser from '@/components/FilterUser'
+  import permission from '@/utils/permission'
+  import Pagination from '@/components/Pagination'
+  import filterHelper from '@/utils/filterHelper'
+  import { shopList, goodsListExport, updateGoodsStatus, goodsDelete, getGoodsDetail, editGoodsData } from '@/api/shop'
+  import Upload from '@/components/Upload'
+
+  export default {
+    name: 'index',
+    components: {FilterUser, Pagination, Upload},
+    mounted () {
+      this.getData()
+      // this.$refs.up_load.successImageUrl='';
+      let system =  getOperatingSystem()
+      if (system == "Android" || system == 'ios') {
+        this.fixedColumn = false
+      } else {
+        this.fixedColumn = 'right'
+      }
+    },
+  
+    data () {
+      return {
+        fixedColumn:false, // 固定,当手机端不固定,pc固定
+        tableHeaders: null,
+        tableData: null,
+        loading: true,
+        currentPage: 1,
+        totalPages: 1,
+        totalCount: 1,
+        pageSize: 20,
+        multipleSelection: [],
+        tool: tool,
+        permission: permission,
+        baseDecLevels: baseInfo.decLevels(),
+        baseEmpLevels: baseInfo.empLevels(),
+        filterTypes: null,
+        dialogVisible: false,
+        dialogLoading: false,
+        filterModel: {},
+        value: [],
+        selectedIds: '',
+        dialogEditFormVisible: false,
+        dialogEditLoading: false,
+        pvSplitOptions: [
+          {
+            value: '0',
+            label: this.$t('common.no')
+          },
+          {
+            value: '1',
+            label: this.$t('common.yes')
+          }],
+        form: {
+          // sellType: [],
+          goodsName: '',
+          type: '',
+          giftType: [],
+          goodsNo: '',
+          unit: '',
+          marketPrice: '',
+          sellPrice: '',
+          sellPriceStandard: '',
+          pricePv: '',
+          point: '',
+          storeNums: '',
+          content: '',
+          sort: '',
+          discount: '',
+          cover: '',
+          textarea: '',
+          sellDiscount: '',
+          pvSplit: '',
+          categoryType: '',
+          sellType: 1,
+          taxRate: 0
+        },
+        submitButtonStat: false,
+        goodsType: [],
+        GiftTypeArr: [],
+        sell_type: [],
+        categoryType: [],
+        img_show: true,
+        pvDisabled: true,
+        exchangeRate: baseInfo.exchangeRate()
+      }
+    },
+    methods: {
+      handleSelectionChange (val) {
+        this.multipleSelection = val
+      },
+      handleCurrentChange (page) {
+        this.getData(page, this.pageSize)
+      },
+      handleSizeChange (pageSize) {
+        this.getData(this.currentPage, pageSize)
+      },
+      handleFilterUser (filterData) {
+        filterHelper.handleFilterUser(this, filterData)
+      },
+      checkSelectable (row) {
+        return row.DONT_DEL !== '1'
+      },
+      handleFilter () {
+        this.getData()
+      },
+      handlestate () {
+        this.$router.push({path: `/shop/goods-add`})
+      },
+      upLoadSuccess (file) {
+        this.form.cover = tool.getArImage(file, '/files/')
+        this.form.coverOrigin = file
+        this.img_show = false
+      },
+      handleEditShow (row) {
+        this.dialogEditLoading = true
+        this.auditId = row.ID
+        this.dialogEditFormVisible = true
+        let vueObj = this
+        getGoodsDetail({id: this.auditId}).then(response => {
+            vueObj.dialogEditLoading = false
+            vueObj.goodsType = response.data.goodsType
+            vueObj.categoryType = response.data.categoryType
+            let gift = response.data.goodsInfo.GIFT_TYPE;
+            let gift_type = response.data.giftType
+            let giftType = []
+            if (gift.length > 0) {
+                for (let i in gift_type) {
+                    giftType.push({key: i, name: gift_type[i].name, checked: false})
+                    gift.map((v, k) => {
+                        if (v === i) {
+                            giftType[i - 1].checked = true
+                        }
+                    })
+                }
+            }
+            vueObj.GiftTypeArr = giftType
+            vueObj.sell_type = response.data.goodsInfo.SELL_TYPE;
+            vueObj.form.goodsName = response.data.goodsInfo.GOODS_NAME
+            vueObj.form.sellDiscount = response.data.goodsInfo.SELL_DISCOUNT
+            vueObj.form.goodsNo = response.data.goodsInfo.GOODS_NO
+            vueObj.form.type = response.data.goodsInfo.TYPE
+            vueObj.form.unit = response.data.goodsInfo.UNIT
+            vueObj.form.marketPrice = response.data.goodsInfo.MARKET_PRICE
+            vueObj.form.sellPrice = response.data.goodsInfo.SELL_PRICE
+            vueObj.form.sellPriceStandard = response.data.goodsInfo.SELL_PRICE_STANDARD
+            vueObj.form.pricePv = response.data.goodsInfo.PRICE_PV
+            vueObj.form.point = response.data.goodsInfo.POINT
+            vueObj.form.storeNums = response.data.goodsInfo.STORE_NUMS
+            vueObj.form.content = response.data.goodsInfo.CONTENT
+            vueObj.form.sort = response.data.goodsInfo.SORT
+            vueObj.form.id = response.data.goodsInfo.ID
+            vueObj.form.pvSplit = response.data.goodsInfo.PV_SPLIT
+            vueObj.form.categoryType = parseInt(response.data.goodsInfo.CATEGORY_TYPE)
+            vueObj.form.taxRate = response.data.goodsInfo.TAX_RATE
+            vueObj.form.coverOrigin = response.data.goodsInfo.COVER
+            vueObj.form.cover = tool.getArImage(response.data.goodsInfo.COVER, '/files/')
+    
+            this.$forceUpdate()
+        }).catch(err => {
+
+        })
+      },
+      handleEdit () {
+        this.dialogEditFormVisible = false
+        this.$message({
+          message: this.$t('common.modifyData'), // 正在修改数据
+          type: 'info'
+        })
+        // let sen_sell=[];
+        // this.sell_type.map((item,index)=>{
+        //     if(item.checked){
+        //         sen_sell.push(item.key);
+        //     }
+        // })
+        // this.form.sellType=sen_sell;
+  
+        let sen_gift = []
+        this.GiftTypeArr.map((item, index) => {
+          if (item.checked) {
+            sen_gift.push(item.key)
+          }
+        })
+        this.form.giftType = sen_gift
+        this.form.sellType = 1
+        this.form.cover = this.form.coverOrigin
+        delete this.form.coverOrigin
+        editGoodsData({...this.form}).then(response => {
+          this.$message({
+            message: response.data,
+            type: 'success'
+          })
+          this.getData(this.currentPage, this.pageSize)
+        }).catch(err => {
+          this.$message({
+            message:err,
+            type: 'error'
+          })
+        })
+      },
+  
+      handleDel (id = null) {
+        let obj = this
+        this.$confirm(this.$t('common.deleteTips'), this.$t('common.hint'), { // '确定删除选定的数据?', '提示'
+          confirmButtonText: this.$t('common.confirm'), // 确定
+          cancelButtonText: this.$t('common.cancel'), // 取消
+          type: 'warning'
+        }).then(() => {
+          let selectedIds = []
+          if (id === null) {
+            for (let val of obj.multipleSelection) {
+              selectedIds.push(val.ID)
+            }
+          } else {
+            selectedIds.push(id)
+          }
+          goodsDelete({selected: selectedIds}).then(response => {
+            this.$message({
+                message: response.data,
+                type: 'success'
+            })
+            obj.getData(obj.currentPage, obj.pageSize)
+          }).catch(err => {
+            this.$message({
+                message: err,
+                type: 'error'
+            })
+          })
+        })
+      },
+      getData (page, pageSize) {
+        let filterData = this.filterModel
+        /* this.allData = response */
+        let vueObj=this
+        const paramsData = Object.assign({
+        page: (page === null || page == undefined) ? 1 : page,
+        pageSize: (pageSize === null || pageSize == undefined) ? vueObj.pageSize : pageSize
+        }, filterData)
+        shopList(paramsData).then(response => {
+            vueObj.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+            vueObj.tableData = response.data.list
+            vueObj.filterTypes = response.data.filterTypes
+            vueObj.currentPage = page
+            vueObj.totalPages = parseInt(response.data.totalPages)
+            vueObj.totalCount = parseInt(response.data.totalCount)
+            vueObj.pageSize = pageSize
+            this.loading = false
+        }).catch(err => {
+            this.loading = false
+            this.$message({
+                message: err,
+                type: 'error'
+            })
+        })
+      },
+      handleGoodUp (id) {
+        updateGoodsStatus({selectedIds: id, status: 1}).then(response => {
+            this.$message({
+              message: response.data,
+              type: 'success'
+            })
+            this.getData(this.currentPage, this.pageSize)
+        }).catch(err => {
+            this.$message({
+              message: err,
+              type: 'error'
+            })
+        })
+      },
+      handleGoodDown (id) {
+        updateGoodsStatus({selectedIds: id, status: 0}).then(response => {
+            this.$message({
+              message: response.data,
+              type: 'success'
+            })
+            this.getData(this.currentPage, this.pageSize)
+        }).catch(err => {
+            this.$message({
+              message: err,
+              type: 'error'
+            })
+        })
+      },
+  
+      handleExport () {
+        this.$confirm(this.$t('financial.exportNotice'), this.$t('common.hint'), { // 确定要导出当前数据吗?`, '提示'
+          confirmButtonText: this.$t('common.confirm'), // 确定
+          cancelButtonText: this.$t('common.cancel'), // 取消
+          type: 'warning'
+        }).then(() => {
+            goodsListExport(this.filterModel).then(response => {
+                this.$message({
+                    message: response.data,
+                    type: 'success'
+                })
+            }).catch(err => {
+                this.$message({
+                    message: err,
+                    type: 'error'
+                })
+            })
+        })
+      }
+    },
+    watch: {
+      // 监听商品分类,控制PV是否展示
+      'form.categoryType': {
+        deep: true,
+        handler (modern, origin) {
+          this.pvDisabled = (parseInt(modern) === 1)
+        }
+      }
+      // // 监听商品标准价格,自动计算销售价格
+      // 'form.sellPriceStandard': {
+      //     deep: true,
+      //     handler(modern, origin) {
+      //         this.form.sellPrice = modern * this.exchangeRate
+      //     }
+      // },
+    }
+  }
+  
+  </script>
+  
+  <style scoped>
+      .table-box .el-form-item__label {
+          width: 100px;
+          color: #99a9bf;
+      }
+  
+      .table-box .el-form-item {
+          width: 30%;
+          margin-right: 0;
+          margin-bottom: 0;
+      }
+      /deep/ .el-dialog .el-form-item__label {
+        width:100%;
+        text-align: left;
+      }
+      @media (max-width:862px) {
+        /deep/ img { 
+          width: 100px !important;
+          height: 60px !important;
+        }
+      }
+      
+  </style>
+  

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

@@ -0,0 +1,165 @@
+<template>
+    <div v-loading="loading">
+      <div class="white-box">
+        <div class="filter-box">
+          <filter-user :filter-types="filterTypes" @select-value="handleFilterUser"></filter-user>
+        </div>
+        <el-table class="table-box" ref="multipleTable" :data="tableData" stripe style="width: 100%;"
+                  @selection-change="handleSelectionChange"
+                  :height="tool.getTableHeight()">
+          <el-table-column type="selection" width="70" v-if="tableHeaders"></el-table-column>
+          <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''" :prop="tableHeader.other.prop ? tableHeader.other.prop : null">
+            <template slot-scope="scope">
+              <template v-if="scope.row[tableHeader.index].other.tag" >
+                <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null" >{{scope.row[tableHeader.index].value}}</el-tag>
+              </template>
+              <template v-else>
+                <div v-html="scope.row[tableHeader.index].value"></div>
+              </template>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="white-box-footer">
+          <el-button type="success" size="small" @click="handleImport" v-show="permission.hasPermission(`shop/order-dec-list-import`)">{{ $t('shop.orderImport') }}<!-- 订单导入 --></el-button>
+  
+          <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange"
+                      @current-change="handleCurrentChange"></pagination>
+        </div>
+      </div>
+      <el-dialog :title="$t('shop.orderImport')" :visible.sync="importDialogVisible" width="50%"><!-- 订单导入 -->
+        <el-form ref="form" :model="excelForm" style="width: 100%;" class="form-page">
+          <el-form-item :label="$t('shop.currentImportOrderDate')"><!-- 当前导入订单日期 -->
+            <el-date-picker  v-model="excelForm.orderDay" type="date" :placeholder="$t('shop.selectDate')"  value-format="yyyy-MM-dd"><!-- 选择日期 -->
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item v-show="false" :label="$t('shop.currentImportOrderPeriods')"><!-- 当前导入订单期数 -->
+            <el-input v-model="excelForm.periodNum"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('shop.totalRowsExcel')"><!-- Excel 文件总行数 -->
+            <el-input v-model="excelForm.rowCount"></el-input>
+          </el-form-item>
+          <el-form-item>
+            <leo-excel-uploader
+                    :request-upload-route="`v1/file/upload-excel`"
+                    :request-import-to-excel-table-route="`shop/import-order-dec-to-excel-table`"
+                    :request-import-excel-table-to-data-route="`shop/import-order-dec`"
+                    :import-row-count="excelForm.rowCount"
+                    :other-params="excelForm"
+                    :finish-callback-func="uploadFinishFunc"
+                    excel-option="addUser"
+                    upload-btn-title="Excel import"
+                    style="float: left;"
+            ></leo-excel-uploader>
+            <!-- Excel导入 -->
+          </el-form-item>
+        </el-form>
+      </el-dialog>
+    </div>
+  </template>
+  
+  <script>
+      import tool from '@/utils/tool'
+      import FilterUser from '@/components/FilterUser'
+      import permission from '@/utils/permission'
+      import LeoExcelUploader from '@/components/ExcelUploader'
+      import Pagination from '@/components/Pagination'
+      import filterHelper from '@/utils/filterHelper'
+      import { orderDecList } from '@/api/shop'
+  
+      export default {
+          name: 'shop_order_dec-list',
+          components: {FilterUser, Pagination, LeoExcelUploader},
+          mounted() {
+            this.initData()
+            this.getData()
+          },
+          data() {
+              return {
+                  tableHeaders: null,
+                  tableData: null,
+                  tableHeight: window.innerHeight - 310,
+                  loading: true,
+                  multipleSelection: [],
+                  currentPage: 1,
+                  totalPages: 1,
+                  totalCount: 1,
+                  pageSize: 20,
+                  tool: tool,
+                  permission: permission,
+                  filterTypes: null,
+                  filterModel: {},
+                  dialogDeliveryVisible: false,
+                  deliveryForm: {
+                      sn: '',
+                      expressCompany: '',
+                      orderTrackNo: '',
+                  },
+                  excelForm: {
+                      rowCount: 0,
+                      periodNum: 0,
+                      orderDay: 0,
+                  },
+                  importDialogVisible:false,
+              }
+          },
+          methods: {
+              handleSelectionChange(val) {
+                  this.multipleSelection = val
+              },
+              handleCurrentChange(page) {
+                  this.getData(page, this.pageSize)
+              },
+              handleSizeChange(pageSize) {
+                  this.getData(this.currentPage, pageSize)
+              },
+              handleFilterUser(filterData) {
+                  filterHelper.handleFilterUser(this, filterData)
+              },
+              initData(){
+                let myDate = new Date();
+                let thisYear = myDate.getFullYear();
+                let thisMonth = myDate.getMonth() + 1 < 10 ? '0' + (myDate.getMonth() + 1) : myDate.getMonth() + 1
+                let thisDate = myDate.getDate() < 10 ? '0' + (myDate.getDate()) : myDate.getDate()
+                this.excelForm.orderDay = thisYear + '-' + thisMonth + '-' + thisDate
+              },
+              getData(page, pageSize) {
+                  let filterData = this.filterModel
+                  let vueObj=this
+                  const paramsData = Object.assign({
+                    page: (page === null || page == undefined) ? 1 : page,
+                    pageSize: (pageSize === null || pageSize == undefined) ? vueObj.pageSize : pageSize
+                    }, filterData)
+                  orderDecList(paramsData).then(response => {
+                    vueObj.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+                    vueObj.tableData = response.data.list
+                    vueObj.filterTypes = response.data.filterTypes
+                    vueObj.currentPage = page
+                    vueObj.totalPages = parseInt(response.data.totalPages)
+                    vueObj.totalCount = parseInt(response.data.totalCount)
+                    vueObj.pageSize = pageSize
+                    this.loading = false
+                  }).catch(err => {
+                    this.loading = false
+                    this.$message({
+                        message: err,
+                        type: 'error'
+                    })
+                  })
+              },
+              handleImport() {
+                  this.importDialogVisible = true
+              },
+              uploadFinishFunc(){
+                  this.importDialogVisible = false
+                  this.getData()
+              }
+          }
+      }
+  </script>
+  
+  <style scoped>
+  /deep/ .el-dialog__body .el-input {
+    width: 100% !important;
+  }
+  </style>
+  

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

@@ -0,0 +1,245 @@
+<template>
+    <div v-loading="loading">
+      <div class="white-box">
+        <div class="filter-box">
+          <filter-user :filter-types="filterTypes" @select-value="handleFilterUser"></filter-user>
+        </div>
+        <el-table class="table-box" ref="multipleTable" :data="tableData" stripe style="width: 100%;"
+                  @selection-change="handleSelectionChange"
+                  :height="tool.getTableHeight()">
+          <el-table-column type="selection" width="70" v-if="tableHeaders"></el-table-column>
+          <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''" :prop="tableHeader.other.prop ? tableHeader.other.prop : null">
+            <template slot-scope="scope">
+              <template v-if="scope.row[tableHeader.index].other.tag" >
+                <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null" >{{scope.row[tableHeader.index].value}}</el-tag>
+              </template>
+              <template v-else>
+                <div v-html="scope.row[tableHeader.index].value"></div>
+              </template>
+            </template>
+          </el-table-column>
+          <el-table-column :fixed="fixedColumn" :label="$t('common.action')" width="180">
+           <template slot-scope="scope">
+              <el-dropdown size="small" trigger="click">
+                <el-button type="primary" size="small" @click.stop="">
+                  {{ $t('common.action') }}<i class="el-icon-arrow-down el-icon--right"></i>
+                </el-button>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item command="edit" @click.native="handleDel(scope.row)" v-if="permission.hasPermission(`shop/edit`)">{{ $t('shop.deleteOrder') }}</el-dropdown-item>
+                  <!-- <el-dropdown-item command="edit" @click.native="handleEdit(scope.row)" v-if="permission.hasPermission(`shop/edit`)">Edit order&lt;!&ndash; 编辑订单 &ndash;&gt;</el-dropdown-item>
+                  <el-dropdown-item command="delivery" @click.native="handleShowDeliveryDialog(scope.row)" v-if="permission.hasPermission(`shop/order-delivery`) && scope.row['STATUS'] === '1' && scope.row['DELIVERY_STATUS'] === '0' ">deliver goods&lt;!&ndash; 发货 &ndash;&gt;</el-dropdown-item>
+                  <el-dropdown-item command="refund" @click.native="handleRefund(scope.row.SN)" v-if="permission.hasPermission(`shop/order-delivery`) && scope.row['PAY_TYPE'] === 'pay_stack' && scope.row['STATUS'] === '1' && scope.row['DELIVERY_STATUS'] === '0' ">Refund&lt;!&ndash; 退款 &ndash;&gt;</el-dropdown-item> -->
+                </el-dropdown-menu>
+              </el-dropdown>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="white-box-footer">
+          <el-button type="success" size="small" @click="handleExport" v-show="permission.hasPermission(`shop/order-list-export`)">{{ $t('common.exportExcel') }}</el-button>
+          <el-button type="primary" size="small" @click="handleExportPDF" v-show="permission.hasPermission(`shop/order-list-export`)">{{ $t('common.exportPDF') }}</el-button>
+          <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange"
+                      @current-change="handleCurrentChange"></pagination>
+        </div>
+      </div>
+      <el-dialog :title="$t('shop.deliverGoods')" :visible.sync="dialogDeliveryVisible"><!-- 发货 -->
+        <el-form :model="deliveryForm" label-width="150px" class="form-dialog">
+          <el-form-item :label="$t('shop.courierCompany')"><!-- 快递公司 -->
+            <el-input v-model="deliveryForm.expressCompany"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('shop.courierNumber')"><!-- 快递单号 -->
+            <el-input v-model="deliveryForm.orderTrackNo"></el-input>
+          </el-form-item>
+        </el-form>
+        <div slot="footer" class="dialog-footer">
+          <el-button @click="dialogDeliveryVisible = false">{{ $t('table.cancel') }}<!-- 取 消 --></el-button>
+          <el-button type="primary" @click.native="handleDelivery">{{ $t('shop.deliverGoods') }}<!-- 发货 --></el-button>
+        </div>
+      </el-dialog>
+    </div>
+  </template>
+  
+  <script>
+  import {getOperatingSystem} from "@/utils"
+  import tool from '@/utils/tool'
+  import FilterUser from '@/components/FilterUser'
+  import permission from '@/utils/permission'
+  import Pagination from '@/components/Pagination'
+  import filterHelper from '@/utils/filterHelper'
+  import { orderList, orderListExport, orderListExportPdf, deleteOrder } from '@/api/shop'
+  
+  export default {
+    name: 'shop_order-list',
+    components: {FilterUser, Pagination},
+    mounted () {
+      let system =  getOperatingSystem()
+      if (system == "Android" || system == 'ios') {
+        this.fixedColumn = false
+      } else {
+        this.fixedColumn = 'right'
+      }
+      this.getData()
+    },
+    data () {
+      return {
+        fixedColumn:false, // 固定,当手机端不固定,pc固定
+        tableHeaders: null,
+        tableData: null,
+        tableHeight: window.innerHeight - 310,
+        loading: true,
+        multipleSelection: [],
+        currentPage: 1,
+        totalPages: 1,
+        totalCount: 1,
+        pageSize: 20,
+        tool: tool,
+        permission: permission,
+        filterTypes: null,
+        filterModel: {},
+        dialogDeliveryVisible: false,
+        deliveryForm: {
+          sn: '',
+          expressCompany: '',
+          orderTrackNo: '',
+        },
+      }
+    },
+    methods: {
+      handleSelectionChange (val) {
+        this.multipleSelection = val
+      },
+      handleCurrentChange (page) {
+        this.getData(page, this.pageSize)
+      },
+      handleSizeChange (pageSize) {
+        this.getData(this.currentPage, pageSize)
+      },
+      handleFilterUser (filterData) {
+        filterHelper.handleFilterUser(this, filterData)
+      },
+      getData (page, pageSize) {
+        let filterData = this.filterModel
+        let vueObj=this
+        const paramsData = Object.assign({
+        page: (page === null || page == undefined) ? 1 : page,
+        pageSize: (pageSize === null || pageSize == undefined) ? vueObj.pageSize : pageSize
+        }, filterData)
+        orderList(paramsData).then(response => {
+            vueObj.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+            vueObj.tableData = response.data.list
+            vueObj.filterTypes = response.data.filterTypes
+            vueObj.currentPage = page
+            vueObj.totalPages = parseInt(response.data.totalPages)
+            vueObj.totalCount = parseInt(response.data.totalCount)
+            vueObj.pageSize = pageSize
+            this.loading = false
+        }).catch(err =>{
+            this.loading = false
+            this.$message({
+                message: err,
+                type: 'error'
+            })
+        })
+      },
+      handleExport (){
+        this.$confirm(this.$t('financial.exportNotice'), this.$t('common.hint'), {//`确定要导出当前数据吗?`, '提示'
+          confirmButtonText: this.$t('common.confirm'), // 确定
+          cancelButtonText: this.$t('common.cancel'), // 取消
+          type: 'warning'
+        }).then(() => {
+            orderListExport(this.filterModel).then(response => {
+                this.$message({
+                    message: response.data,
+                    type: 'success'
+                })
+            }).catch(err => {
+                this.$message({
+                    message: err,
+                    type: 'error'
+                })
+            })
+        })
+      },
+      handleExportPDF () {
+        if (this.multipleSelection.length === 0) {
+          this.$message({
+            message: this.$t('shop.selectOrderExportNotice'), // 请选择一条订单导出
+            type: 'error'
+          })
+          return false
+        }
+  
+        // 提取订单ID
+        let orderSnList = this.multipleSelection.map((item) => item.SN.value || '')
+        // 去重
+        let orderSnSet = Array.from(new Set(orderSnList))
+        if (orderSnSet.length !== 1) {
+          this.$message({
+            message: this.$t('shop.pdfOnlyOneOrderExported'), // 每次只能导出一条订单
+            type: 'error'
+          })
+          return false
+        }
+  
+        this.$confirm(this.$t('financial.exportNotice'), this.$t('common.hint'), { // `确定要导出当前数据吗?`, '提示'
+          confirmButtonText: this.$t('common.confirm'), // 确定
+          cancelButtonText: this.$t('common.cancel'), // 取消
+          type: 'info'
+        }).then(() => {
+          // 导出时只需要订单ID即可
+          let orderSn = orderSnSet[0]
+          orderListExportPdf(orderSn).then(response => {
+            this.$message({
+              message: response.data,
+              type: 'success'
+            })
+          }).catch(err => {
+            this.$message({
+                message: err,
+                type: 'error'
+            })
+          })
+        })
+      },
+      handleEdit () {
+        // 进入修改订单页面
+      },
+      handleDel (row) {
+        let orderSn = row.SN.value // order订单表的编号
+        let msg = this.$t('shop.sureDeleteOrder')
+        this.$confirm(`${msg}${orderSn}`, this.$t('common.hint'), {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        }).then(() => {
+          // 删除订单
+          let postData = {
+            orderSn
+          }
+          deleteOrder(postData).then(response => {
+            this.$message({
+              message: response.data,
+              type: 'success'
+            })
+            this.submitButtonStat = false
+            this.$router.go(0)
+          }).catch(err => {
+            this.submitButtonStat = false
+            this.$message({
+              message: err,
+              type: 'error'
+            })
+          })
+        })
+      },
+    }
+  }
+  </script>
+  
+  <style >
+  @media (max-width: 720px) {
+  .el-message-box {
+    width: 320px !important;
+  }
+}
+  </style>
+  

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

@@ -0,0 +1,174 @@
+<template>
+    <div v-loading="loading">
+      <div class="white-box">
+        <div class="filter-box">
+          <filter-user :filter-types="filterTypes" @select-value="handleFilterUser"></filter-user>
+        </div>
+        <el-table class="table-box" ref="multipleTable" :data="tableData" stripe style="width: 100%;"
+                  @selection-change="handleSelectionChange"
+                  :height="tool.getTableHeight()">
+          <el-table-column type="selection" width="70" v-if="tableHeaders"></el-table-column>
+          <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''" :prop="tableHeader.other.prop ? tableHeader.other.prop : null">
+            <template slot-scope="scope">
+              <template v-if="scope.row[tableHeader.index].other.tag" >
+                <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null" >{{scope.row[tableHeader.index].value}}</el-tag>
+              </template>
+              <template v-else>
+                <div v-html="scope.row[tableHeader.index].value"></div>
+              </template>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="white-box-footer">
+          <el-button type="success" size="small" @click="handleImport" v-show="permission.hasPermission(`shop/order-shop-list-import`)">Order import<!-- 订单导入 --></el-button>
+  
+          <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange"
+                      @current-change="handleCurrentChange"></pagination>
+        </div>
+      </div>
+      <el-dialog title="Order import" :visible.sync="importDialogVisible" width="50%"><!-- 订单导入 -->
+        <el-form ref="form" :model="excelForm" style="width: 100%;" class="form-page">
+          <el-form-item label="Current import order date"><!-- 当前导入订单日期 -->
+            <el-date-picker  v-model="excelForm.orderDay" type="date" placeholder="Select date"  value-format="yyyy-MM-dd"><!-- 选择日期 -->
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item label="Current import order type"><!-- 当前导入订单类型 -->
+            <el-select v-model="excelForm.orderType" placeholder="Please select order type" style="width: 400px;"><!-- 请选择订单类型 -->
+              <el-option label="Resale order" value="cash" :key="1"></el-option><!-- 复销订单 -->
+              <el-option label="Points order" value="point" :key="2"></el-option><!-- 积分订单 -->
+            </el-select>
+          </el-form-item>
+          <el-form-item v-show="false" label="Current import order periods"><!-- 当前导入订单期数 -->
+            <el-input v-model="excelForm.periodNum"></el-input>
+          </el-form-item>
+          <el-form-item label="Total rows of Excel file"><!-- Excel 文件总行数 -->
+            <el-input v-model="excelForm.rowCount"></el-input>
+          </el-form-item>
+          <el-form-item>
+            <leo-excel-uploader
+              :request-upload-route="`v1/file/upload-excel`"
+              :request-import-to-excel-table-route="`shop/import-order-shop-to-excel-table`"
+              :request-import-excel-table-to-data-route="`shop/import-order-shop`"
+              :import-row-count="excelForm.rowCount"
+              :other-params="excelForm"
+              :finish-callback-func="uploadFinishFunc"
+              excel-option="addUser"
+              upload-btn-title="Excel import"
+              style="float: left;"
+            ></leo-excel-uploader><!-- Excel导入 -->
+            </el-form-item>
+        </el-form>
+      </el-dialog>
+    </div>
+  </template>
+  
+  <script>
+    import tool from '@/utils/tool'
+    import FilterUser from '@/components/FilterUser'
+    import permission from '@/utils/permission'
+    import LeoExcelUploader from '@/components/ExcelUploader'
+    import Pagination from '@/components/Pagination'
+    import filterHelper from '@/utils/filterHelper'
+    import { orderShopList } from '@/api/shop'
+  
+    export default {
+      name: 'shop_order_shop-list',
+      components: {FilterUser, Pagination, LeoExcelUploader},
+      mounted() {
+        this.initData()
+        this.getData()
+      },
+      data() {
+        return {
+          tableHeaders: null,
+          tableData: null,
+          tableHeight: window.innerHeight - 310,
+          loading: true,
+          multipleSelection: [],
+          currentPage: 1,
+          totalPages: 1,
+          totalCount: 1,
+          pageSize: 20,
+          tool: tool,
+          permission: permission,
+          filterTypes: null,
+          filterModel: {},
+          dialogDeliveryVisible: false,
+          deliveryForm: {
+            sn: '',
+            expressCompany: '',
+            orderTrackNo: '',
+          },
+          excelForm: {
+            rowCount: 0,
+            orderType: '',
+            periodNum: 0,
+            orderDay: 0,
+          },
+          importDialogVisible:false,
+        }
+      },
+      methods: {
+        handleSelectionChange(val) {
+          this.multipleSelection = val
+        },
+        handleCurrentChange(page) {
+          this.getData(page, this.pageSize)
+        },
+        handleSizeChange(pageSize) {
+          this.getData(this.currentPage, pageSize)
+        },
+        handleFilterUser(filterData) {
+          filterHelper.handleFilterUser(this, filterData)
+        },
+        initData(){
+          let myDate = new Date();
+          let thisYear = myDate.getFullYear();
+          let thisMonth = myDate.getMonth() + 1 < 10 ? '0' + (myDate.getMonth() + 1) : myDate.getMonth() + 1
+          let thisDate = myDate.getDate() < 10 ? '0' + (myDate.getDate()) : myDate.getDate()
+          this.excelForm.orderDay = thisYear + '-' + thisMonth + '-' + thisDate
+        },
+        getData(page, pageSize) {
+          let filterData = this.filterModel
+          let vueObj=this
+          const paramsData = Object.assign({
+            page: (page === null || page == undefined) ? 1 : page,
+            pageSize: (pageSize === null || pageSize == undefined) ? vueObj.pageSize : pageSize
+            }, filterData)
+            orderShopList(paramsData).then(response => {
+                vueObj.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+                vueObj.tableData = response.data.list
+                vueObj.filterTypes = response.data.filterTypes
+                vueObj.currentPage = page
+                vueObj.totalPages = parseInt(response.data.totalPages)
+                vueObj.totalCount = parseInt(response.data.totalCount)
+                vueObj.pageSize = pageSize
+                this.loading = false
+            }).catch(err => {
+                this.loading = false
+                this.$message({
+                    message: err,
+                    type: 'error'
+                })
+            })
+        },
+        handleImport() {
+          this.importDialogVisible = true
+        },
+        uploadFinishFunc(){
+          this.importDialogVisible = false
+          this.getData()
+        }
+      }
+    }
+  </script>
+  
+  <style scoped>
+  /deep/ .el-dialog__body .el-input {
+    width: 100% !important;
+  }
+  /deep/ .el-dialog__body .el-select {
+    width: 100% !important;
+  }
+  </style>
+  

+ 113 - 0
src/views/shop/remain-pv.vue

@@ -0,0 +1,113 @@
+<template>
+    <div v-loading="loading">
+      <div class="white-box">
+        <div class="filter-box">
+          <filter-user :filter-types="filterTypes" @select-value="handleFilterUser"></filter-user>
+        </div>
+        <el-table class="table-box" ref="multipleTable" :data="tableData" stripe style="width: 100%;" :height="tool.getTableHeight()">
+          <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :prop="tableHeader.other.prop ? tableHeader.other.prop : null">
+            <template slot-scope="scope">
+              <template v-if="scope.row[tableHeader.index].other.tag" >
+                <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null" >{{scope.row[tableHeader.index].value}}</el-tag>
+              </template>
+              <template v-else>
+                <div v-html="scope.row[tableHeader.index].value"></div>
+              </template>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="white-box-footer">
+          <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange"></pagination>
+        </div>
+      </div>
+    </div>
+  </template>
+  
+  <script>
+  import tool from '@/utils/tool'
+  import baseInfo from '@/utils/baseInfo'
+  import FilterUser from '@/components/FilterUser'
+  import permission from '@/utils/permission'
+  import Pagination from '@/components/Pagination'
+  import filterHelper from '@/utils/filterHelper'
+  import { remainPv } from '@/api/shop'
+  
+  export default {
+    name: 'shop_remain-pv',
+    components: {FilterUser, Pagination},
+    mounted () {
+      this.getData()
+    },
+    data () {
+      return {
+        tableHeaders: null,
+        tableData: null,
+        loading: true,
+        multipleSelection: [],
+        currentPage: 1,
+        totalPages: 1,
+        totalCount: 1,
+        pageSize: 20,
+        tool: tool,
+        permission: permission,
+        baseDecLevels: baseInfo.decLevels(),
+        baseEmpLevels: baseInfo.empLevels(),
+        filterTypes: null,
+        filterModel: {}
+      }
+    },
+    methods: {
+      handleCurrentChange (page) {
+        this.getData(page, this.pageSize)
+      },
+      handleSizeChange (pageSize) {
+        this.getData(this.currentPage, pageSize)
+      },
+      handleFilterUser (filterData) {
+        filterHelper.handleFilterUser(this, filterData)
+      },
+      getData (page, pageSize) {
+        let filterData = this.filterModel
+        let vueObj=this
+        const paramsData = Object.assign({
+        page: (page === null || page == undefined) ? 1 : page,
+        pageSize: (pageSize === null || pageSize == undefined) ? vueObj.pageSize : pageSize
+        }, filterData)
+        remainPv(paramsData).then(response => {
+            vueObj.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+            vueObj.tableData = response.data.list
+            vueObj.filterTypes = response.data.filterTypes
+            vueObj.currentPage = page
+            vueObj.totalPages = parseInt(response.data.totalPages)
+            vueObj.totalCount = parseInt(response.data.totalCount)
+            vueObj.pageSize = pageSize
+            this.loading = false
+        }).catch(err => {
+            this.loading = false
+            this.$message({
+                message: err,
+                type: 'error'
+            })
+        })
+        
+        // network.getPageData(this, 'shop/remain-pv', page, pageSize, this.filterModel, response => {
+        //   this.filterTypes = response.filterTypes
+        // })
+      }
+    }
+  }
+  
+  </script>
+  
+  <style scoped>
+    .table-box .el-form-item__label {
+      width: 100px;
+      color: #99a9bf;
+    }
+    .table-box .el-form-item {
+      width: 30%;
+      margin-right: 0;
+      margin-bottom: 0;
+    }
+  </style>
+  

+ 222 - 0
src/views/user/dec-level-list.vue

@@ -0,0 +1,222 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <div class="filter-box">
+        <filter-user ref="filterUser" :filter-types="filterTypes" @select-value="handleFilterUser"></filter-user>
+      </div>
+
+      <el-table :data="tableData" stripe style="width: 100%;">
+        <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header">
+          <template slot-scope="{row}">
+            <template v-if="row[tableHeader.index].other.tag">
+							<el-tag :type="row[tableHeader.index].other.tag.type ? row[tableHeader.index].other.tag.type : null" :size="row[tableHeader.index].other.tag.size ? row[tableHeader.index].other.tag.size : null" :class="row[tableHeader.index].other.tag.class ? row[tableHeader.index].other.tag.class : null" >
+								<span style="word-break: keep-all; word-wrap: break-word; white-space: pre-wrap;">{{ row[tableHeader.index].value }}</span>
+							</el-tag>
+						</template>
+            <template v-else-if="row[tableHeader.index].other.progress">
+              <el-progress type="circle" :percentage="Number.parseInt(percentList['MOVE_PERCENT'][row.ID])" :width="50" :stroke-width="3"></el-progress>
+            </template>
+            <template v-else>
+              <div v-html="row[tableHeader.index].value"></div>
+            </template>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="white-box-footer">
+        <el-button type="primary" size="small" @click="dialog = true" icon="el-icon-plus" v-show="permission.hasPermission(`user/change-user-dec-level`)">{{ $t('member.modifyMemberLevel') }}</el-button>
+
+				<pagination v-show="total>0" :total="total" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+      </div>
+    </div>
+
+    <!-- 修改会员级别	-->
+		<el-dialog :title="$t('member.modifyMemberLevel')" :visible.sync="dialog" :width="screenWidth" style="margin-top: -80px">
+			<el-form ref="form" :model="form" label-width="150px" :label-position="labelPosition">
+				<el-form-item :label="$t('member.memberCode')">
+					<el-input v-model.trim="form.userName" @change="handleChange"></el-input>
+					<el-tag style="margin-top: 15px;" v-show="userInfo.REAL_NAME!==null">{{ $t('member.memberName') }}:{{ userInfo.REAL_NAME }} {{ $t('member.currentLevel') }}:{{ userInfo.LEVEL_NAME }}</el-tag>
+				</el-form-item>
+				<el-form-item :label="$t('member.entryLevel')">
+					<el-select v-model="form.levelId" :placeholder="$t('member.selectEntryLevelHint')">
+						<el-option v-for="(item,key) in allDecLevel" :label="item.LEVEL_NAME" :value="item.ID" :key="key"></el-option>
+					</el-select>
+				</el-form-item>
+				<el-form-item :label="$t('member.remark')">
+					<el-input type="textarea" :rows="2" placeholder="" v-model="form.remark">
+					</el-input>
+				</el-form-item>
+				<el-form-item>
+					<el-button type="primary" :loading="submitButtonStat" @click="onSubmit">{{ $t('common.confirm') }}</el-button>
+				</el-form-item>
+			</el-form>
+		</el-dialog>
+  </div>
+</template>
+
+<script>
+	import FilterUser from '@/components/FilterUser'
+	import baseInfo from '@/utils/baseInfo'
+	import permission from '@/utils/permission'
+	import Pagination from '@/components/Pagination'
+	import filterHelper from '@/utils/filterHelper'
+	import {getScreenWidth} from "@/utils";
+	import {fetchEntryLevelList, fetchMemberFullInfo, updateUserEntryLevel} from "@/api/member";
+	import tool from "@/utils/tool";
+
+	export default {
+		name: 'decLevelList',
+		components: {FilterUser,Pagination},
+		mounted() {
+			this.getData()
+		},
+		data() {
+			return {
+				tableHeaders: null,
+				tableData: null,
+				loading: false,
+				tool: tool,
+				permission: permission,
+				allDecLevel: baseInfo.decLevels(),
+				filterTypes: {},
+				filterModel: {},
+				filterStatus: '0',
+				total: 0,
+				page: 1,
+				pageSize: 20,
+				currentPage: 1,
+
+				screenWidth: getScreenWidth() > 500 ? '500px' : getScreenWidth() + 'px',
+				labelPosition: getScreenWidth() >= 500 ? 'right' : 'top',
+
+				submitButtonStat: false,
+				dialog: false,
+				form: {
+					userName: null,
+					periodNum: null,
+					levelId: null,
+					remark: null,
+				},
+				userInfo: {
+					REAL_NAME: null,
+					DEC_LV: null,
+				},
+			}
+		},
+		methods: {
+			handleChange() {
+				this.submitButtonStat = true
+				fetchMemberFullInfo({ userName: this.form.userName }).then(response => {
+					this.userInfo = response.data
+					this.submitButtonStat = false
+				}).catch(error => {
+					this.userInfo.REAL_NAME = null
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+					this.submitButtonStat = false
+				})
+			},
+			handleFilterUser(filterData) {
+				filterHelper.handleFilterUser(this, filterData)
+			},
+			handleCurrentChange(page) {
+				this.getData(page, this.pageSize)
+			},
+			handleSizeChange(pageSize) {
+				this.getData(this.currentPage, pageSize)
+			},
+			getData(page, pageSize) {
+				this.loading = true
+				const paramsData = Object.assign({
+					page: (page === null || page == undefined) ? 1 : page,
+					pageSize: (pageSize === null || pageSize == undefined) ? this.pageSize : pageSize
+				}, this.filterModel)
+				fetchEntryLevelList(paramsData).then(response => {
+					this.filterTypes = response.data.filterTypes
+					this.tableData = response.data.list
+					this.total = +response.data.totalCount
+					this.currentPage = page
+					this.pageSize = pageSize
+					this.filterTypes = response.data.filterTypes
+					this.tableHeaders = response.data.columnsShow
+
+					this.loading = false
+				}).catch(error => {
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+					this.loading = false
+				})
+			},
+			onSubmit() {
+				this.$confirm(this.$t('member.modifyMemberEntryLevelHits'), this.$t('common.hint'), {
+					confirmButtonText: this.$t('common.confirm'),
+					cancelButtonText: this.$t('common.cancel'),
+					type: 'warning'
+				}).then(() => {
+					this._handleSubmit()
+				}).catch(error => {
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+				})
+			},
+			_handleSubmit() {
+				this.submitButtonStat = true
+				updateUserEntryLevel(this.form).then(response => {
+					this.$message({
+						message: response.data,
+						type: 'success'
+					})
+
+					setTimeout(() => {
+						this.submitButtonStat = false
+					}, 0.5 * 1000)
+
+					this.submitButtonStat = false
+					this._clearData()
+					this.dialog = false
+					this.getData()
+				}).catch(error => {
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+
+					this.submitButtonStat = false
+				})
+			},
+			_clearData(){
+				this.form = {
+					userName: null,
+					periodNum: null,
+					levelId: null,
+					remark: null,
+				}
+				this.userInfo= {
+					REAL_NAME: null,
+					DEC_LV: null,
+				}
+			},
+		}
+	}
+</script>
+
+<style>
+.app-main {
+	padding: 15px;
+}
+.app-container {
+	padding: 0;
+}
+.white-box {
+	padding: 15px;
+}
+.form-page {
+	width: 100%;
+}
+</style>

+ 299 - 0
src/views/user/empty-order-operation.vue

@@ -0,0 +1,299 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <el-tabs v-model="tabActiveName">
+        <el-tab-pane :label="$t('member.addManually')" name="first" v-if="permission.hasPermission(`user/user-add`)">
+          <el-form ref="form" :model="form" label-width="250px" :label-position="labelPosition">
+
+            <div class="hr-tip"><span>{{ $t('member.accountInformation') }}</span></div>
+
+            <el-form-item :label="$t('member.memberCode')" required>
+              <el-input v-model="form.userName"></el-input>
+            </el-form-item>
+            <el-form-item :label="$t('member.entryLevel')" required>
+              <el-select v-model="form.decLv" :placeholder="$t('member.selectEntryLevelHint')">
+                <el-option v-for="(item,index) in allDecLevel" :key="index" :label="item.LEVEL_NAME" :value="item.ID"></el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item :label="$t('member.stockistOrNot')">
+              <el-switch v-model="form.isDec"></el-switch>
+            </el-form-item>
+            <el-form-item :label="$t('member.stockistLevel')" v-show="form.isDec">
+              <el-select v-model="form.decRoleId" :placeholder="$t('member.pleaseSelectStockistLevel')">
+                <el-option v-for="(item,index) in allDecRole" :key="index" :label="item.ROLE_NAME" :value="item.ID"></el-option>
+              </el-select>
+            </el-form-item>
+
+            <div class="hr-tip"><span>{{ $t('member.networkInformation') }}</span></div>
+
+            <el-form-item :label="$t('member.stockistNo')" required>
+              <el-tooltip class="item" effect="dark" :content="$t('member.autoDetectMember')" placement="top-start">
+                <el-input v-model="form.decUserName" @change="handleChkDecUser">
+                  <template slot="append">【{{ decRealName }}】</template>
+                </el-input>
+              </el-tooltip>
+            </el-form-item>
+            <el-form-item :label="$t('member.contactPerson')" required>
+              <el-input v-model="form.conUserName" @change="handleChkConUser">
+                <template slot="append">【{{ conRealName }}】</template>
+              </el-input>
+            </el-form-item>
+            <el-form-item :label="$t('member.resettlementLocation')" required>
+              <el-radio-group v-model="form.location">
+                <el-radio-button :label="1">{{ $t('member.left') }}</el-radio-button>
+                <el-radio-button :label="2">{{ $t('member.right') }}</el-radio-button>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item :label="$t('member.sponsor')" required>
+              <el-input v-model="form.recUserName" @change="handleChkRecUser">
+                <template slot="append">【{{ recRealName }}】</template>
+              </el-input>
+            </el-form-item>
+
+            <div class="hr-tip"><span>{{ $t('member.personalData') }}</span></div>
+
+            <el-form-item :label="$t('member.memberName')" required>
+              <el-input v-model="form.realName"></el-input>
+            </el-form-item>
+            <el-form-item :label="$t('member.phoneNumber')">
+              <el-input v-model="form.mobile" maxlength="11"></el-input>
+            </el-form-item>
+
+            <el-collapse style="margin-bottom: 20px;">
+							<el-collapse-item :title="$t('member.otherInformation')" name="1">
+                <div class="hr-tip"><span>{{ $t('member.bankInformation') }}</span></div>
+
+                <el-form-item :label="$t('member.bankName')">
+                  <el-select v-model="form.openBank" :placeholder="$t('member.selectBankDeposit')">
+                    <el-option v-for="(item,index) in allOpenBank" :key="index" :label="item.BANK_NAME" :value="item.BANK_CODE"></el-option>
+                  </el-select>
+                </el-form-item>
+								<el-form-item :label="$t('member.bankRegion')" prop="bankAreaSelected">
+									<el-cascader size="large" :options="regionData" v-model="form.bankAreaSelected"></el-cascader>
+								</el-form-item>
+                <el-form-item :label="$t('member.subBankName')">
+                  <el-input v-model="form.bankAddress"></el-input>
+                </el-form-item>
+                <el-form-item :label="$t('member.bankAccount')">
+                  <el-input v-model="form.bankNo" maxlength="19"></el-input>
+                </el-form-item>
+
+              </el-collapse-item>
+            </el-collapse>
+            <el-form-item>
+              <el-button type="primary" @click="onSubmit" :loading="submitButtonStat">{{ $t('common.submit') }}</el-button>
+            </el-form-item>
+          </el-form>
+        </el-tab-pane>
+      </el-tabs>
+    </div>
+  </div>
+</template>
+
+<script>
+  import baseInfo from '@/utils/baseInfo'
+  import permission from '@/utils/permission'
+	import {getScreenWidth} from "@/utils"
+	import region from "@/store/modules/region"
+	import {fetchMemberFullInfo, fetchUserAdd, updateUserAdd} from "@/api/member"
+
+  export default {
+    name: 'emptyOrderOperation',
+    mounted() {
+      this.getData()
+    },
+    data() {
+      return {
+        form: {
+          userName: '',
+          nation: '',
+          realName: '',
+          idCard: '',
+          mobile: '',
+          address: '',
+          openBank: '',
+          bankAddress: '',
+          bankNo: '',
+          bankAreaSelected: [],
+          decLv: '',
+          areaSelected: [],
+          tel: '',
+          subComId: '',
+          isDec: false,
+          decUserName: '',
+          birthday: '',
+          decRoleId: '',
+          conUserName: '',
+          recUserName: '',
+          location: 1,
+        },
+        decRealName: '-',
+        conRealName: '-',
+        recRealName: '-',
+        excelForm: {
+          rowCount: 0,
+        },
+        loading: false,
+        tabActiveName: 'first',
+        submitButtonStat: false,
+        importButtonStat: false,
+        allNation: null,
+        allOpenBank: null,
+        regionData: region.regionInfo.regionData,
+        allDecLevel: baseInfo.decLevels(),
+        allDecRole: [],
+        delForm: {
+          delUserName: ''
+        },
+        userInfo: {
+          REAL_NAME: '',
+          DEC_USER_NAME: '',
+          DEC_REAL_NAME: '',
+          CON_USER_NAME: '',
+          CON_REAL_NAME: '',
+          LOCATION: '',
+          REC_USER_NAME: '',
+          REC_REAL_NAME: '',
+        },
+        delButtonStat: false,
+        delButtonDisabled: true,
+        permission: permission,
+				screenWidth: getScreenWidth() > 650 ? '650px' : getScreenWidth() + 'px',
+				labelPosition: getScreenWidth() >= 600 ? 'right' : 'top',
+      }
+    },
+    methods: {
+      getData() {
+        if (permission.hasPermission(`user/user-del`)) {
+          this.tabActiveName = 'third'
+        }
+        if (permission.hasPermission(`user/import-users-to-excel-table`) && permission.hasPermission(`user/import-users-add`)) {
+          this.tabActiveName = 'second'
+        }
+        if (permission.hasPermission(`user/user-add`)) {
+          this.tabActiveName = 'first'
+					this.loading = true
+					fetchUserAdd().then(response => {
+						this.loading = false
+						this.allNation = response.data.allNation
+						this.allOpenBank = response.data.allOpenBank
+						this.allDecRole = response.data.allDecRole
+						this.form.userName = response.data.userName
+					}).catch(error => {
+						this.$message({
+							message: error,
+							type: 'warning'
+						})
+						this.loading = false
+					})
+        } else {
+          this.loading = false
+        }
+      },
+      onSubmit() {
+        this.submitButtonStat = true
+				updateUserAdd(this.form).then(response => {
+					this.submitButtonStat = false
+
+					this.$message({
+						message: response.data,
+						type: 'success'
+					})
+				}).catch(error => {
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+					this.submitButtonStat = false
+				})
+      },
+      handleChkDecUser() {
+        if (this.form.decUserName) {
+          this.loading = true
+					fetchMemberFullInfo({ userName: this.form.decUserName }).then(response => {
+						this.decRealName = response.data.REAL_NAME
+						this.loading = false
+					}).catch(error => {
+						this.$message({
+							message: error,
+							type: 'warning'
+						})
+						this.loading = false
+					})
+        }
+      },
+      handleChkConUser() {
+        if (this.form.conUserName) {
+					this.loading = true
+					fetchMemberFullInfo({ userName: this.form.conUserName }).then(response => {
+						this.conRealName = response.data.REAL_NAME
+						this.loading = false
+					}).catch(error => {
+						this.$message({
+							message: error,
+							type: 'warning'
+						})
+						this.loading = false
+					})
+        }
+      },
+      handleChkRecUser() {
+        if (this.form.recUserName) {
+					this.loading = true
+					fetchMemberFullInfo({ userName: this.form.recUserName }).then(response => {
+						this.recRealName = response.data.REAL_NAME
+						this.loading = false
+					}).catch(error => {
+						this.$message({
+							message: error,
+							type: 'warning'
+						})
+						this.loading = false
+					})
+        }
+      },
+    }
+  }
+</script>
+
+<style>
+.app-main {
+	padding: 15px;
+}
+.app-container {
+	padding: 0;
+}
+.white-box {
+	padding: 15px;
+}
+.form-page {
+	width: 100%;
+}
+  .hr-tip {
+    font-size: 12px;
+    position: relative;
+    text-align: center;
+    height: 30px;
+    line-height: 30px;
+    color: #999;
+    margin-bottom: 20px;
+  }
+
+  .hr-tip:before {
+    content: '';
+    display: block;
+    position: absolute;
+    left: 0;
+    right: 0;
+    top: 14px;
+    border-bottom: 1px dashed #ddd;
+    height: 1px;
+  }
+
+  .hr-tip span {
+    display: inline-block;
+    background: #fff;
+    position: relative;
+    padding: 0 10px;
+  }
+</style>

+ 552 - 107
src/views/user/member-list.vue

@@ -1,121 +1,566 @@
 <template>
-  <div class="app-container">
-    <el-table v-loading="loading" fit lazy highlight-current-row :data="memberData">
-      <!--			<el-table-column fixed type="selection" width="55" v-if="tableHeaders"></el-table-column>-->
-      <el-table-column
-        v-for="(tableHeader, key) in tableHeaders"
-        :key="key"
-        :label="tableHeader.header"
-        :width="tableHeader.other.width ? tableHeader.other.width : ''"
-        :fixed="tableHeader.index == 'USER_NAME' || tableHeader.index == 'REAL_NAME' ? true : false"
-      >
-        <template slot-scope="scope">
-          <template v-if="scope.row[tableHeader.index].other.tag">
-            <el-tag
-              :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null"
-              :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null"
-              :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null"
-            >
-              {{ scope.row[tableHeader.index].value }}
-            </el-tag>
-          </template>
-          <template v-else>
-            <template v-if="tableHeader.index === 'USER_NAME'">
-              <el-dropdown v-if="permission.hasPermission(`user/login-to-frontend`)">
-                <span class="el-dropdown-link">
-                  {{ scope.row.USER_NAME.value }} <i class="el-icon-arrow-down el-icon--right" />
-                </span>
-                <el-dropdown-menu slot="dropdown">
-                  <el-dropdown-item v-show="scope.row.BTF_URL !== null" command="login">
-                    <a
-                      :href="`${frontendServer}/#/login-by-backend?${scope.row.BTF_URL}`"
-                      target="_blank"
-                      style="color:#606266;"
-                    >Quick logon<!-- 快速登录 --></a>
-                  </el-dropdown-item>
-                </el-dropdown-menu>
-              </el-dropdown>
-              <el-tag
-                v-if="!permission.hasPermission(`user/login-to-frontend`)"
-                type="primary"
-                size="small"
-                class="no-border"
-              >{{ scope.row.USER_NAME.value }}
-              </el-tag>
-            </template>
-            <template v-else>
-              <div v-html="scope.row[tableHeader.index].value" />
-            </template>
-          </template>
-        </template>
-      </el-table-column>
-    </el-table>
-
-    <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.pageSize" @pagination="getMemberList" />
-  </div>
+	<div v-loading="loading">
+		<div class="white-box">
+			<!-- 功能搜索 -->
+			<div class="filter-box">
+				<filter-user :filter-types="filterTypes" @select-value="handleFilterUser"></filter-user>
+			</div>
+
+			<!-- 列表展示 -->
+			<el-table ref="wrapper" :data="tableData" stripe style="width: 100%;" @selection-change="handleSelectionChange" :height="tool.getTableHeight()">
+				<el-table-column :fixed="leftFixed" type="selection" width="55" v-if="tableHeaders"></el-table-column>
+				<el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''" :fixed="tableHeader.index == 'USER_NAME' || tableHeader.index == 'REAL_NAME' ? leftFixed : false">
+					<template slot-scope="scope">
+						<template v-if="scope.row[tableHeader.index].other.tag">
+							<el-tag
+								:type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null"
+								:size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null"
+								:class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null">
+								{{scope.row[tableHeader.index].value}}
+							</el-tag>
+						</template>
+						<template v-else>
+							<template v-if="tableHeader.index === 'USER_NAME'">
+								<el-dropdown v-if="permission.hasPermission(`user/login-to-frontend`)">
+									<span class="el-dropdown-link">
+										{{scope.row.USER_NAME.value}} <i class="el-icon-arrow-down el-icon--right"></i>
+									</span>
+									<el-dropdown-menu slot="dropdown">
+										<el-dropdown-item command="login" v-show="scope.row.BTF_URL !== null">
+											<a :href="`${frontendServer}/#/login-by-backend?${scope.row.BTF_URL}`" target="_blank" style="color:#606266;">{{ $t('member.quickLogon') }}</a>
+										</el-dropdown-item>
+									</el-dropdown-menu>
+								</el-dropdown>
+								<el-tag type="primary" size="small" class="no-border" v-if="!permission.hasPermission(`user/login-to-frontend`)">{{ scope.row.USER_NAME.value }}</el-tag>
+							</template>
+							<template v-else>
+								<div v-html="scope.row[tableHeader.index].value"></div>
+							</template>
+						</template>
+					</template>
+				</el-table-column>
+				<el-table-column :fixed="fixed" :label="$t('common.action')" width="180">
+					<template slot-scope="{row}">
+						<el-dropdown size="small" trigger="click">
+							<el-button type="primary" size="small" @click.stop="">{{ $t('common.action') }}<i class="el-icon-arrow-down el-icon--right"></i></el-button>
+							<el-dropdown-menu slot="dropdown">
+								<el-dropdown-item @click.native="handleModifyPassword(row)" v-if="permission.hasPermission(`user/modify-password`)">{{ $t('member.changePassword') }}</el-dropdown-item>
+								<el-dropdown-item @click.native="handleModifyProfile(row)" v-if="permission.hasPermission(`user/modify-profile`)">{{ $t('member.modifyPersonalData') }}</el-dropdown-item>
+								<el-dropdown-item @click.native="handleStatusActive(row)" v-if="permission.hasPermission(`user/modify-status`)">{{ $t('member.statusActivation') }}</el-dropdown-item>
+								<el-dropdown-item @click.native="handleStatusLock(row)" v-if="permission.hasPermission(`user/modify-status`)">{{ $t('member.statusLock') }}</el-dropdown-item>
+								<el-dropdown-item @click.native="handleIsModifyPassword(row, 1)" v-if="permission.hasPermission(`user/is-modify-password-status`)">{{ $t('member.openPasswordModification') }}</el-dropdown-item>
+								<el-dropdown-item @click.native="handleIsModifyPassword(row, 0)" v-if="permission.hasPermission(`user/is-modify-password-status`)">{{ $t('member.turnOffPasswordModification') }}</el-dropdown-item>
+							</el-dropdown-menu>
+						</el-dropdown>
+					</template>
+				</el-table-column>
+			</el-table>
+
+			<!-- 快捷功能 -->
+			<div class="white-box-footer">
+				<el-dropdown size="small" trigger="click" v-show="permission.hasPermission(`user/is-dec`)" style="margin: 5px;">
+					<el-button type="primary" size="small" @click.stop="">
+						{{ $t('member.stockistManagement') }}<i class="el-icon-arrow-down el-icon--right"></i>
+					</el-button>
+					<el-dropdown-menu slot="dropdown">
+						<el-dropdown-item command="isDec" @click.native="handleIsDecManage(true)">{{ $t('member.setAsStockist') }}</el-dropdown-item>
+						<el-dropdown-item command="notDec" @click.native="handleIsDecManage(false)">{{ $t('member.cancelStockist') }}</el-dropdown-item>
+					</el-dropdown-menu>
+				</el-dropdown>
+
+				<el-dropdown size="small" trigger="click" v-show="permission.hasPermission(`user/is-atlas`)" style="margin: 5px;">
+					<el-button type="primary" size="small" @click.stop="">
+						{{ $t('member.chartManagement') }}<i class="el-icon-arrow-down el-icon--right"></i>
+					</el-button>
+					<el-dropdown-menu slot="dropdown">
+						<el-dropdown-item command="isAtlas" @click.native="handleIsAtlasManage(true)">{{ $t('member.displayChart') }}</el-dropdown-item>
+						<el-dropdown-item command="notAtlas" @click.native="handleIsAtlasManage(false)">{{ $t('member.hiddenChart') }}</el-dropdown-item>
+					</el-dropdown-menu>
+				</el-dropdown>
+
+				<el-dropdown size="small" trigger="click" v-show="permission.hasPermission(`user/is-recharge`)" style="margin: 5px;">
+					<el-button type="primary" size="small" @click.stop="">
+						{{ $t('member.rechargeManagement') }}<i class="el-icon-arrow-down el-icon--right"></i>
+					</el-button>
+					<el-dropdown-menu slot="dropdown">
+						<el-dropdown-item command="isAtlas" @click.native="handleIsRechargeManage(true)">{{ $t('member.displayRecharge') }}</el-dropdown-item>
+						<el-dropdown-item command="notAtlas" @click.native="handleIsRechargeManage(false)">{{ $t('member.hideRecharge') }}</el-dropdown-item>
+					</el-dropdown-menu>
+				</el-dropdown>
+				<el-button type="success" size="small" @click="handleExport" v-show="permission.hasPermission(`user/index-export`)" style="margin: 5px;">{{ $t('member.exportExcel') }}</el-button>
+
+
+				<pagination v-show="totalCount>0" :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+			</div>
+		</div>
+
+		<!-- 修改密码 -->
+		<el-dialog :title="formModifyPassword.typeName" :visible.sync="dialogModifyPasswordVisible" :width="screenWidth">
+			<el-form ref="form" :model="formModifyPassword" label-width="120px" class="form-dialog" :label-position="labelPosition">
+				<el-form-item :label="$t('member.type')">
+					<el-select v-model="formModifyPassword.passwordType" :placeholder="$t('member.selectType')">
+						<el-option v-for="(item,key) in passwordType" :label="item.label" :value="item.type" :key="key"></el-option>
+					</el-select>
+				</el-form-item>
+				<el-form-item :label="$t('member.password')">
+					<el-input :placeholder="$t('member.password')"  v-model="formModifyPassword.password"></el-input>
+				</el-form-item>
+				<el-form-item>
+					<el-button type="primary" @click="handleModifyPasswordSubmit" :loading="submitPasswordButtonStat">{{ $t('common.confirm') }}</el-button>
+				</el-form-item>
+			</el-form>
+		</el-dialog>
+
+		<!-- 修改会员信息 -->
+		<el-dialog :title="formModifyProfile.typeName" :visible.sync="dialogModifyProfileVisible" :width="screenWidth">
+			<el-form ref="form" :model="formModifyProfile" label-width="150px" :label-position="labelPosition">
+				<el-form-item :label="$t('member.memberName')">
+					<el-input v-model="formModifyProfile.realName"></el-input>
+				</el-form-item>
+				<el-form-item :label="$t('member.identityNo')">
+					<el-input v-model="formModifyProfile.idCard"></el-input>
+				</el-form-item>
+				<el-form-item :label="$t('member.phoneNumber')">
+					<el-input v-model="formModifyProfile.mobile"></el-input>
+				</el-form-item>
+				<el-form-item :label="$t('member.bankName')">
+					<el-select v-model="formModifyProfile.openBank" :placeholder="$t('member.selectBankName')">
+						<el-option v-for="(item,index) in allOpenBank" :key="index" :label="item.BANK_NAME" :value="item.BANK_CODE"></el-option>
+					</el-select>
+				</el-form-item>
+				<el-form-item :label="$t('member.bankAddress')">
+					<el-input v-model="formModifyProfile.bankAddress"></el-input>
+				</el-form-item>
+				<el-form-item :label="$t('member.bankAccount')">
+					<el-input v-model="formModifyProfile.bankNo"></el-input>
+				</el-form-item>
+				<el-form-item>
+					<el-button type="primary" @click="handleModifyProfileSubmit" :loading="submitProfileButtonStat">{{ $t('common.confirm') }}</el-button>
+				</el-form-item>
+			</el-form>
+		</el-dialog>
+	</div>
 </template>
 
 <script>
-import waves from '@/directive/waves'
+import tool from '@/utils/tool'
+import baseInfo from '@/utils/baseInfo'
+import FilterUser from '@/components/FilterUser'
+import permission from '@/utils/permission'
 import Pagination from '@/components/Pagination'
-import { getScreenWidth } from '@/utils'
-import { fetchMemberList } from '@/api/member'
+import filterHelper from '@/utils/filterHelper'
+import waves from "@/directive/waves";
+import {getOperatingSystem, getScreenWidth} from "@/utils"
+import region from "@/store/modules/region"
+import {
+	fetchCloseDec, fetchCloseDecGet, fetchCloseLoginGet, fetchMemberExport, fetchMemberList, fetchProfileGet,
+	updateModifyPassword, updateModifyProfile, updateSetActive, updateSetAsStockist, updateSetChartDisplay, updateSetLock, updateSetModifyPassword, updateSetRechargeDisplay,
+} from "@/api/member"
 
 export default {
-  name: 'MemberList',
-  components: { Pagination },
-  directives: { waves },
-  filters: {
-    statusFilter(status) {
-      const statusMap = {
-        Unpaid: 'info',
-        Paid: 'success'
-      }
-      return statusMap[status]
-    }
-  },
-  data() {
-    return {
-      tableKey: 0,
-      total: 0,
-      memberData: [],
-      loading: true,
-      downloadLoading: false,
-      listQuery: {
-        page: 1,
-        pageSize: 20
-      },
-      childrenNode: [],
-      screenWidth: getScreenWidth() > 600 ? '500px' : getScreenWidth() + 'px',
-      labelPosition: getScreenWidth() > 600 ? 'right' : 'top'
-    }
-  },
-  created() {
-    this.getMemberList()
-  },
-  methods: {
-    getMemberList() {
-      this.loading = true
-      fetchMemberList(this.listQuery).then(response => {
-        this.memberData = response.data.list
-        this.total = +response.data.totalCount
-        console.log(this.memberData)
-        setTimeout(() => {
-          this.loading = false
-        }, 0.5 * 1000)
-      })
-    }
-  }
+	name: 'memberList',
+	directives: { waves },
+	components: {FilterUser, Pagination},
+	mounted() {
+		// TODO: 测试接口
+		// this.getData()
+
+		if (permission.hasPermission(`user/close-login`) || permission.hasPermission(`user/close-area-login`) || permission.hasPermission(`user/batch-close-login`)) {
+			fetchCloseLoginGet().then(response => {
+				this.apps = response.data.apps
+				this.closeSwitch = response.data.closeSwitch
+				if (permission.hasPermission(`user/close-dec`) || permission.hasPermission(`user/close-area-dec`) || permission.hasPermission(`user/batch-close-dec`)) {
+					fetchCloseDecGet().then(response => {
+						this.closeDecSwitch = response.data.closeSwitch
+						this.getData()
+					}).catch(error => {
+						this.$message({
+							message: error,
+							type: 'warning'
+						})
+					})
+				} else {
+					this.getData()
+				}
+			}).catch(error => {
+				this.$message({
+					message: error,
+					type: 'warning'
+				})
+			})
+		} else {
+			if (permission.hasPermission(`user/close-dec`) || permission.hasPermission(`user/close-area-dec`) || permission.hasPermission(`user/batch-close-dec`)) {
+				fetchCloseDecGet().then(response => {
+					this.closeDecSwitch = response.data.closeSwitch
+					this.getData()
+				}).catch(error => {
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+				})
+			} else {
+				this.getData()
+			}
+		}
+	},
+	data() {
+		return {
+			tableHeaders: null,
+			tableData: null,
+			loading: true,
+			multipleSelection: [],
+			currentPage: 1,
+			totalPages: 1,
+			totalCount: 1,
+			pageSize: 20,
+			frontendServer: process.env.VUE_APP_FRONTEND_WEBSITE,
+			baseDecLevels: baseInfo.decLevels(),
+			baseEmpLevels: baseInfo.empLevels(),
+			tool: tool,
+			permission: permission,
+			filterTypes: null,
+			filterModel: {},
+			dialogVisible: false,
+			formCloseLogin: {
+				userName: null,
+				typeName: this.$t('member.loginManagement'),
+				type: null,
+				isClose: 0,
+				remark: '',
+				areaSelected: null,
+			},
+			regionDataPlus: region.regionInfo.regionData,
+			apps: null,
+			closeSwitch: null,
+			submitButtonStat: false,
+			dialogDecVisible: false,
+			dialogModifyPasswordVisible: false,
+			dialogModifyProfileVisible: false,
+			formCloseDec: {
+				userName: null,
+				typeName: this.$t('member.entryManage'),
+				type: null,
+				isClose: 0,
+				remark: '',
+				areaSelected: null,
+			},
+			formModifyPassword: {
+				userId:'',
+				password: '',
+				typeName: this.$t('member.changePassword'),
+				passwordType: 'password',
+			},
+			formModifyProfile: {
+				userId:'',
+				typeName: this.$t('member.modifyPersonalData'),
+				nation: '',
+				realName: '',
+				idCard: '',
+				mobile: '',
+				openBank: '',
+				bankAddress: '',
+				bankNo: '',
+			},
+			passwordType: [
+				{
+					type:"password",
+					label: this.$t('member.loginPassword'),
+				},
+				{
+					type:"payPassword",
+					label: this.$t('member.paymentPassword'),
+				},
+			],
+			allOpenBank:null,
+			allNation:null,
+			submitDecButtonStat: false,
+			submitPasswordButtonStat: false,
+			submitProfileButtonStat: false,
+			transferPropForm: {
+				userIds: [],
+				allowTransfer: true,
+				transferProp: 100,
+				withdrawProp: 0,
+				remark: '',
+			},
+			closeUserData: null,
+			screenWidth: getScreenWidth() > 500 ? '500px' : getScreenWidth() + 'px',
+			labelPosition: getScreenWidth() >= 500 ? 'right' : 'top',
+			leftFixed: ['Android', 'ios'].includes(getOperatingSystem()) ? false : 'left',
+			fixed: ['Android', 'ios'].includes(getOperatingSystem()) ? false : 'right',
+		}
+	},
+	methods: {
+		handleSelectionChange(val) {
+			this.multipleSelection = val
+		},
+		handleCurrentChange(page) {
+			this.getData(page, this.pageSize)
+		},
+		handleSizeChange(pageSize) {
+			this.getData(this.currentPage, pageSize)
+		},
+		handleFilterUser(filterData) {
+			filterHelper.handleFilterUser(this, filterData)
+		},
+		handleFilter() {
+			this.getData()
+		},
+		getData(page, pageSize) {
+			this.loading = true
+			const paramsData = Object.assign({
+				page: (page === null || page == undefined) ? 1 : page,
+				pageSize: (pageSize === null || pageSize == undefined) ? this.pageSize : pageSize
+			}, this.filterModel)
+			fetchMemberList(paramsData).then(response => {
+				this.filterTypes = response.data.filterTypes
+				this.tableData = response.data.list
+				this.totalCount = +response.data.totalCount
+				this.currentPage = page
+				this.pageSize = pageSize
+				this.filterTypes = response.data.filterTypes
+				this.tableHeaders = response.data.columnsShow
+				this.loading = false
+			}).catch(error => {
+				this.$message({
+					message: error,
+					type: 'warning'
+				})
+				this.loading = false
+			})
+		},
+		handleIsDecManage(isDec) {
+			if (this.multipleSelection.length < 1) {
+				this.$message({
+					message: this.$t('member.selectMemberData'),
+					type: 'warning'
+				})
+				return
+			}
+			let isDecTip = isDec === true ? this.$t('member.setAsStockist') : this.$t('member.cancelStockist')
+			this.$confirm( this.$t('member.sureWant') + `【${isDecTip}】?`, this.$t('common.hint'), {
+				confirmButtonText: this.$t('common.confirm'),
+				cancelButtonText: this.$t('common.cancel'),
+				type: 'warning'
+			}).then(() => {
+				let selectedIds = []
+				for (let val of this.multipleSelection) {
+					selectedIds.push(val.USER_ID)
+				}
+				this.loading = true
+				updateSetAsStockist( { userIds: selectedIds, isDec: isDec }).then(response => {
+					this.$message({
+						message: response.data,
+						type: 'success'
+					})
+
+					this.loading = false
+					this.getData(this.currentPage, this.pageSize)
+				})
+			}).catch(error => {
+				this.$message({
+					message: error,
+					type: 'warning'
+				})
+				this.loading = false
+			})
+		},
+		handleIsAtlasManage(isAtlas) {
+			if (this.multipleSelection.length < 1) {
+				this.$message({
+					message: this.$t('member.selectMemberData'),
+					type: 'warning'
+				})
+				return
+			}
+			let isAtlasTip = isAtlas === true ? this.$t('member.displayChart') : this.$t('member.hiddenChart')
+			this.$confirm(this.$t('member.sureWant') + `【${isAtlasTip}】?`, this.$t('common.hint'), {
+				confirmButtonText: this.$t('common.confirm'),
+				cancelButtonText: this.$t('common.cancel'),
+				type: 'warning'
+			}).then(() => {
+				let selectedIds = []
+				for (let val of this.multipleSelection) {
+					selectedIds.push(val.USER_ID)
+				}
+				this.loading = true
+				updateSetChartDisplay( { userIds: selectedIds, isAtlas: isAtlas }).then(response => {
+					this.$message({
+						message: response.data,
+						type: 'success'
+					})
+
+					this.loading = false
+					this.getData(this.currentPage, this.pageSize)
+				})
+			}).catch(error => {
+				this.$message({
+					message: error,
+					type: 'warning'
+				})
+				this.loading = false
+			})
+		},
+		handleIsRechargeManage(isRecharge) {
+			if (this.multipleSelection.length < 1) {
+				this.$message({
+					message: this.$t('member.selectMemberData'),
+					type: 'warning'
+				})
+				return false
+			}
+			let isRechargeTip = isRecharge === true ? this.$t('member.displayRecharge') : this.$t('member.hideRecharge')
+			this.$confirm(this.$t('member.sureWant') + `【${isRechargeTip}】?`, this.$t('common.hint'), {
+				confirmButtonText: this.$t('common.confirm'),
+				cancelButtonText: this.$t('common.cancel'),
+				type: 'warning'
+			}).then(() => {
+				let selectedIds = []
+				for (let val of this.multipleSelection) {
+					selectedIds.push(val.USER_ID)
+				}
+				this.loading = true
+				updateSetRechargeDisplay( { userIds: selectedIds, isRecharge: isRecharge }).then(response => {
+					this.$message({
+						message: response.data,
+						type: 'success'
+					})
+					this.loading = false
+					this.getData(this.currentPage, this.pageSize)
+				})
+			}).catch(error => {
+				this.$message({
+					message: error,
+					type: 'warning'
+				})
+				this.loading = false
+			})
+		},
+		handleExport() {
+			this.$confirm(this.$t('member.exportDataHint'), this.$t('common.hint'), {
+				confirmButtonText: this.$t('common.confirm'),
+				cancelButtonText: this.$t('common.cancel'),
+				type: 'warning'
+			}).then(() => {
+				this.loading = true
+				fetchMemberExport( this.filterModel).then(response => {
+					this.$message({
+						message: response.data,
+						type: 'success'
+					})
+					this.loading = false
+					this.getData(this.currentPage, this.pageSize)
+				})
+			}).catch(error => {
+				this.$message({
+					message: error,
+					type: 'warning'
+				})
+				this.loading = false
+			})
+		},
+		handleModifyPassword(row){
+			this.formModifyPassword.userId = row.USER_ID;
+			this.dialogModifyPasswordVisible = true
+		},
+		handleModifyProfile(row){
+			this.dialogModifyProfileVisible = true
+			fetchProfileGet( { id: row.USER_ID }).then(response => {
+				this.formModifyProfile = response.data.userInfo
+				this.allOpenBank = response.data.allOpenBank
+				this.allNation = response.data.allNation
+			})
+		},
+		handleStatusActive(row) {
+			this.loading = true
+			updateSetActive( { userId: row.USER_ID, status: 1 }).then(response => {
+				this.$message({
+					message: response.data,
+					type: 'success'
+				})
+				this.loading = false
+				this.getData(this.currentPage, this.pageSize)
+			})
+		},
+		handleStatusLock(row) {
+			this.loading = true
+			updateSetLock( { userId: row.USER_ID, status: 0 }).then(response => {
+				this.$message({
+					message: response.data,
+					type: 'success'
+				})
+				this.loading = false
+				this.getData(this.currentPage, this.pageSize)
+			})
+		},
+		handleIsModifyPassword(row, status){
+			this.loading = true
+			updateSetModifyPassword( { userId: row.USER_ID, status: status }).then(response => {
+				this.$message({
+					message: response.data,
+					type: 'success'
+				})
+				this.loading = false
+				this.getData(this.currentPage, this.pageSize)
+			})
+		},
+		handleModifyPasswordSubmit() {
+			this.submitPasswordButtonStat = true
+			updateModifyPassword( this.formModifyPassword).then(response => {
+				this.$message({
+					message: response.data,
+					type: 'success'
+				})
+
+				this.submitPasswordButtonStat = false
+				this.dialogModifyPasswordVisible = false
+
+				this.getData(this.currentPage, this.pageSize)
+			}).catch(error => {
+				this.$message({
+					message: error,
+					type: 'success'
+				})
+				this.submitPasswordButtonStat = false
+			})
+		},
+		handleModifyProfileSubmit() {
+			this.submitProfileButtonStat = true
+			updateModifyProfile( this.formModifyProfile).then(response => {
+				this.$message({
+					message: response.data,
+					type: 'success'
+				})
+
+				this.submitProfileButtonStat = false
+				this.dialogModifyProfileVisible = false
+
+				this.getData(this.currentPage, this.pageSize)
+			}).catch(error => {
+				this.$message({
+					message: error,
+					type: 'success'
+				})
+				this.submitProfileButtonStat = false
+				this.dialogModifyProfileVisible = false
+			})
+		},
+	}
 }
 </script>
 
 <style>
-.el-table th.el-table__cell > .cell {
-	white-space: nowrap;
+.app-main {
+	padding: 15px;
 }
-
-.el-table td.el-table__cell > .cell {
-	word-break: keep-all;
-	white-space: pre-wrap;
+.app-container {
+	padding: 0;
+}
+.white-box {
+	padding: 15px;
+}
+.form-page {
+	width: 100%;
 }
 </style>

+ 656 - 0
src/views/user/member-network-move.vue

@@ -0,0 +1,656 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <el-tabs v-model="filterStatus" @tab-click="handleFilterStatusClick">
+        <el-tab-pane :lazy="true" :label="$t('member.all')"      name="-1"></el-tab-pane>
+        <el-tab-pane :lazy="true" :label="$t('member.reviewed')" name="0"></el-tab-pane>
+        <el-tab-pane :lazy="true" :label="$t('member.approved')" name="1"></el-tab-pane>
+        <el-tab-pane :lazy="true" :label="$t('member.rejected')" name="3"></el-tab-pane>
+      </el-tabs>
+
+			<!-- 搜索	-->
+      <div class="filter-box">
+        <filter-user ref="filterUser" :filter-types.sync="filterTypes" @select-value="handleFilterUser"></filter-user>
+      </div>
+
+			<!-- 列表	-->
+      <el-table :data="tableData" stripe style="width: 100%;" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" v-if="tableHeaders"></el-table-column>
+        <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''">
+          <template slot-scope="{row}">
+            <template v-if="row[tableHeader.index].other.tag" >
+              <el-tag :type="row[tableHeader.index].other.tag.type ? row[tableHeader.index].other.tag.type : null" :size="row[tableHeader.index].other.tag.size ? row[tableHeader.index].other.tag.size : null" :class="row[tableHeader.index].other.tag.class ? row[tableHeader.index].other.tag.class : null" >
+								{{ row[tableHeader.index].value }}
+							</el-tag>
+            </template>
+            <template v-else-if="row[tableHeader.index].other.progress" >
+              <el-progress type="circle" :percentage="Number.parseInt(percentList['MOVE_PERCENT'][row.ID])" :width="50" :stroke-width="3"></el-progress>
+            </template>
+            <template v-else>
+              <div v-html="row[tableHeader.index].value"></div>
+            </template>
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('common.action')" v-if="tableHeaders">
+          <template slot-scope="{row}" v-if="row.AUDIT_STATUS === '0' && (permission.hasPermission(`user/move-pass`) || permission.hasPermission(`user/move-audit`) || permission.hasPermission(`user/move-delete`))">
+            <el-dropdown size="small" trigger="click">
+              <el-button type="primary" size="small">{{ $t('common.action') }}<i class="el-icon-arrow-down el-icon--right"></i></el-button>
+              <el-dropdown-menu slot="dropdown">
+                <el-dropdown-item command="pass"   @click.native="handleAuditShow(row)" v-show="permission.hasPermission(`user/move-pass`)">{{ $t('member.approved') }}</el-dropdown-item>
+                <el-dropdown-item command="refuse" @click.native="handleAudit(row, 'reject')" v-show="permission.hasPermission(`user/move-audit`)">{{ $t('member.rejected') }}</el-dropdown-item>
+                <el-dropdown-item command="del"    @click.native="handleDel(row.ID)" v-show="permission.hasPermission(`user/move-delete`)">{{ $t('member.deleteData') }}</el-dropdown-item>
+              </el-dropdown-menu>
+            </el-dropdown>
+          </template>
+        </el-table-column>
+      </el-table>
+
+			<!-- 功能菜单	-->
+      <div class="white-box-footer">
+				<el-button type="danger"  size="small" @click.native="handleDel()" v-if="(filterStatus==='0') && permission.hasPermission(`user/move-delete`)" style="margin: 10px; margin-left: 10px;">{{ $t('member.batchesDelete') }}</el-button>
+        <el-button type="primary" size="small" @click="dialogApplyFormVisible = true" icon="el-icon-plus" v-show="permission.hasPermission(`user/move-add`)" style="margin: 10px;">{{ $t('member.applyNetworkMove') }}</el-button>
+        <el-button type="success" size="small" @click="handleExport" v-show="permission.hasPermission(`user/move-export`)" style="margin: 10px;">{{ $t('member.exportExcel') }}</el-button>
+
+				<!-- 分页	-->
+				<pagination v-show="total>0" :total="total" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+      </div>
+    </div>
+
+		<!-- 新建移网	-->
+		<el-dialog :title="$t('member.applyNetworkTransfer')" :visible.sync="dialogApplyFormVisible" :width="screenWidth" style="margin-top: -80px;">
+			<el-form :model="applyForm" label-width="230px" :label-position="labelPosition" v-loading="dialogApplyLoading" size="mini" style="padding: 10px 15px; margin-top: -25px; margin-bottom: -25px;">
+				<el-form-item :label="$t('member.networkTransferType')">
+					<el-select v-model="applyForm.type" :placeholder="$t('member.selectNetworkTransferType')" style="width: 100%;">
+						<el-option v-for="(item,key) in netType" :label="item.name" :value="item.id" :key="key"></el-option>
+					</el-select>
+				</el-form-item>
+				<div v-if="applyForm.type==='network'">
+					<el-form-item :label="$t('member.mobileMemberCode')">
+						<el-input v-model.trim="applyForm.moveUserName" @blur="handleChkUser"></el-input>
+					</el-form-item>
+					<el-form-item :label="$t('member.mobileMemberName')" v-if="moveUser">
+						<el-input v-model="moveUser.REAL_NAME" :disabled="true"></el-input>
+					</el-form-item>
+					<el-form-item :label="$t('member.moveToPlacementMemberCode')">
+						<el-input v-model.trim="applyForm.toConUserName"></el-input>
+						<el-tag v-if="showToName == '' ? false : true">{{ showToName }}</el-tag>
+						<el-alert :title="toAlertTile" :type="toAlertType" :closable="false" v-show="toAlertShow"></el-alert>
+					</el-form-item>
+					<el-form-item :label="$t('member.moveToPlacementMemberName')">
+						<el-input v-model="applyForm.toConRealName"></el-input>
+					</el-form-item>
+				</div>
+				<div v-if="applyForm.type === 'relation'">
+					<el-form-item :label="$t('member.mobileMemberCode')">
+						<el-input v-model.trim="applyForm.moveUserName" @blur="handleChkUser"></el-input>
+					</el-form-item>
+					<el-form-item :label="$t('member.mobileMemberName')" v-if="moveUser">
+						<el-input v-model="moveUser.REAL_NAME" :disabled="true"></el-input>
+					</el-form-item>
+					<el-form-item :label="$t('member.moveToSponsorMemberCode')">
+						<el-input v-model.trim="applyForm.toConUserName"></el-input>
+						<el-tag v-if="showToName == '' ? false : true">{{ showToName }}</el-tag>
+						<el-alert :title="toAlertTile" :type="toAlertType" :closable="false" v-show="toAlertShow"></el-alert>
+					</el-form-item>
+					<el-form-item :label="$t('member.moveToSponsorMemberName')">
+						<el-input v-model="applyForm.toConRealName"></el-input>
+					</el-form-item>
+				</div>
+				<el-form-item v-if="applyForm.type === 'network'" :label="$t('member.moveToLocation')">
+					<el-select v-model="applyForm.location" :placeholder="$t('member.moveToLocation')" style="width: 100%;">
+						<el-option :label="$t('member.oneMarket')" value="1" key="location_1" sele></el-option>
+						<el-option :label="$t('member.twoMarket')" value="2" key="location_2"></el-option>
+					</el-select>
+				</el-form-item>
+				<el-form-item :label="$t('member.remark')" v-if="applyForm.type">
+					<el-input v-model="applyForm.remark"></el-input>
+				</el-form-item>
+			</el-form>
+			<div slot="footer" class="dialog-footer" style="margin-top: -15px;">
+				<el-button size="mini" @click="dialogApplyFormVisible = false">{{ $t('common.cancel') }}</el-button>
+				<el-button size="mini" type="primary" @click="onSubmit" :loading="submitButtonStat">{{ $t('common.submit') }}</el-button>
+			</div>
+		</el-dialog>
+
+		<!-- 修改移网	-->
+    <el-dialog :title="$t('member.modifyNetworkTransfer')" :visible.sync="dialogEditFormVisible" :width="screenWidth" style="margin-top: -80px;">
+      <el-form :model="form" label-width="230px" :label-position="labelPosition" v-loading="dialogEditLoading" size="mini" style="padding: 10px 15px; margin-top: -25px; margin-bottom: -25px;">
+        <el-form-item :label="$t('member.networkTransferType')">
+          <el-select v-model="form.type" :placeholder="$t('member.selectNetworkTransferType')" style="width: 100%;">
+            <el-option v-for="(item,key) in netType" :label="item.name" :value="item.id" :key="key"></el-option>
+          </el-select>
+        </el-form-item>
+        <div v-if="form.type==='network'">
+          <el-form-item :label="$t('member.mobileMemberCode')">
+            <el-input v-model="form.baseInfo.USER_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.mobileMemberName')">
+            <el-input v-model="form.baseInfo.REAL_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.originalSuperiorNo')">
+            <el-input v-model="form.baseInfo.CON_USER_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.originalSuperiorName')">
+            <el-input v-model="form.baseInfo.CON_REAL_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.moveToPlacementMemberCode')">
+            <el-input v-model="form.toConUserName"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.moveToPlacementMemberName')">
+            <el-input v-model="form.toConRealName"></el-input>
+          </el-form-item>
+        </div>
+        <div v-if="form.type==='relation'">
+          <el-form-item :label="$t('member.mobileMemberCode')">
+            <el-input v-model="form.baseInfo.USER_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.mobileMemberName')">
+            <el-input v-model="form.baseInfo.REAL_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.originalDeveloperNo')">
+            <el-input v-model="form.baseInfo.REC_USER_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.nameOfOriginalDeveloper')">
+            <el-input v-model="form.baseInfo.REC_REAL_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.moveToSponsorMemberCode')">
+            <el-input v-model="form.toConUserName"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.moveToSponsorMemberName')">
+            <el-input v-model="form.toConRealName"></el-input>
+          </el-form-item>
+        </div>
+        <el-form-item v-if="form.type === 'network'" :label="$t('member.moveToLocation')">
+          <el-select v-model="form.location" :placeholder="$t('member.moveToLocation')" style="width: 100%;">
+            <el-option :label="$t('member.oneMarket')" value="1" key="location_1"></el-option>
+            <el-option :label="$t('member.twoMarket')" value="2" key="location_2"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item :label="$t('member.remark')" v-if="form.type">
+          <el-input v-model="form.remark"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer" style="margin-top: -15px;">
+        <el-button size="mini" @click="dialogEditFormVisible = false">{{ $t('common.cancel') }}</el-button>
+        <el-button size="mini" type="primary" @click.native="handleEdit">{{ $t('common.submit') }}</el-button>
+      </div>
+    </el-dialog>
+
+		<!-- 移网审核	-->
+    <el-dialog :title="$t('member.reviewNetworkTransfer')" :visible.sync="dialogAuditFormVisible" :width="screenWidth" style="margin-top: -80px">
+      <el-form :model="form" label-width="230px" :label-position="labelPosition" v-loading="dialogAuditLoading" size="mini" style="padding: 10px 15px;">>
+        <el-form-item :label="$t('member.networkTransferType')">
+          <el-select v-model="form.type" :placeholder="$t('member.selectNetworkTransferType')" style="width: 100%;">
+            <el-option v-for="(item,key) in netType" :label="item.name" :value="item.id" :key="key"></el-option>
+          </el-select>
+        </el-form-item>
+        <div v-if="form.type==='network'">
+          <el-form-item :label="$t('member.mobileMemberCode')">
+            <el-input v-model="form.baseInfo.USER_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.mobileMemberName')">
+            <el-input v-model="form.baseInfo.REAL_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.originalSuperiorNo')">
+            <el-input v-model="form.baseInfo.CON_USER_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.originalSuperiorName')">
+            <el-input v-model="form.baseInfo.CON_REAL_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.moveToPlacementMemberCode')">
+            <el-input v-model="form.toConUserName"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.moveToPlacementMemberName')">
+            <el-input v-model="form.toConRealName"></el-input>
+          </el-form-item>
+        </div>
+        <div v-if="form.type==='relation'">
+          <el-form-item :label="$t('member.mobileMemberCode')">
+            <el-input v-model="form.baseInfo.USER_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.mobileMemberName')">
+            <el-input v-model="form.baseInfo.REAL_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.originalDeveloperNo')">
+            <el-input v-model="form.baseInfo.REC_USER_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.nameOfOriginalDeveloper')">
+            <el-input v-model="form.baseInfo.REC_REAL_NAME" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.moveToSponsorMemberCode')">
+            <el-input v-model="form.toConUserName"></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('member.moveToSponsorMemberName')">
+            <el-input v-model="form.toConRealName"></el-input>
+          </el-form-item>
+        </div>
+				<el-form-item v-if="form.type==='network'" :label="$t('member.moveToLocation')">
+					<el-select v-model="form.location" :placeholder="$t('member.moveToLocation')" style="width: 100%;">
+						<el-option :label="$t('member.oneMarket')" value="1" key="location_1"></el-option>
+						<el-option :label="$t('member.twoMarket')" value="2" key="location_2"></el-option>
+					</el-select>
+				</el-form-item>
+				<el-form-item :label="$t('member.remark')" v-if="form.type">
+					<el-input v-model="form.remark"></el-input>
+				</el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button size="mini" @click="dialogAuditFormVisible = false">{{ $t('common.cancel') }}</el-button>
+        <el-button size="mini" type="primary" @click.native="handleAuditPass">{{ $t('member.adopted') }}</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+  import tool from '@/utils/tool'
+  import FilterUser from '@/components/FilterUser'
+  import permission from '@/utils/permission'
+  import Pagination from '@/components/Pagination'
+  import filterHelper from '../../utils/filterHelper'
+	import {
+		fetchMemberFullInfo,
+		fetchNetworkMoveExport, fetchNetworkMoveGet,
+		fetchNetworkMoveList,
+		fetchNetworkType, updateNetworkMoveApply, updateNetworkMoveAudit, updateNetworkMoveDelete, updateNetworkMoveEdit,
+		updateNetworkMovePass
+	} from "@/api/member";
+	import {getScreenWidth} from "@/utils";
+
+  export default {
+    name: 'memberNetworkMove',
+    components: {FilterUser,Pagination},
+    mounted() {
+      // store.state.socket.onMessageCallback = this.onMessageCallback
+			// 查询移网分类
+			fetchNetworkType().then(response => {
+				this.netType = response.data.netType
+				this.getData()
+			}).catch(error => {
+				this.$message({
+					message: error,
+					type: 'warning'
+				})
+				this.loading = false
+			})
+    },
+    data() {
+      return {
+        tableHeaders: null,
+        allData: null,
+        tableData: null,
+        netType: [],
+        loading: true,
+        multipleSelection: [],
+				total: 0,
+				page: 1,
+				pageSize: 20,
+				currentPage: 1,
+        tool: tool,
+        permission: permission,
+        filterTypes: {},
+        filterModel: {},
+        filterStatus: '0',
+        dialogEditLoading: false,
+        dialogAuditLoading: false,
+        dialogEditFormVisible: false,
+        dialogAuditFormVisible: false,
+				dialogApplyLoading: false,
+				dialogApplyFormVisible: false,
+        auditId: null,
+        form: {
+          baseInfo: {USER_NAME: null},
+          moveUserName: null,
+          toConUserName: null,
+          toConRealName: null,
+          type: '',
+          location: '1',
+          remark: null,
+          createRemark: '',
+          auditStatus: null
+        },
+        percentList: {
+          'MOVE_PERCENT': {},
+        },
+				screenWidth: getScreenWidth() > 600 ? '600px' : getScreenWidth() + 'px',
+				labelPosition: getScreenWidth() >= 600 ? 'right' : 'top',
+
+				applyForm: {
+					moveUserName: null,
+					toConUserName: null,
+					toConRealName: null,
+					type: null,
+					location: '1',
+					remark: null,
+				},
+				moveUser: {},
+				showToName: '',
+				toAlertTile: '',
+				toAlertShow: false,
+				toAlertType: 'success',
+				isRelation: false,
+				submitButtonStat: false,
+      }
+    },
+    methods: {
+      handleSelectionChange(val) {
+        this.multipleSelection = val
+      },
+      handleCurrentChange(page) {
+        this.getData(page, this.pageSize)
+      },
+      handleSizeChange(pageSize) {
+        this.getData(this.currentPage, pageSize)
+      },
+      handleEditShow(row) {
+        this.dialogEditLoading = true
+        this.auditId = row.ID
+        this.dialogEditFormVisible = true
+				fetchNetworkMoveGet({ id: this.auditId }).then(response => {
+					this.$message({
+						message: response,
+						type: 'success'
+					})
+					this.dialogEditLoading = false
+					this.form = response
+					this.form.type = String(response.type)
+					this.form.location = String(response.location)
+					this.form.createRemark = this.form.remark
+				}).catch(error => {
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+					this.dialogEditLoading = false
+				})
+      },
+      handleEdit() {
+        this.dialogEditFormVisible = false
+        this.$message({
+          message: this.$t('member.modifyingData'),
+          type: 'info'
+        })
+
+				updateNetworkMoveEdit(this.form).then(response => {
+					this.$message({
+						message: response,
+						type: 'success'
+					})
+
+					this.getData(this.currentPage, this.pageSize)
+				}).catch(error => {
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+				})
+      },
+      handleAuditShow(row) {
+        this.dialogAuditLoading = true
+        this.auditId = row.ID
+        this.dialogAuditFormVisible = true
+				fetchNetworkMoveGet({ id: this.auditId }).then(response => {
+					this.$message({
+						message: response,
+						type: 'success'
+					})
+					this.dialogAuditLoading = false
+					this.form = response
+					this.form.type = String(response.type)
+					this.form.location = String(response.location) !== '0' ? String(response.location) : '1'
+					this.form.createRemark = this.form.remark
+				}).catch(error => {
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+					this.dialogAuditLoading = false
+				})
+      },
+      handleAuditPass() {
+        this.dialogAuditFormVisible = false
+        this.$message({
+          message: this.$t('member.passingAudit'),
+          type: 'info'
+        })
+        this.form.auditStatus = 'true'
+				updateNetworkMovePass(this.form).then(response => {
+					this.$message({
+						message: response,
+						type: 'success'
+					})
+					this.getData(this.currentPage, this.pageSize)
+
+					this.loading = false
+				}).catch(error => {
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+					this.loading = false
+				})
+      },
+      handleAudit(row = null, status) {
+        let obj = this
+        let title = (status === 'reject') ? this.$t('member.rejectAuditNote') : this.$t('member.passAuditNote')
+        this.$prompt(title, this.$t('common.hint'), {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          inputValue: '',
+        }).then(({value}) => {
+          this.$message({
+            message: this.$t('member.operationInProcess'),
+            type: 'info'
+          })
+          let selectedIds = []
+          if (row === null) {
+            for (let val of obj.multipleSelection) {
+              selectedIds.push(val.ID)
+            }
+          } else {
+            selectedIds.push(row.ID)
+          }
+
+					const data = {
+						selected: selectedIds,
+						remark: value,
+						auditStatus: status
+					}
+					updateNetworkMoveAudit(data).then(response => {
+						this.$message({
+							message: response,
+							type: 'success'
+						})
+						this.getData(this.currentPage, this.pageSize)
+					}).catch(error => {
+						this.$message({
+							message: error,
+							type: 'warning'
+						})
+					})
+        }).then(response => {
+          this.$message({
+            message: response,
+            type: 'success'
+          })
+          this.getData(this.currentPage, this.pageSize)
+        }).catch(error => {
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+        })
+      },
+      handleDel(id = null) {
+				if (id == null && this.multipleSelection.length === 0) {
+					this.$message({
+						message:this.$t('member.selectedNonData'),
+						type: 'warning'
+					})
+					return false
+				}
+
+        this.$confirm(this.$t('member.deleteHint'), this.$t('common.hint'), {
+					confirmButtonText: this.$t('common.confirm'),
+					cancelButtonText: this.$t('common.cancel'),
+          type: 'warning',
+					customClass: 'csClass',
+        }).then(() => {
+          let selectedIds = []
+          if (id === null) {
+            for (let val of this.multipleSelection) {
+              selectedIds.push(val.ID)
+            }
+          } else {
+            selectedIds.push(id)
+          }
+
+					updateNetworkMoveDelete({ selected: selectedIds }).then(response => {
+						this.$message({
+							message: response,
+							type: 'success'
+						})
+						this.getData(this.currentPage, this.pageSize)
+					}).catch(error => {
+						this.$message({
+							message: error,
+							type: 'warning'
+						})
+					})
+        }).then(response => {
+          this.$message({
+            message: response,
+            type: 'success'
+          })
+					this.getData(this.currentPage, this.pageSize)
+        }).catch(error => {
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+        })
+      },
+      handleFilterStatusClick(tab, event) {
+        filterHelper.clearFilterOption(this)
+        this.getData()
+      },
+      handleFilterUser(filterData) {
+        filterHelper.handleFilterUser(this, filterData)
+      },
+      handleFilter() {
+        this.getData()
+      },
+      getData(page, pageSize) {
+				this.loading = true
+				let filterData = this.filterModel
+				filterData.filterStatus = this.filterStatus != '-1' ? `=,${this.filterStatus}` : ''
+				const paramsData = Object.assign({
+					page: (page === null || page == undefined) ? 1 : page,
+					pageSize: (pageSize === null || pageSize == undefined) ? this.pageSize : pageSize
+				}, filterData)
+				fetchNetworkMoveList(paramsData).then(response => {
+					this.filterTypes = response.data.filterTypes
+					this.tableData = response.data.list
+					this.total = +response.data.totalCount
+					this.currentPage = page
+					this.pageSize = pageSize
+					this.filterTypes = response.data.filterTypes
+					this.tableHeaders = response.data.columnsShow
+
+					this.loading = false
+				}).catch(error => {
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+					this.loading = false
+				})
+      },
+      handleExport() {
+        this.$confirm(this.$t('member.exportExcelHint'), this.$t('common.hint'), {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning',
+					customClass: 'csClass',
+        }).then(() => {
+					fetchNetworkMoveExport(this.filterModel).then(response => {
+						this.$message({
+							message: response,
+							type: 'warning'
+						})
+					}).catch(error => {
+						this.$message({
+							message: error,
+							type: 'warning'
+						})
+					})
+        }).then(response => {
+          this.$message({
+            message: response,
+            type: 'success'
+          })
+        }).catch(() => {
+
+        })
+      },
+      onMessageCallback(data) {
+        if (data) {
+          if (data.other && data.other.MODEL === 'USER_MOVE' && data.other.ID) {
+            this.$set(this.percentList[data.other.FIELD], data.other.ID, data.percent)
+          }
+          if (data.percent && data.percent === 100) {
+            //this.getData(this.currentPage, this.pageSize)
+          }
+        }
+      },
+			handleChkUser() {
+				if (this.applyForm.moveUserName) {
+					fetchMemberFullInfo({ userName: this.applyForm.moveUserName }).then(response => {
+						this.moveUser = response.data
+					}).catch(error => {
+						this.$message({
+							message: error,
+							type: 'warning'
+						})
+					})
+				}
+			},
+			onSubmit() {
+				this.submitButtonStat = true
+				updateNetworkMoveApply(this.applyForm).then(response => {
+					this.$message({
+						message: response,
+						type: 'success'
+					})
+					this.dialogApplyFormVisible = false
+					this.submitButtonStat = false
+				}).catch(error => {
+					this.$message({
+						message: error,
+						type: 'warning'
+					})
+					this.submitButtonStat = false
+				})
+			},
+    }
+  }
+
+</script>
+
+<style>
+.app-main {
+	padding: 15px;
+}
+.app-container {
+	padding: 10px;
+}
+.white-box {
+	padding: 15px;
+}
+.form-page {
+	width: 100%;
+}
+.csClass{
+	margin-top: 50px;
+}
+</style>

+ 137 - 0
src/views/user/modify-stockist-level.vue

@@ -0,0 +1,137 @@
+<template>
+  <div class="app-container">
+    <div v-loading="loading" class="white-box">
+			<el-form ref="form" :model="form" label-width="250px" :label-position="labelPosition">
+				<el-form-item :label="$t('member.memberCode')">
+					<el-input v-model.trim="form.userName" @change="handleChange"></el-input>
+					<el-tag style="margin-top: 15px;" v-show="userInfo.REAL_NAME !== null">{{ $t('member.memberName') }}:{{ userInfo.REAL_NAME }} {{ $t('member.currentLevel') }}:{{ allDecRole[userInfo.DEC_ROLE_ID] ? allDecRole[userInfo.DEC_ROLE_ID]['ROLE_NAME'] : '' }}</el-tag>
+				</el-form-item>
+				<el-form-item :label="$t('member.stockistLevel')">
+					<el-select v-model="form.levelId" :placeholder="$t('member.pleaseSelectStockistLevel')">
+						<el-option v-for="(item,key) in allDecRole" :label="item.ROLE_NAME" :value="item.ID" :key="key"></el-option>
+					</el-select>
+				</el-form-item>
+				<el-form-item :label="$t('member.remark')">
+					<el-input type="textarea" :rows="2" placeholder="" v-model="form.remark">
+					</el-input>
+				</el-form-item>
+				<el-form-item>
+					<el-button type="primary" :loading="submitButtonStat" @click="onSubmit">{{ $t('common.confirm') }}</el-button>
+				</el-form-item>
+			</el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import waves from '@/directive/waves'
+import { getScreenWidth } from '@/utils'
+import {fetchMemberFullInfo, updateUserStockistLevel} from "@/api/member";
+import baseInfo from "@/utils/baseInfo";
+
+export default {
+  name: 'modifyStockistLevel',
+  directives: { waves },
+  data() {
+    return {
+			form: {
+				userName: null,
+				levelId: null,
+				remark: null,
+			},
+			loading: false,
+			submitButtonStat: false,
+			allDecRole: baseInfo.decRoles(),
+			periodArr: [],
+			userInfo: {
+				REAL_NAME: null,
+				DEC_ROLE_ID: null,
+			},
+      screenWidth: getScreenWidth() > 600 ? '500px' : getScreenWidth() + 'px',
+      labelPosition: getScreenWidth() > 600 ? 'right' : 'top',
+    }
+  },
+  methods: {
+		handleChange() {
+			this.loading = true
+			fetchMemberFullInfo({ userName: this.form.userName }).then(response => {
+				this.userInfo = response.data
+
+				setTimeout(() => {
+					this.loading = false
+				}, 0.5 * 1000)
+			}).catch(error => {
+				this.userInfo.REAL_NAME = null
+				this.$message({
+					message: error,
+					type: 'warning'
+				})
+				this.loading = false
+			})
+		},
+    onSubmit() {
+			this.$confirm(this.$t('member.modifyEntryLevelHits'), this.$t('common.hint'), {
+				confirmButtonText: this.$t('common.confirm'),
+				cancelButtonText: this.$t('common.cancel'),
+				type: 'warning'
+			}).then(() => {
+				this._handleSubmit()
+			}).catch(error => {
+				this.$message({
+					message: error,
+					type: 'warning'
+				})
+			})
+    },
+		_handleSubmit() {
+			updateUserStockistLevel(this.form).then(response => {
+				this.$message({
+					message: response.data,
+					type: 'success'
+				})
+
+				setTimeout(() => {
+					this.submitButtonStat = false
+				}, 0.5 * 1000)
+
+				this.submitButtonStat = false
+			}).catch(error => {
+				this.$message({
+					message: error,
+					type: 'warning'
+				})
+
+				this.submitButtonStat = false
+			})
+
+			this._clearData()
+		},
+		_clearData(){
+			this.form = {
+				userName: null,
+				levelId: null,
+				remark: null,
+			}
+			this.userInfo= {
+				REAL_NAME: null,
+				DEC_ROLE_ID: null,
+			}
+		}
+  }
+}
+</script>
+
+<style>
+.app-main {
+	padding: 15px;
+}
+.app-container {
+	padding: 0;
+}
+.white-box {
+	padding: 15px;
+}
+.form-page {
+	width: 100%;
+}
+</style>

+ 134 - 0
vue.config.js

@@ -0,0 +1,134 @@
+'use strict'
+const path = require('path')
+const defaultSettings = require('./src/settings.js')
+
+function resolve(dir) {
+  return path.join(__dirname, dir)
+}
+
+const name = defaultSettings.title || 'Settlement system background' // page title
+
+// If your port is set to 80,
+// use administrator privileges to execute the command line.
+// For example, Mac: sudo npm run
+// You can change the port by the following method:
+// port = 9527 npm run dev OR npm run dev --port = 9527
+const port = process.env.port || process.env.npm_config_port || 9527 // dev port
+
+// All configuration item explanations can be find in https://cli.vuejs.org/config/
+module.exports = {
+  /**
+   * You will need to set publicPath if you plan to deploy your site under a sub path,
+   * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
+   * then publicPath should be set to "/bar/".
+   * In most cases please use '/' !!!
+   * Detail: https://cli.vuejs.org/config/#publicpath
+   */
+  publicPath: process.env.NODE_ENV === 'production' ? './' : '/',
+  outputDir: 'dist',
+  assetsDir: 'static',
+  // lintOnSave: process.env.NODE_ENV === 'development',
+  lintOnSave: false,
+  productionSourceMap: false,
+  devServer: {
+    port: port,
+    open: true,
+    overlay: {
+      warnings: false,
+      errors: true
+    },
+    proxy: {
+      [process.env.VUE_APP_BASE_API]:{
+        target:"http://172.21.141.111:9970",
+        changeOrigin:true,
+        pathRewrite:{
+          ["^" + process.env.VUE_APP_BASE_API] : ""
+        }
+      }
+    }
+    /* before: require('./mock/mock-server.js')*/
+  },
+  configureWebpack: {
+    // provide the app's title in webpack's name field, so that
+    // it can be accessed in index.html to inject the correct title.
+    name: name,
+    resolve: {
+      alias: {
+        '@': resolve('src')
+      }
+    }
+  },
+  chainWebpack(config) {
+    // it can improve the speed of the first screen, it is recommended to turn on preload
+    // it can improve the speed of the first screen, it is recommended to turn on preload
+    config.plugin('preload').tap(() => [
+      {
+        rel: 'preload',
+        // to ignore runtime.js
+        // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
+        fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
+        include: 'initial'
+      }
+    ])
+
+    // when there are many pages, it will cause too many meaningless requests
+    config.plugins.delete('prefetch')
+
+    // set svg-sprite-loader
+    config.module
+      .rule('svg')
+      .exclude.add(resolve('src/icons'))
+      .end()
+    config.module
+      .rule('icons')
+      .test(/\.svg$/)
+      .include.add(resolve('src/icons'))
+      .end()
+      .use('svg-sprite-loader')
+      .loader('svg-sprite-loader')
+      .options({
+        symbolId: 'icon-[name]'
+      })
+      .end()
+
+    config
+      .when(process.env.NODE_ENV !== 'development',
+        config => {
+          config
+            .plugin('ScriptExtHtmlWebpackPlugin')
+            .after('html')
+            .use('script-ext-html-webpack-plugin', [{
+            // `runtime` must same as runtimeChunk name. default is `runtime`
+              inline: /runtime\..*\.js$/
+            }])
+            .end()
+          config
+            .optimization.splitChunks({
+              chunks: 'all',
+              cacheGroups: {
+                libs: {
+                  name: 'chunk-libs',
+                  test: /[\\/]node_modules[\\/]/,
+                  priority: 10,
+                  chunks: 'initial' // only package third parties that are initially dependent
+                },
+                elementUI: {
+                  name: 'chunk-elementUI', // split elementUI into a single package
+                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
+                  test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
+                },
+                commons: {
+                  name: 'chunk-commons',
+                  test: resolve('src/components'), // can customize your rules
+                  minChunks: 3, //  minimum common number
+                  priority: 5,
+                  reuseExistingChunk: true
+                }
+              }
+            })
+          // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
+          config.optimization.runtimeChunk('single')
+        }
+      )
+  }
+}