浏览代码

Merge branch 'deploy' of jianguan-web/jg-ocs-html into master

陈瑞 4 年之前
父节点
当前提交
2ceb53999b
共有 100 个文件被更改,包括 11736 次插入196 次删除
  1. 3 2
      .env
  2. 2 1
      .env.development
  3. 3 2
      .env.preview
  4. 47 0
      public/adapter.js
  5. 50 0
      public/index.html
  6. 113 0
      src/api/allocateBill.js
  7. 47 0
      src/api/allocateType.js
  8. 13 5
      src/api/data.js
  9. 138 0
      src/api/dealer.js
  10. 57 0
      src/api/dealerRelation.js
  11. 44 0
      src/api/dealerScope.js
  12. 83 0
      src/api/dispatch.js
  13. 37 0
      src/api/notice.js
  14. 36 0
      src/api/noticeUser.js
  15. 109 0
      src/api/oos.js
  16. 6 6
      src/api/power-role.js
  17. 15 7
      src/api/power-user.js
  18. 101 0
      src/api/predict.js
  19. 214 0
      src/api/product.js
  20. 43 0
      src/api/productBrand.js
  21. 34 0
      src/api/productType.js
  22. 53 0
      src/api/promoActive.js
  23. 50 0
      src/api/promoRule.js
  24. 131 0
      src/api/sales.js
  25. 136 0
      src/api/salesDetail.js
  26. 143 0
      src/api/salesReturn.js
  27. 58 0
      src/api/salesReturnDetail.js
  28. 10 0
      src/api/settleStyle.js
  29. 87 0
      src/api/spareParts.js
  30. 111 0
      src/api/stock.js
  31. 50 0
      src/api/stockOut.js
  32. 32 0
      src/api/stockPut.js
  33. 42 0
      src/api/subarea.js
  34. 89 0
      src/api/supplier.js
  35. 67 0
      src/api/waitDispatchDetail.js
  36. 86 0
      src/api/warehouse.js
  37. 二进制
      src/assets/explain/def_calculation.png
  38. 二进制
      src/assets/explain/icon_example.png
  39. 二进制
      src/assets/explain/icon_inventory.png
  40. 二进制
      src/assets/explain/icon_mete.png
  41. 二进制
      src/assets/explain/icon_sales.png
  42. 二进制
      src/assets/explain/pressed_gray.png
  43. 1 0
      src/components/GlobalHeader/GlobalHeader.vue
  44. 27 19
      src/components/MultiTab/MultiTab.vue
  45. 53 10
      src/components/NoticeIcon/NoticeIcon.vue
  46. 1 1
      src/components/PageHeader/PageHeader.vue
  47. 28 4
      src/components/Table/index.js
  48. 72 30
      src/components/UploadFile/index.vue
  49. 224 2
      src/components/global.less
  50. 4 2
      src/components/tools/UserMenu.vue
  51. 1510 28
      src/config/router.config.js
  52. 7 3
      src/layouts/BasicLayout.vue
  53. 3 2
      src/layouts/PageView.vue
  54. 31 0
      src/libs/commonData.js
  55. 85 61
      src/libs/getDate.js
  56. 5 0
      src/libs/tools.js
  57. 1 0
      src/store/getters.js
  58. 3 1
      src/store/index.js
  59. 8 0
      src/store/modules/user.js
  60. 121 0
      src/store/modules/websocketStore.js
  61. 3 1
      src/utils/mixin.js
  62. 1 1
      src/utils/request.js
  63. 32 3
      src/views/Home.vue
  64. 217 0
      src/views/allocationManagement/transferOut/basicInfoModal.vue
  65. 187 0
      src/views/allocationManagement/transferOut/detail.vue
  66. 469 0
      src/views/allocationManagement/transferOut/edit.vue
  67. 290 0
      src/views/allocationManagement/transferOut/list.vue
  68. 159 0
      src/views/basicData/transferTypeManagement/editModal.vue
  69. 104 0
      src/views/basicData/transferTypeManagement/list.vue
  70. 162 0
      src/views/basicData/warehouse/editModal.vue
  71. 147 0
      src/views/basicData/warehouse/list.vue
  72. 183 0
      src/views/basicData/warehouse/storingLocation/editModal.vue
  73. 167 0
      src/views/basicData/warehouse/storingLocation/list.vue
  74. 162 0
      src/views/common/chooseBrandModal.vue
  75. 248 0
      src/views/common/chooseCustomerModal.vue
  76. 227 0
      src/views/common/chooseImportModal.vue
  77. 424 0
      src/views/common/chooseProductsModal.vue
  78. 280 0
      src/views/common/chooseSupplierModal.vue
  79. 168 0
      src/views/common/chooseTypeModal.vue
  80. 70 0
      src/views/common/custList.vue
  81. 30 5
      src/views/common/editInput.js
  82. 216 0
      src/views/common/importGuideModal.vue
  83. 68 0
      src/views/common/productBrand.js
  84. 60 0
      src/views/common/productType.js
  85. 64 0
      src/views/common/promoList.vue
  86. 61 0
      src/views/common/rangeDate.vue
  87. 70 0
      src/views/common/settleStyle.js
  88. 70 0
      src/views/common/subarea.js
  89. 89 0
      src/views/dealerManagement/dealerAccountManagement/detailModal.vue
  90. 213 0
      src/views/dealerManagement/dealerAccountManagement/editModal.vue
  91. 188 0
      src/views/dealerManagement/dealerAccountManagement/list.vue
  92. 172 0
      src/views/dealerManagement/dealerRelationshipBinding/associateModal.vue
  93. 208 0
      src/views/dealerManagement/dealerRelationshipBinding/list.vue
  94. 72 0
      src/views/dealerManagement/dealerRelationshipBinding/queryChild.vue
  95. 350 0
      src/views/dealerManagement/marketingDivisionSet/editModal.vue
  96. 112 0
      src/views/dealerManagement/marketingDivisionSet/list.vue
  97. 207 0
      src/views/dealerManagement/merchantInfoManagement/detailModal.vue
  98. 674 0
      src/views/dealerManagement/merchantInfoManagement/edit.vue
  99. 260 0
      src/views/dealerManagement/merchantInfoManagement/list.vue
  100. 328 0
      src/views/dealerManagement/merchantInfoManagement/permissionSetting.vue

+ 3 - 2
.env

@@ -1,8 +1,9 @@
 NODE_ENV=production
 VUE_APP_PREVIEW=false
-VUE_APP_API_BASE_URL=https://it.zyucgj.com/zyit/
+VUE_APP_API_BASE_URL=http://ocs-admin.360arrow.com/ocs-admin
+VUE_APP_WX_BASE_URL=//ocs-admin.360arrow.com/ocs-admin/websocket/
 VUE_APP_VERSION=V1.0.1
-VUE_APP_PRO_NAME=箭冠汽配BOSS系统
+VUE_APP_PRO_NAME=箭冠运营中心系统
 VUE_APP_LOGO=@/assets/logo.png
 VUE_APP_THEME_COLOR=#ed1c24
 VUE_APP_COM_NAME=广州市箭冠网络科技有限公司

+ 2 - 1
.env.development

@@ -1,8 +1,9 @@
 NODE_ENV=development
 VUE_APP_PREVIEW=true
 VUE_APP_API_BASE_URL=/api
+VUE_APP_WX_BASE_URL=//192.168.16.103:8602/ocs-admin/websocket/
 VUE_APP_VERSION=V1.0.1
-VUE_APP_PRO_NAME=箭冠汽配BOSS系统-dev
+VUE_APP_PRO_NAME=箭冠运营中心系统-dev
 VUE_APP_LOGO=@/assets/logo.png
 VUE_APP_THEME_COLOR=#ed1c24
 VUE_APP_COM_NAME=广州市箭冠网络科技有限公司

+ 3 - 2
.env.preview

@@ -1,8 +1,9 @@
 NODE_ENV=production
 VUE_APP_PREVIEW=true
-VUE_APP_API_BASE_URL=http://it.test.zyucgj.com/zyit
+VUE_APP_API_BASE_URL=http://ocs-admin.360arrow.com.cn/ocs-admin
+VUE_APP_WX_BASE_URL=//ocs-admin.360arrow.com.cn/ocs-admin/websocket/
 VUE_APP_VERSION=V1.0.1
-VUE_APP_PRO_NAME=箭冠汽配BOSS系统-pre
+VUE_APP_PRO_NAME=箭冠运营中心系统-pre
 VUE_APP_LOGO=@/assets/logo.png
 VUE_APP_THEME_COLOR=#ed1c24
 VUE_APP_COM_NAME=广州市箭冠网络科技有限公司

+ 47 - 0
public/adapter.js

@@ -0,0 +1,47 @@
+//  非谷歌浏览器或非IE11时,则提示下载谷歌浏览器进行访问
+function BrowserType () {
+  var userAgent = navigator.userAgent // 取得浏览器的userAgent字符串
+  var isOpera = userAgent.indexOf('Opera') > -1 // 判断是否Opera浏览器
+  // var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1 && !isOpera; //判断是否IE浏览器
+  var isIE = window.ActiveXObject || 'ActiveXObject' in window
+  // var isEdge = userAgent.indexOf("Windows NT 6.1; Trident/7.0;") > -1 && !isIE; //判断是否IE的Edge浏览器
+  var isEdge = userAgent.indexOf('Edge') > -1 // 判断是否IE的Edge浏览器
+  var isFF = userAgent.indexOf('Firefox') > -1 // 判断是否Firefox浏览器
+  var isSafari = userAgent.indexOf('Safari') > -1 && userAgent.indexOf('Chrome') == -1 // 判断是否Safari浏览器
+  var isChrome = userAgent.indexOf('Chrome') > -1 && userAgent.indexOf('Safari') > -1 && !isEdge // 判断Chrome浏览器
+
+  if (isIE) {
+    var reIE = new RegExp('MSIE (\\d+\\.\\d+);')
+    reIE.test(userAgent)
+    var fIEVersion = parseFloat(RegExp['$1'])
+    if (userAgent.indexOf('MSIE 6.0') != -1) {
+      return 'IE6'
+    } else if (fIEVersion == 7) {
+      return 'IE7'
+    } else if (fIEVersion == 8) {
+      return 'IE8'
+    } else if (fIEVersion == 9) {
+      return 'IE9'
+    } else if (fIEVersion == 10) {
+      return 'IE10'
+    } else if (userAgent.toLowerCase().match(/rv:([\d.]+)\) like gecko/)) {
+      return 'IE11'
+    } else { // IE版本过低
+      return '0'
+    }
+  } // isIE end
+
+  if (isFF) { return 'FF' }
+  if (isOpera) { return 'Opera' }
+  if (isSafari) { return 'Safari' }
+  if (isChrome) { return 'Chrome' }
+  if (isEdge) { return 'Edge' }
+} // myBrowser() end
+
+if (BrowserType() != 'Chrome' && BrowserType() != 'IE11') {
+  var con = alert('当前浏览器版本过低,为保证更好体验请下载谷歌浏览器进行操作, 点击【确定】升级,如不升级您将不能正常浏览网页!' + '\n' + '下载地址:“https://www.google.cn/chrome”') // 在页面上弹出对话框
+  if (con == true) {} else {
+    window.location = 'https://www.google.cn/chrome'
+  }
+}
+//  升级ie  https://support.microsoft.com/zh-cn/help/17621/internet-explorer-downloads

+ 50 - 0
public/index.html

@@ -11,6 +11,56 @@
     <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
     <link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" />
     <% } %>
+    <!-- <script src="./adapter.js" type="text/javascript"></script> -->
+    <script>
+      //  非谷歌浏览器或非IE11时,则提示下载谷歌浏览器进行访问
+      function BrowserType () {
+        var userAgent = navigator.userAgent // 取得浏览器的userAgent字符串
+        var isOpera = userAgent.indexOf('Opera') > -1 // 判断是否Opera浏览器
+        // var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1 && !isOpera; //判断是否IE浏览器
+        var isIE = window.ActiveXObject || 'ActiveXObject' in window
+        // var isEdge = userAgent.indexOf("Windows NT 6.1; Trident/7.0;") > -1 && !isIE; //判断是否IE的Edge浏览器
+        var isEdge = userAgent.indexOf('Edge') > -1 // 判断是否IE的Edge浏览器
+        var isFF = userAgent.indexOf('Firefox') > -1 // 判断是否Firefox浏览器
+        var isSafari = userAgent.indexOf('Safari') > -1 && userAgent.indexOf('Chrome') == -1 // 判断是否Safari浏览器
+        var isChrome = userAgent.indexOf('Chrome') > -1 && userAgent.indexOf('Safari') > -1 && !isEdge // 判断Chrome浏览器
+      
+        if (isIE) {
+          var reIE = new RegExp('MSIE (\\d+\\.\\d+);')
+          reIE.test(userAgent)
+          var fIEVersion = parseFloat(RegExp['$1'])
+          if (userAgent.indexOf('MSIE 6.0') != -1) {
+            return 'IE6'
+          } else if (fIEVersion == 7) {
+            return 'IE7'
+          } else if (fIEVersion == 8) {
+            return 'IE8'
+          } else if (fIEVersion == 9) {
+            return 'IE9'
+          } else if (fIEVersion == 10) {
+            return 'IE10'
+          } else if (userAgent.toLowerCase().match(/rv:([\d.]+)\) like gecko/)) {
+            return 'IE11'
+          } else { // IE版本过低
+            return '0'
+          }
+        } // isIE end
+      
+        if (isFF) { return 'FF' }
+        if (isOpera) { return 'Opera' }
+        if (isSafari) { return 'Safari' }
+        if (isChrome) { return 'Chrome' }
+        if (isEdge) { return 'Edge' }
+      } // myBrowser() end
+      
+      if (BrowserType() != 'Chrome' && BrowserType() != 'IE11') {
+        var con = alert('当前浏览器版本过低,为保证更好体验请下载谷歌浏览器进行操作, 点击【确定】升级,如不升级您将不能正常浏览网页!' + '\n' + '下载地址:“https://www.google.cn/chrome”') // 在页面上弹出对话框
+        if (con == true) {} else {
+          window.location = 'https://www.google.cn/chrome'
+        }
+      }
+      //  升级ie  https://support.microsoft.com/zh-cn/help/17621/internet-explorer-downloads
+    </script>
   </head>
   <body>
     <noscript>

+ 113 - 0
src/api/allocateBill.js

@@ -0,0 +1,113 @@
+import { axios } from '@/utils/request'
+
+//  调拨管理 列表  分页
+export const allocateBillList = (params) => {
+  const url = `/allocateBill/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+// 调拨管理  新增
+export const allocateBillSave = params => {
+  return axios({
+    url: '/allocateBill/save',
+    data: params,
+    method: 'post'
+  })
+}
+// 调拨管理  详情
+export const allocateBillDel = params => {
+  return axios({
+    url: `/allocateBill/delete/${params.sn}`,
+    data: {},
+    method: 'get'
+  })
+}
+// 调拨管理  删除
+export const allocateBillDetail = params => {
+  return axios({
+    url: `/allocateBill/findBySn/${params.sn}`,
+    data: {},
+    method: 'get'
+  })
+}
+// 调拨管理  审核
+export const allocateBillAudit = params => {
+  return axios({
+    url: `/allocateBill/audit/${params.sn}/${params.state}`,
+    data: {},
+    method: 'get'
+  })
+}
+// 调拨管理  提交
+export const allocateBillSubmit = params => {
+  return axios({
+    url: `/allocateBill/submit/${params.sn}`,
+    data: {},
+    method: 'get'
+  })
+}
+//  调拨管理 导出
+export const allocateBillExport = (params) => {
+  return axios({
+    url: '/allocateBill/exportExcel',
+    data: params,
+    method: 'post',
+    responseType: 'blob'
+  })
+}
+//  调拨管理  明细 列表  分页
+export const allocateBillDetailList = (params) => {
+  const url = `/allocateBill/detail/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  调拨管理  明细 列表  合计
+export const allocateBillDetailCount = (params) => {
+  return axios({
+    url: '/allocateBill/detail/queryCount',
+    data: params,
+    method: 'post'
+  })
+}
+// 调拨管理  详情  删除
+export const allocateBillDetailDel = params => {
+  return axios({
+    url: `/allocateBill/detail/delete/${params.id}`,
+    data: {},
+    method: 'get'
+  })
+}
+// 调拨管理  详情  整单删除
+export const allocateBillDetailDelAll = params => {
+  return axios({
+    url: `/allocateBill/detail/deleteAll/${params.sn}`,
+    data: {},
+    method: 'get'
+  })
+}
+// 调拨管理  详情  保存
+export const allocateBillDetailSave = params => {
+  return axios({
+    url: '/allocateBill/detail/save',
+    data: params,
+    method: 'post'
+  })
+}
+// 调拨管理 详情  打印
+export const allocateBillDetailPrint = params => {
+  return axios.request({
+    url: `allocateBill/print/${params.sn}/${params.isPreview}`,
+    method: 'get',
+    responseType: 'blob'
+  })
+}

+ 47 - 0
src/api/allocateType.js

@@ -0,0 +1,47 @@
+import { axios } from '@/utils/request'
+
+//  调拨类型管理 列表  分页
+export const allocateTypeList = (params) => {
+  const url = `/allocateType/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+// 调拨类型管理 列表  无分页
+export const allocateTypeAllList = params => {
+  return axios({
+    url: '/allocateType/queryList',
+    data: params,
+    method: 'post'
+  })
+}
+// 调拨类型管理  新增/编辑
+export const allocateTypeSave = params => {
+  return axios({
+    url: '/allocateType/save',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 调拨类型管理  删除
+export const allocateTypeDel = params => {
+  return axios({
+    url: `/allocateType/delete/${params.sn}`,
+    data: {},
+    method: 'get'
+  })
+}
+
+// 调拨类型管理  详情
+export const allocateTypeDetail = params => {
+  return axios({
+    url: `/allocateType/findBySn/${params.sn}`,
+    data: {},
+    method: 'get'
+  })
+}

+ 13 - 5
src/api/data.js

@@ -9,7 +9,7 @@ export function login (parameter) {
 }
 
 export const listLookUp = params => {
-  let url = `/lookup/queryLike`
+  const url = `/lookup/queryLike`
   return axios({
     url: url,
     data: params,
@@ -18,7 +18,7 @@ export const listLookUp = params => {
 }
 
 export const getLookUpData = (params) => {
-  let url = `/lookupItem/query/${params.pageNo}/${params.pageSize}`
+  const url = `/lookupItem/query/${params.pageNo}/${params.pageSize}`
   delete params.pageNo
   delete params.pageSize
   return axios({
@@ -107,14 +107,14 @@ function randomStr (len) {
 // 查询省
 export const getProvince = () => {
   return axios({
-    url: `/area/findProvince`,
+    url: `/area/province`,
     method: 'post'
   })
 }
 // 查询市
 export const getCityByPro = params => {
   return axios({
-    url: `/area/findCity/${params.id}`,
+    url: `/area/city/${params.id}`,
     data: params,
     method: 'post'
   })
@@ -122,7 +122,15 @@ export const getCityByPro = params => {
 // 查询区
 export const getDistrictByCity = params => {
   return axios({
-    url: `/area/findDistrict/${params.id}`,
+    url: `/area/district/${params.id}`,
+    data: params,
+    method: 'post'
+  })
+}
+// 查询省/市/区
+export const getArea = (params) => {
+  return axios({
+    url: `/area/queryList`,
     data: params,
     method: 'post'
   })

+ 138 - 0
src/api/dealer.js

@@ -0,0 +1,138 @@
+import { axios } from '@/utils/request'
+
+//  根据sn查找经销商详情
+export const dealerDetailBySn = (params) => {
+  return axios({
+    url: `/dealer/findBySn/${params.sn}`,
+    data: params,
+    method: 'get'
+  })
+}
+// 根据sn查找修改过后的经销商信息
+export const dealerFindUpdateInfoBySn = (params) => {
+  return axios({
+    url: `/dealer/findUpdateInfoBySn/${params.sn}`,
+    data: params,
+    method: 'get'
+  })
+}
+//  经销商列表有分页
+export const dealerQueryList = (params) => {
+  const url = `/dealer/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  经销商 列表 有分页
+export const dealerSubareaScopeList = (params) => {
+  const url = `/dealer/queryBySubareaScope/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  经销商保存
+export const dealerSave = (params) => {
+  return axios({
+    url: '/dealer/save',
+    data: params,
+    method: 'post'
+  })
+}
+//  经销商 导出
+export const dealerExport = (params) => {
+  return axios({
+    url: '/dealer/exportList',
+    data: params,
+    method: 'post',
+    responseType: 'blob'
+  })
+}
+// 审核经销商资料
+export const dealerAudit = (params) => {
+  return axios({
+    url: `/dealer/audit/${params.dealerAuditSn}/${params.auditState}`,
+    method: 'get'
+  })
+}
+
+// 更新经销级别
+export const updateDealerLevel = (params) => {
+  return axios({
+    url: `/dealer/updateDealerLevel/${params.dealerSn}/${params.dealerLevel}`,
+    method: 'get'
+  })
+}
+
+// 更新合作状态
+export const updateCooperate = (params) => {
+  return axios({
+    url: '/dealer/updateCooperate',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  经销商账号  列表  有分页
+export const dealerUserList = (params) => {
+  const url = `/dealer/user/queryLike/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+// 经销商账号  详情
+export const dealerUserDetail = (params) => {
+  return axios({
+    url: `/dealer/user/findById/${params.id}`,
+    method: 'get'
+  })
+}
+// 经销商账号  删除
+export const dealerUserDel = (params) => {
+  return axios({
+    url: `/dealer/user/delete/${params.id}`,
+    method: 'get'
+  })
+}
+// 经销商账号  启禁用
+export const dealerUserEnable = (params) => {
+  return axios({
+    url: `/dealer/user/enable/${params.id}/${params.flag}`,
+    method: 'get'
+  })
+}
+// 经销商账号  修改密码
+export const dealerUserChangeP = (params) => {
+  return axios({
+    url: `/dealer/user/changePWD`,
+    data: params,
+    method: 'post'
+  })
+}
+// 经销商账号  重置密码
+export const dealerUserResetP = (params) => {
+  return axios({
+    url: `/dealer/user/resetPwd`,
+    data: params,
+    method: 'post'
+  })
+}
+// 经销商账号  保存
+export const dealerUserSave = (params) => {
+  return axios({
+    url: `/dealer/user/save`,
+    data: params,
+    method: 'post'
+  })
+}

+ 57 - 0
src/api/dealerRelation.js

@@ -0,0 +1,57 @@
+import { axios } from '@/utils/request'
+
+// 绑定经销商关系
+export const bindRelation = (params) => {
+  return axios({
+    url: `/dealerRelation/bindRelation/${params.parentDealerSn}/${params.subDealerSn}`,
+    method: 'get'
+  })
+}
+
+//  经销商关系绑定 列表  有分页
+export const dealerRelationList = (params) => {
+  const url = `/dealerRelation/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 分页查询返利信息
+export const queryRebatePage = (params) => {
+  const url = `/dealerRelation/queryRebatePage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 根据父经销商查找子经销商列表
+export const querySubList = (params) => {
+  return axios({
+    url: `/dealerRelation/querySubList/${params.parentDealerSn}`,
+    method: 'get'
+  })
+}
+
+// 解绑经销商关系
+export const unbindRelation = (params) => {
+  return axios({
+    url: `/dealerRelation/unbindRelation/${params.subDealerSn}`,
+    method: 'get'
+  })
+}
+
+// 更新经销商返利信息
+export const updateRebate = (params) => {
+  return axios({
+    url: `/dealerRelation/updateRebate/${params.dealerSn}/${params.rebateDealerSn}`,
+    method: 'get'
+  })
+}

+ 44 - 0
src/api/dealerScope.js

@@ -0,0 +1,44 @@
+import { axios } from '@/utils/request'
+
+//  经销权 列表 有分页
+export const dealerScopeList = (params) => {
+  const url = `/dealerScope/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  经销权 列表 无分页
+export const dealerScopeQueryList = (params) => {
+  return axios({
+    url: '/dealerScope/queryList',
+    data: params,
+    method: 'post'
+  })
+}
+//  经销权  添加
+export const dealerScopeSave = (params) => {
+  return axios({
+    url: '/dealerScope/addDealerScope',
+    data: params,
+    method: 'post'
+  })
+}
+// 经销权 删除
+export const dealerScopeDel = (params) => {
+  return axios({
+    url: `/dealerScope/deleteBySn/${params.sn}`,
+    method: 'get'
+  })
+}
+//  经销权  校验产品是否被包含在品牌分类中
+export const dealerScopeValidProduct = (params) => {
+  return axios({
+    url: '/dealerScope/validProductIsIncloude',
+    data: params,
+    method: 'post'
+  })
+}

+ 83 - 0
src/api/dispatch.js

@@ -0,0 +1,83 @@
+import { axios } from '@/utils/request'
+
+// 发货列表分页
+export const dispatchlList = (params) => {
+  const url = `/dispatch/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 发货单明细列表分页
+export const dispatchDetaillList = (params) => {
+  const url = `/dispatch/detail/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 根据销售单SN查询发货单
+export const findBySalesBillSn = (params) => {
+  return axios({
+    url: `/dispatch/findBySalesBillSn/${params.salesBillSn}`,
+    method: 'get'
+  })
+}
+// 根据发货单SN查询发货单对象
+export const dispatchFindBySn = (params) => {
+  return axios({
+    url: `/dispatch/findBySn/${params.dispatchBillSn}`,
+    method: 'get'
+  })
+}
+// 发货单统计查询
+export const dispatchQueryCount = (params) => {
+  return axios({
+    url: '/dispatch/queryCount',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 出库
+export const dispatchStockOut = (params) => {
+  return axios({
+    url: `/dispatch/stockOut/${params.dispatchBillSn}`,
+    method: 'get'
+  })
+}
+
+// 备货审核
+export const dispatchStockUpAduit = (params) => {
+  return axios({
+    url: '/dispatch/stockUpAduit',
+    data: params,
+    method: 'post'
+  })
+}
+// 下推 详情  打印
+export const dispatchDetailPrint = params => {
+  const url = `/dispatch/print/${params.type}`
+  delete params.type
+  return axios.request({
+    url: url,
+    data: params,
+    method: 'post',
+    responseType: 'blob'
+  })
+}
+// 下推  详情  该销售单的产品二级分类
+export const dispatchDetailType = (params) => {
+  return axios({
+    url: `/dispatch/detail/queryProductType/${params.dispatchBillSn}`,
+    method: 'get'
+  })
+}

+ 37 - 0
src/api/notice.js

@@ -0,0 +1,37 @@
+import { axios } from '@/utils/request'
+
+//  公告 列表  有分页
+export const noticeList = (params) => {
+  const url = `/notice/queryLike/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  公告 保存
+export const noticeSave = (params) => {
+  return axios({
+    url: '/notice/save',
+    data: params,
+    method: 'post'
+  })
+}
+//  公告 删除
+export const noticeDel = (params) => {
+  const url = `/notice/delete/${params.id}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}
+//  公告 详情
+export const noticeDetail = (params) => {
+  const url = `/notice/findById/${params.id}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}

+ 36 - 0
src/api/noticeUser.js

@@ -0,0 +1,36 @@
+import { axios } from '@/utils/request'
+
+//  公告 列表  有分页
+export const noticeUserList = (params) => {
+  const url = `/noticeUser/queryLike/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  公告 详情
+export const noticeUserDetail = (params) => {
+  const url = `/notice/findById/${params.id}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}
+
+// 获取通知消息未读数
+export const getUnreadCount = params => {
+  return axios({
+    url: 'noticeUser/queryNotReadCount',
+    method: 'post'
+  })
+}
+// 设置已读消息
+export const hasRead = id => {
+  return axios({
+    url: `noticeUser/setRead/${id}`,
+    method: 'get'
+  })
+}

+ 109 - 0
src/api/oos.js

@@ -0,0 +1,109 @@
+import { axios } from '@/utils/request'
+
+//  缺货  列表  分页
+export const oosList = (params) => {
+  const url = `/oos/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  缺货  详情
+export const oosDetail = (params) => {
+  const url = `/oos/findBySn/${params.sn}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}
+//  缺货 导出
+export const oosDetailExport = (params) => {
+  return axios({
+    url: '/oos/detail/exportByBuyer',
+    data: params,
+    method: 'post',
+    responseType: 'blob'
+  })
+}
+//  缺货  详情  列表  分页
+export const oosDetailList = (params) => {
+  const url = `/oos/detail/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+// 缺货统计  按客户  列表  分页
+export const oosBuyerList = (params) => {
+  const url = `/oos/detail/queryPageByBuyer/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+// 缺货统计  按客户  合计  本页
+export const oosBuyerDetailPageCount = (params) => {
+  const url = `/oos/detail/queryPageCountByBuyer/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+// 缺货统计  按客户  合计
+export const oosBuyerDetailCount = (params) => {
+  return axios({
+    url: '/oos/detail/queryAllCountByBuyer',
+    data: params,
+    method: 'post'
+  })
+}
+// 缺货统计  按产品  列表  分页
+export const oosProductList = (params) => {
+  const url = `/oos/detail/queryPageByProduct/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+// 缺货统计  按产品  合计  本页
+export const oosProductDetailPageCount = (params) => {
+  const url = `/oos/detail/queryPageCountByProduct/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+// 缺货统计  按产品  合计
+export const oosProductDetailCount = (params) => {
+  return axios({
+    url: '/oos/detail/queryAllCountByProduct',
+    data: params,
+    method: 'post'
+  })
+}
+// 缺货 详情  打印
+export const oosDetailPrint = params => {
+  return axios.request({
+    url: `oos/print/${params.sn}`,
+    method: 'get',
+    responseType: 'blob'
+  })
+}

+ 6 - 6
src/api/power-role.js

@@ -2,7 +2,7 @@ import { axios } from '@/utils/request'
 
 // 获取列表数据
 export const getPowerRoleList = params => {
-  const url = `/role/queryLike/${params.pageNo}/${params.pageSize}`
+  const url = `/yyrole/queryLike/${params.pageNo}/${params.pageSize}`
   delete params.pageNo
   delete params.pageSize
   return axios({
@@ -15,7 +15,7 @@ export const getPowerRoleList = params => {
 // 改变权限状态接口 flag 0:禁用 1:启用
 export const updateEnableStatus = params => {
   return axios({
-    url: `/role/enable/${params.id}/${params.flag}`,
+    url: `/yyrole/enable/${params.id}/${params.flag}`,
     data: {},
     method: 'get'
   })
@@ -24,7 +24,7 @@ export const updateEnableStatus = params => {
 // 删除用户接口
 export const delectRolePower = params => {
   return axios({
-    url: `/role/delete/${params.id}`,
+    url: `/yyrole/delete/${params.id}`,
     data: {},
     method: 'get'
   })
@@ -33,7 +33,7 @@ export const delectRolePower = params => {
 // 新增/编辑保存接口
 export const saveRolePower = params => {
   return axios({
-    url: '/role/save',
+    url: '/yyrole/save',
     data: params,
     method: 'POST'
   })
@@ -41,7 +41,7 @@ export const saveRolePower = params => {
 
 // 获取菜单树数据
 export const getMenuList = params => {
-  const url = `/role/findAllMenu/${params.id}`
+  const url = `/yyrole/findAllMenu/${params.id}`
   return axios({
     url: url,
     method: 'get'
@@ -50,7 +50,7 @@ export const getMenuList = params => {
 
 // 保存权限分配
 export const addMenuPower = params => {
-  const url = `/role/saveRoleMenu`
+  const url = `/yyrole/saveRoleMenu`
   return axios({
     url: url,
     data: params,

+ 15 - 7
src/api/power-user.js

@@ -3,7 +3,7 @@ import { axios } from '@/utils/request'
 // 重置密码
 export const resetPSD = params => {
   return axios({
-    url: '/user/resetPwd',
+    url: '/yyuser/resetPwd',
     data: params,
     method: 'POST'
   })
@@ -11,7 +11,7 @@ export const resetPSD = params => {
 
 // 获取列表数据
 export const getPowerUserList = params => {
-  const url = `/user/queryLike/${params.pageNo}/${params.pageSize}`
+  const url = `/ocsuser/queryLikePage/${params.pageNo}/${params.pageSize}`
   delete params.pageNo
   delete params.pageSize
   return axios({
@@ -24,7 +24,7 @@ export const getPowerUserList = params => {
 // 改变权限状态接口
 export const updateEnableStatus = params => {
   return axios({
-    url: `/user/enable/${params.id}/${params.flag}`,
+    url: `/yyuser/enable/${params.id}/${params.flag}`,
     data: {},
     method: 'get'
   })
@@ -33,7 +33,7 @@ export const updateEnableStatus = params => {
 // 删除用户接口
 export const delectUserPower = params => {
   return axios({
-    url: `/user/delete/${params.id}`,
+    url: `/yyuser/delete/${params.id}`,
     data: {},
     method: 'get'
   })
@@ -42,7 +42,7 @@ export const delectUserPower = params => {
 // 新增/编辑保存接口
 export const saveUserPower = params => {
   return axios({
-    url: '/user/save',
+    url: '/yyuser/save',
     data: params,
     method: 'POST'
   })
@@ -51,8 +51,16 @@ export const saveUserPower = params => {
 // 获取角色列表接口
 export const getRoleList = params => {
   return axios({
-    url: '/role/findAll',
+    url: '/yyrole/findAll',
     data: params,
     method: 'POST'
   })
-}
+}
+// 用户管理   分区设置
+export const userSubareaSave = params => {
+  return axios({
+    url: '/userSubarea/save',
+    data: params,
+    method: 'post'
+  })
+}

+ 101 - 0
src/api/predict.js

@@ -0,0 +1,101 @@
+import { axios } from '@/utils/request'
+
+//  智能补货列表  无分页
+export const predictList = (params) => {
+  return axios({
+    url: '/predict/stockPredict/queryList',
+    data: params,
+    method: 'post'
+  })
+}
+//  智能补货  产品范围列表  无分页
+export const predictRangeList = (params) => {
+  const url = `/predict/stockPredict/queryRangeList/${params.sn}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}
+//  智能补货  趋势平均列表
+export const predictTrendList = (params) => {
+  return axios({
+    url: '/predict/stockPredict/queryTrendList',
+    params: params,
+    method: 'get'
+  })
+}
+//  智能补货  保存
+export const predictSave = (params) => {
+  return axios({
+    url: '/predict/stockPredict/save',
+    data: params,
+    method: 'post'
+  })
+}
+//  智能补货  删除
+export const predictDel = (params) => {
+  const url = `/predict/stockPredict/delete/${params.sn}`
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  智能补货  详情
+export const predictDetail = (params) => {
+  const url = `/predict/stockPredict/queryBySn/${params.sn}`
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  智能补货  产品范围 保存
+export const predictRangeSave = (params) => {
+  return axios({
+    url: '/predict/stockPredict/saveBatchRange',
+    data: params,
+    method: 'post'
+  })
+}
+//  智能补货  产品范围 删除
+export const predictRangeDel = (params) => {
+  return axios({
+    url: '/predict/stockPredict/deleteRange',
+    data: params,
+    method: 'post'
+  })
+}
+//  智能补货  计算
+export const predictRun = (params) => {
+  return axios({
+    url: '/predict/stockPredict/run',
+    data: params,
+    method: 'post'
+  })
+}
+//  智能补货  基础信息设置  批量插入
+export const predictProductInfoInsert = (params) => {
+  return axios({
+    url: '/predictProductInfo/batchInsert',
+    data: params,
+    method: 'post'
+  })
+}
+//  智能补货  基础信息设置  下载
+export const predictProductInfoExport = (params) => {
+  return axios({
+    url: '/predictProductInfo/exportExcel',
+    data: params,
+    method: 'post',
+    responseType: 'blob'
+  })
+}
+//  智能补货  基础信息设置  解析
+export const predictProductInfoGoods = (params) => {
+  return axios({
+    url: '/predictProductInfo/parseGoods',
+    data: params,
+    method: 'post'
+  })
+}

+ 214 - 0
src/api/product.js

@@ -0,0 +1,214 @@
+import { axios } from '@/utils/request'
+
+//  产品 列表  分页
+export const productList = (params) => {
+  const url = `/product/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  产品 列表 已定过价的 分页
+export const productPricedList = (params) => {
+  const url = `/product/queryPricedPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  产品 保存
+export const productSave = (params) => {
+  return axios({
+    url: '/product/save',
+    data: params,
+    method: 'post'
+  })
+}
+//  产品 删除
+export const productDel = (params) => {
+  return axios({
+    url: `/product/delete/${params.sn}`,
+    method: 'get'
+  })
+}
+//  产品 导出
+export const productExport = (params) => {
+  return axios({
+    url: '/product/exportExcel',
+    data: params,
+    method: 'post',
+    responseType: 'blob'
+  })
+}
+//  产品 详情  根据sn查询
+export const productSnDetail = (params) => {
+  return axios({
+    url: `/product/findBySn/${params.sn}`,
+    method: 'get'
+  })
+}
+//  产品 审核
+export const productAudit = (params) => {
+  return axios({
+    url: `/product/audit/${params.sn}`,
+    method: 'get'
+  })
+}
+//  产品 批量审核
+export const productBatchAudit = (params) => {
+  return axios({
+    url: '/product/batchAudit',
+    data: params,
+    method: 'post'
+  })
+}
+//  产品 上线
+export const productOnline = (params) => {
+  return axios({
+    url: `/product/online/${params.sn}`,
+    method: 'get'
+  })
+}
+//  产品 下线
+export const productOffline = (params) => {
+  return axios({
+    url: `/product/offline`,
+    data: params,
+    method: 'post'
+  })
+}
+//  产品 批量上线
+export const productBatchOnline = (params) => {
+  return axios({
+    url: '/product/batchOnline',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  产品  定价  列表  分页
+export const productPricingList = (params) => {
+  const url = `/product/pricing/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  产品  定价 详情  根据sn查询
+export const productPricingSnDetail = (params) => {
+  return axios({
+    url: `/product/pricing/getPricingInfo/${params.sn}`,
+    method: 'get'
+  })
+}
+//  产品  定价 编辑
+export const productPricingSave = (params) => {
+  return axios({
+    url: '/product/pricing/save',
+    data: params,
+    method: 'post'
+  })
+}
+//  产品  定价 审核
+export const productPricingAudit = (params) => {
+  return axios({
+    url: '/product/pricing/audit',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  产品  上线审核  列表  分页
+export const productOnlineList = (params) => {
+  const url = `/product/online/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  产品 上线审核  审核
+export const productOnlineAudit = (params) => {
+  return axios({
+    url: `/product/auditOnline/${params.sn}`,
+    method: 'get'
+  })
+}
+//  产品 批量上线审核
+export const productBatchOnlineAudit = (params) => {
+  return axios({
+    url: '/product/batchAuditOnline',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  产品  下线审核  列表  分页
+export const productOfflineList = (params) => {
+  const url = `/product/offline/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  产品 下线审核  审核
+export const productOfflineAudit = (params) => {
+  return axios({
+    url: `/product/auditOffline/${params.sn}`,
+    method: 'get'
+  })
+}
+//  产品 批量下线审核
+export const productBatchOfflineAudit = (params) => {
+  return axios({
+    url: '/product/batchAuditOffline',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  产品  价格变更记录  列表  分页
+export const productPriceChangeList = (params) => {
+  const url = `/product/priceChange/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  价格变更记录 导出
+export const productPriceChangeExport = (params) => {
+  return axios({
+    url: '/product/priceChange/exportExcel',
+    data: params,
+    method: 'post',
+    responseType: 'blob'
+  })
+}
+//  产品  级别 列表  分页
+export const productLevelList = (params) => {
+  const url = `/product/level/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}

+ 43 - 0
src/api/productBrand.js

@@ -0,0 +1,43 @@
+import { axios } from '@/utils/request'
+
+//  产品品牌 列表   无分页
+export const productBrandQuery = (params) => {
+  return axios({
+    url: '/productBrand/query',
+    data: params,
+    method: 'post'
+  })
+}
+//  产品品牌 列表  分页
+export const productBrandList = (params) => {
+  const url = `/productBrand/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  产品品牌 保存
+export const productBrandSave = (params) => {
+  return axios({
+    url: '/productBrand/save',
+    data: params,
+    method: 'post'
+  })
+}
+//  产品品牌 删除
+export const productBrandDel = (params) => {
+  return axios({
+    url: `/productBrand/delete/${params.sn}`,
+    method: 'get'
+  })
+}
+//  产品品牌 详情  根据sn查询
+export const productBrandSnDetail = (params) => {
+  return axios({
+    url: `/productBrand/findBySn/${params.sn}`,
+    method: 'get'
+  })
+}

+ 34 - 0
src/api/productType.js

@@ -0,0 +1,34 @@
+import { axios } from '@/utils/request'
+
+// //  产品分类 列表   一层分类查询   无分页
+// export const productTypeQueryList = (params) => {
+//   return axios({
+//     url: '/productType/queryList',
+//     data: params,
+//     method: 'post'
+//   })
+// }
+//  产品分类 列表  多层分类查询   无分页
+export const productTypeQuery = (params) => {
+  return axios({
+    url: '/productType/query',
+    data: params,
+    method: 'post'
+  })
+}
+// 产品分类  新增/编辑
+export const productTypeSave = params => {
+  return axios({
+    url: '/productType/save',
+    data: params,
+    method: 'post'
+  })
+}
+// 产品分类  删除
+export const productTypeDel = params => {
+  return axios({
+    url: `/productType/delete/${params.sn}`,
+    data: {},
+    method: 'get'
+  })
+}

+ 53 - 0
src/api/promoActive.js

@@ -0,0 +1,53 @@
+import { axios } from '@/utils/request'
+
+//  优惠活动 列表  有分页
+export const promoActiveList = (params) => {
+  const url = `/promoActive/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  优惠活动 保存
+export const promoActiveSave = (params) => {
+  return axios({
+    url: '/promoActive/save',
+    data: params,
+    method: 'post'
+  })
+}
+//  优惠活动 删除
+export const promoActiveDel = (params) => {
+  const url = `/promoActive/delete/${params.sn}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}
+//  优惠活动 详情
+export const promoActiveDetail = (params) => {
+  const url = `/promoActive/findBySn/${params.sn}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}
+//  优惠活动 启禁用
+export const promoActiveEnable = (params) => {
+  const url = `/promoActive/enable/${params.sn}/${params.flag}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}
+//  优惠活动 详情
+export const promoActiveDetailD = (params) => {
+  const url = `/promoActive/findDetailBySn/${params.sn}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}

+ 50 - 0
src/api/promoRule.js

@@ -0,0 +1,50 @@
+import { axios } from '@/utils/request'
+
+//  优惠活动 规则 列表  无分页
+export const promoRuleQueryList = (params) => {
+  return axios({
+    url: '/promoRule/queryList',
+    data: params,
+    method: 'post'
+  })
+}
+//  优惠活动 保存
+export const promoRuleSave = (params) => {
+  return axios({
+    url: '/promoRule/save',
+    data: params,
+    method: 'post'
+  })
+}
+//  优惠活动 删除
+export const promoRuleDel = (params) => {
+  const url = `/promoRule/delete/${params.sn}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}
+//  优惠活动 详情
+export const promoRuleDetail = (params) => {
+  const url = `/promoRule/findBySn/${params.sn}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}
+//  优惠活动 详情  包含规则
+export const promoRuleDetailD = (params) => {
+  const url = `/promoRule/findDetailBySn/${params.sn}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}
+//  促销规则  获取可导入和不可导入列表数据
+export const promoRuleGoods = (params) => {
+  return axios({
+    url: '/promoRule/parseGoods',
+    data: params,
+    method: 'post'
+  })
+}

+ 131 - 0
src/api/sales.js

@@ -0,0 +1,131 @@
+import { axios } from '@/utils/request'
+
+//  销售 审核
+export const salesWriteAudit = (params) => {
+  return axios({
+    url: '/sales/audit',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售 删除
+export const salesDel = (params) => {
+  return axios({
+    url: `/sales/delete/${params.salesBillSn}`,
+    method: 'get'
+  })
+}
+
+//  销售 详情bysn
+export const salesDetailBySn = (params) => {
+  return axios({
+    url: `/sales/findBySn/${params.salesBillSn}`,
+    data: params,
+    method: 'get'
+  })
+}
+
+//  销售 新增或编辑
+export const salesSave = (params) => {
+  return axios({
+    url: '/sales/insert',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售 打印
+export const salesPrint = (params) => {
+  return axios({
+    url: '/sales/print',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售 打印预览
+export const salesPrintPreview = (params) => {
+  return axios({
+    url: '/sales/printPreview',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 销售 统计查询
+export const salesCount = (params) => {
+  return axios({
+    url: `/sales/queryCount`,
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售 列表  有分页
+export const salesList = (params) => {
+  const url = `/sales/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售 提交
+export const salesWriteSubmit = (params) => {
+  return axios({
+    url: `/sales/submit/${params.salesBillSn}`,
+    data: params,
+    method: 'get'
+  })
+}
+//  财务收款 列表 分页
+export const salesReceiptList = (params) => {
+  const url = `/sales/queryPageByReceipt/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  财务收款
+export const salesReceipt = (params) => {
+  return axios({
+    url: `/sales/receipt/${params.sn}`,
+    data: params,
+    method: 'get'
+  })
+}
+
+// 获取促销活动
+export const getPromoacActiveList = (params) => {
+  return axios({
+    url: `/sales/getPromoacActiveList/${params.salesBillSn}`,
+    data: params,
+    method: 'get'
+  })
+}
+//  促销订单统计 列表  有分页
+export const salesPromoList = (params) => {
+  const url = `/sales/queryPageByPromo/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  促销订单统计 合计
+export const salesPromoCount = (params) => {
+  return axios({
+    url: '/sales/queryCountByPromo',
+    data: params,
+    method: 'post'
+  })
+}

+ 136 - 0
src/api/salesDetail.js

@@ -0,0 +1,136 @@
+import { axios } from '@/utils/request'
+
+//  销售详情 删除
+export const salesDetailDel = (params) => {
+  return axios({
+    url: `/sales/detail/delete`,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 一键发货
+export const salesDetailDispatchByOneKey = (params) => {
+  return axios({
+    url: `/sales/detail/dispatchByOneKey/${params.salesBillSn}`,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 新增销售明细
+export const salesDetailInsert = (params) => {
+  return axios({
+    url: '/sales/detail/insert',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 批量新增代发货信息
+export const insertBatchOfWaitDispatch = (params) => {
+  return axios({
+    url: '/sales/detail/insertBatchOfWaitDispatch',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 销售详情列表分页
+export const salesDetailList = (params) => {
+  const url = `/sales/detail/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 销售详情列表不分页
+export const salesDetailAllList = (params) => {
+  const url = `/sales/detail/query`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 修改销售明细取消数量
+export const salesDetailUpdateCancelQty = (params) => {
+  return axios({
+    url: '/sales/detail/updateBatchCancelQty',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  修改销售明细数量
+export const salesDetailUpdateQty = (params) => {
+  return axios({
+    url: '/sales/detail/updateQty',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售详情 整单删除
+export const salesDetailDelAll = (params) => {
+  return axios({
+    url: `/sales/detail/deleteAll`,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 获取产品适用活动的促销产品列表
+export const getPromoGoodsList = (params) => {
+  return axios({
+    url: `/sales/detail/getPromoGoodsList`,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 批量添加促销品
+export const addPromoGoods = (params) => {
+  return axios({
+    url: `/sales/detail/addPromoGoods`,
+    data: params,
+    method: 'post'
+  })
+}
+// 促销产品统计  列表  分页
+export const salesDetailPromoList = (params) => {
+  const url = `/sales/detail/queryPageByPromo/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+// 促销产品统计  合计
+export const salesDetailPromoCount = (params) => {
+  return axios({
+    url: `/sales/detail/queryCountByPromo`,
+    data: params,
+    method: 'post'
+  })
+}
+// 促销产品统计  详情  列表  分页
+export const salesDetailPromoProductList = (params) => {
+  const url = `/sales/detail/queryPageOfPromoProduct/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}

+ 143 - 0
src/api/salesReturn.js

@@ -0,0 +1,143 @@
+import { axios } from '@/utils/request'
+
+//  销售退货 审核
+export const salesReturnAudit = (params) => {
+  return axios({
+    url: `/salesReturn/audit`,
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货 品检
+export const salesReturnCheck = (params) => {
+  return axios({
+    url: `/salesReturn/check`,
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货 删除
+export const salesReturnDel = (params) => {
+  return axios({
+    url: `/salesReturn/delete/${params.salesReturnBillSn}`,
+    method: 'get'
+  })
+}
+
+// 根据SN查询销售退货单
+export const salesReturnDetail = (params) => {
+  return axios({
+    url: `/salesReturn/findBySn/${params.sn}`,
+    method: 'get'
+  })
+}
+
+// 新建销售退货单
+export const salesReturnInsert = (params) => {
+  return axios({
+    url: '/salesReturn/insert',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 销售退货单付款
+export const salesReturnPay = (params) => {
+  return axios({
+    url: '/salesReturn/pay',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货 打印
+export const salesReturnPrint = (params) => {
+  return axios({
+    url: '/salesReturn/print',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货 打印预览
+export const salesReturnPrintPreview = (params) => {
+  return axios({
+    url: '/salesReturn/printPreview',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货 统计查询
+export const salesReturnQueryCount = (params) => {
+  return axios({
+    url: '/salesReturn/queryCount',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货 分页查询产品
+export const salesReturnList = (params) => {
+  const url = `/salesReturn/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货 提交
+export const salesReturnSubmit = (params) => {
+  return axios({
+    url: `/salesReturn/submit/${params.salesReturnBillSn}`,
+    method: 'get'
+  })
+}
+
+// 抓单列表
+export const salesQueryByReturn = (params) => {
+  const url = `/sales/detail/queryByReturn/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 退货确认  列表  分页
+export const salesReturnFinancialList = (params) => {
+  const url = `/salesReturn/queryPageByFinancial/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+// 退货确认  详情  列表  分页
+export const salesReturnFinancialDetailList = (params) => {
+  const url = `/salesReturn/detail/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+// 退货确认 退货确认
+export const salesReturnFinancial = (params) => {
+  return axios({
+    url: '/salesReturn/financial',
+    data: params,
+    method: 'post'
+  })
+}

+ 58 - 0
src/api/salesReturnDetail.js

@@ -0,0 +1,58 @@
+import { axios } from '@/utils/request'
+
+
+//  销售退货明细 删除
+export const salesReturnDetailDel = (params) => {
+  return axios({
+    url: `/salesReturn/detail/delete/${params.salesReturnDetailSn}`,
+    method: 'get'
+  })
+}
+
+//  新增销售退货明细
+export const salesReturnDetailInsert = (params) => {
+  return axios({
+    url: '/salesReturn/detail/insert',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 修改销售退货明细返库数量
+export const updateBackStockQty = (params) => {
+  return axios({
+    url: '/salesReturn/detail/updateBackStockQty',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 分页查询销售退货明细
+export const salesReturnDetailList = (params) => {
+  const url = `/salesReturn/detail/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 修改销售退货明细数量
+export const salesReturnDetailUpdateQty = (params) => {
+  return axios({
+    url: '/salesReturn/detail/updateQty',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 修改销售退货明细退货原因
+export const salesReturnDetailUpdateReason = (params) => {
+  return axios({
+    url: '/salesReturn/detail/updateReason',
+    data: params,
+    method: 'post'
+  })
+}

+ 10 - 0
src/api/settleStyle.js

@@ -0,0 +1,10 @@
+import { axios } from '@/utils/request'
+
+//  结算方式列表
+export const settleStyleQueryAll = (params) => {
+  return axios({
+    url: '/settleStyle/findAll',
+    data: params,
+    method: 'post'
+  })
+}

+ 87 - 0
src/api/spareParts.js

@@ -0,0 +1,87 @@
+import { axios } from '@/utils/request'
+
+//  散件入库 列表  分页
+export const sparePartsList = (params) => {
+  const url = `/spareParts/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 审核
+export const sparePartsAudit = (params) => {
+  return axios({
+    url: `/spareParts/audit`,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 删除
+export const sparePartsDelete = (params) => {
+  return axios({
+    url: `/spareParts/delete/${params.sn}`,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 删除明细
+export const sparePartsDeleteDetail = (params) => {
+  return axios({
+    url: `/spareParts/deleteDetail/${params.sn}`,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 分页列表明细
+export const sparePartsDetailList = (params) => {
+  const url = `/spareParts/queryDetailPage/${params.sn}/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 分页列表明细合计
+export const sparePartsPageCount = (params) => {
+  return axios({
+    url: `/spareParts/queryDetailPageCount/${params.sn}`,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 保存
+export const sparePartsSave = (params) => {
+  return axios({
+    url: `/spareParts/save`,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 保存明细
+export const sparePartsSaveDetail = (params) => {
+  return axios({
+    url: `/spareParts/saveDetail`,
+    data: params,
+    method: 'post'
+  })
+}
+// 明细  详情
+export const sparePartsDetailD = (params) => {
+  return axios({
+    url: `/spareParts/queryDetailBySn/${params.sn}`,
+    data: params,
+    method: 'post'
+  })
+}

+ 111 - 0
src/api/stock.js

@@ -0,0 +1,111 @@
+import { axios } from '@/utils/request'
+
+//  库存列表  分页
+export const stockList = (params) => {
+  const url = `/stock/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  库存 列表 合计
+export const stockCount = (params) => {
+  return axios({
+    url: '/stock/queryPageCount',
+    data: params,
+    method: 'post'
+  })
+}
+//  库存 导出
+export const stockExport = (params) => {
+  return axios({
+    url: '/stock/exportExcel',
+    data: params,
+    method: 'post',
+    responseType: 'blob'
+  })
+}
+//  库存 详情列表  分页
+export const stockDetailList = (params) => {
+  const url = `/stock/queryDetailPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  库存 详情列表 合计
+export const stockDetailCount = (params) => {
+  return axios({
+    url: '/stock/queryDetailPageCount',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 分页查询产品库存列表
+export const queryStockProductPage = (params) => {
+  const url = `/stock/queryStockProductPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+//  出入库明细 列表  有分页
+export const stockFlowList = (params) => {
+  const url = `/stock/queryFlowPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  出入库明细  列表  合计
+export const stockFlowCount = (params) => {
+  return axios({
+    url: '/stock/queryFlowPageCount',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  库存预警 列表  分页
+export const stockWarnList = (params) => {
+  const url = `/stock/queryWarnPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  库存预警 保存
+export const stockWarnSaveBatch = (params) => {
+  return axios({
+    url: '/stock/updateStateBatch',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  根据产品sn查询库存
+export const stockByProductSn = (params) => {
+  const url = `/stock/queryStockByProductSn/${params.sn}`
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}

+ 50 - 0
src/api/stockOut.js

@@ -0,0 +1,50 @@
+import { axios } from '@/utils/request'
+
+//  出库 列表  有分页
+export const stockOutList = (params) => {
+  const url = `/stockOut/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  出库 出库
+export const stockOutOut = (params) => {
+  return axios({
+    url: '/stockOut/out',
+    data: params,
+    method: 'post'
+  })
+}
+//  出库 详情
+export const stockOutDetail = (params) => {
+  const url = `/stockOut/queryDetailHeadInfoBySn/${params.sn}`
+  return axios({
+    url: url,
+    data: {},
+    method: 'post'
+  })
+}
+//  出库 详情 列表 有分页
+export const stockOutDetailList = (params) => {
+  const url = `/stockOut/queryDetailPageBySn/${params.sn}/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  出库 详情 合计
+export const stockOutDetailCount = (params) => {
+  const url = `/stockOut/queryDetailPageCountBySn/${params.sn}`
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}

+ 32 - 0
src/api/stockPut.js

@@ -0,0 +1,32 @@
+import { axios } from '@/utils/request'
+
+//  入库确认 列表 有分页
+export const stockPutList = (params) => {
+  const url = `/stockPut/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  入库确认
+export const stockPutConfirm = (params) => {
+  return axios({
+    url: '/stockPut/confirm',
+    data: params,
+    method: 'post'
+  })
+}
+//  入库确认 明细 列表 有分页
+export const stockPutDetailList = (params) => {
+  const url = `/stockPut/queryDetailPage/${params.sn}/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}

+ 42 - 0
src/api/subarea.js

@@ -0,0 +1,42 @@
+import { axios } from '@/utils/request'
+
+//  查询所有分区
+export const subareaQueryAll = (params) => {
+  return axios({
+    url: `/subarea/queryAll`,
+    method: 'get'
+  })
+}
+
+// 查询包含区域的所有分区
+export const subareaQueryIncludeAreaAll = (params) => {
+  return axios({
+    url: `/subarea/queryIncludeAreaAll`,
+    method: 'get'
+  })
+}
+
+// 根据sn删除分区信息
+export const subareaDeleteBySn = (params) => {
+  return axios({
+    url: `/subarea/deleteBySn/${params.sn}`,
+    method: 'get'
+  })
+}
+
+// 根据分区sn查询选中分区
+export const subareaFindBySn = (params) => {
+  return axios({
+    url: `/subarea/findBySn/${params.sn}`,
+    method: 'get'
+  })
+}
+
+// 保存选中省市区
+export const subareaSaveSubareaArea = (params) => {
+  return axios({
+    url: `/subarea/saveSubareaArea`,
+    data: params,
+    method: 'post'
+  })
+}

+ 89 - 0
src/api/supplier.js

@@ -0,0 +1,89 @@
+import { axios } from '@/utils/request'
+
+//  供应商 列表  有分页
+export const supplierList = (params) => {
+  const url = `/supplier/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  供应商 列表  无分页
+export const supplierAllList = (params) => {
+  return axios({
+    url: '/supplier/queryAll',
+    method: 'get'
+  })
+}
+//  供应商 详情
+export const supplierDetail = (params) => {
+  return axios({
+    url: `/supplier/findBySn/${params.sn}`,
+    method: 'get'
+  })
+}
+//  供应商 保存
+export const supplierSave = (params) => {
+  return axios({
+    url: '/supplier/save',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 启用禁用
+export const updateEnableStatus = (params) => {
+  return axios({
+    url: `/supplier/enable/${params.sn}/${params.flag}`,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 分页查询供应商产品列表
+export const supplierProductList = (params) => {
+  const url = `/supplierProduct/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 设置成本价
+export const settingCost = (params) => {
+  return axios({
+    url: `/supplierProduct/settingCost`,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 删除产品信息
+export const deleteProduct = (params) => {
+  return axios({
+    url: `/supplierProduct/deleteProduct/${params.sn}`,
+    method: 'get'
+  })
+}
+
+// 添加产品信息
+export const addProduct = (params) => {
+  return axios({
+    url: `/supplierProduct/addProduct`,
+    data: params,
+    method: 'post'
+  })
+}
+// 查询供应商产品sn集合
+export const supplierProductSnList = (params) => {
+  return axios({
+    url: `/supplierProduct/queryProductSnList/${params.sn}`,
+    method: 'get'
+  })
+}

+ 67 - 0
src/api/waitDispatchDetail.js

@@ -0,0 +1,67 @@
+import { axios } from '@/utils/request'
+
+//  批量删除
+export const deleteBatch = (params) => {
+  return axios({
+    url: '/dispatch/detail/deleteBatch',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 下推
+export const pushDown = (params) => {
+  return axios({
+    url: `/dispatch/pushDown/${params.dispatchBillSn}`,
+    method: 'get'
+  })
+}
+
+// 统计查询
+export const queryCount = (params) => {
+  return axios({
+    url: `/dispatch/queryCount`,
+    data: params,
+    method: 'post'
+  })
+}
+// 销售单  下推  带下推产品列表 合计
+export const dispatchDetail = (params) => {
+  return axios({
+    url: `/dispatch/findBySn/${params.dispatchBillSn}`,
+    method: 'get'
+  })
+}
+
+// 列表  有分页
+export const waitDispatchDetailList = (params) => {
+  const url = `/dispatch/detail/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 列表  不分页
+export const waitDispatchDetailAllList = (params) => {
+  const url = `/dispatch/detail/query`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+//  数量修改
+export const updateQty = (params) => {
+  return axios({
+    url: '/dispatch/detail/updateQty',
+    data: params,
+    method: 'post'
+  })
+}

+ 86 - 0
src/api/warehouse.js

@@ -0,0 +1,86 @@
+import { axios } from '@/utils/request'
+
+//  仓库列表  有分页
+export const warehouseList = (params) => {
+  const url = `/warehouse/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  仓库列表  无分页
+export const warehouseAllList = (params) => {
+  const url = '/warehouse/queryList'
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  仓库仓位  级联数据
+export const warehouseCascadeList = (params) => {
+  const url = '/warehouse/queryListWithExt'
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+// 新增/编辑仓库
+export const warehouseSave = params => {
+  return axios({
+    url: '/warehouse/save',
+    data: params,
+    method: 'post'
+  })
+}
+// 删除仓库
+export const warehouseDel = params => {
+  return axios({
+    url: `/warehouse/delete/${params.sn}`,
+    data: {},
+    method: 'get'
+  })
+}
+
+//  仓位列表  有分页
+export const warehouseLocList = (params) => {
+  const url = `/warehouseLoc/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  仓位列表  无分页
+export const warehouseLocAllList = (params) => {
+  const url = '/warehouseLoc/queryList'
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 新增/编辑仓位
+export const warehouseLocSave = params => {
+  return axios({
+    url: '/warehouseLoc/save',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 删除仓位
+export const warehouseLocDel = params => {
+  return axios({
+    url: `/warehouseLoc/delete/${params.sn}`,
+    data: {},
+    method: 'get'
+  })
+}

二进制
src/assets/explain/def_calculation.png


二进制
src/assets/explain/icon_example.png


二进制
src/assets/explain/icon_inventory.png


二进制
src/assets/explain/icon_mete.png


二进制
src/assets/explain/icon_sales.png


二进制
src/assets/explain/pressed_gray.png


+ 1 - 0
src/components/GlobalHeader/GlobalHeader.vue

@@ -74,6 +74,7 @@ export default {
   },
   mounted () {
     document.addEventListener('scroll', this.handleScroll, { passive: true })
+    console.log(this.multiTab)
   },
   methods: {
     handleScroll () {

+ 27 - 19
src/components/MultiTab/MultiTab.vue

@@ -6,6 +6,7 @@ export default {
   data () {
     return {
       fullPathList: [],
+      tabsList: [],
       pages: [],
       activeKey: '',
       newTabIndex: 0
@@ -35,7 +36,7 @@ export default {
     })
 
     this.pages.push(this.$route)
-    this.fullPathList.push(this.$route.fullPath)
+    this.tabsList.push(this.$route.name)
     this.selectedLastPath()
   },
   methods: {
@@ -43,30 +44,30 @@ export default {
       this[action](targetKey)
     },
     remove (targetKey) {
-      this.pages = this.pages.filter(page => page.fullPath !== targetKey)
-      this.fullPathList = this.fullPathList.filter(path => path !== targetKey)
+      this.pages = this.pages.filter(page => page.name !== targetKey)
+      this.tabsList = this.tabsList.filter(name => name !== targetKey)
       // 判断当前标签是否关闭,若关闭则跳转到最后一个还存在的标签页
-      if (!this.fullPathList.includes(this.activeKey)) {
+      if (!this.tabsList.includes(this.activeKey)) {
         this.selectedLastPath()
       }
     },
     selectedLastPath () {
-      this.activeKey = this.fullPathList[this.fullPathList.length - 1]
+      this.activeKey = this.tabsList[this.tabsList.length - 1]
     },
 
     // content menu
     closeThat (e) {
       // 判断是否为最后一个标签页,如果是最后一个,则无法被关闭
-      if (this.fullPathList.length > 1) {
+      if (this.tabsList.length > 1) {
         this.remove(e)
       } else {
         this.$message.info('这是最后一个标签了, 无法被关闭')
       }
     },
     closeLeft (e) {
-      const currentIndex = this.fullPathList.indexOf(e)
+      const currentIndex = this.tabsList.indexOf(e)
       if (currentIndex > 0) {
-        this.fullPathList.forEach((item, index) => {
+        this.tabsList.forEach((item, index) => {
           if (index < currentIndex) {
             this.remove(item)
           }
@@ -76,9 +77,9 @@ export default {
       }
     },
     closeRight (e) {
-      const currentIndex = this.fullPathList.indexOf(e)
-      if (currentIndex < (this.fullPathList.length - 1)) {
-        this.fullPathList.forEach((item, index) => {
+      const currentIndex = this.tabsList.indexOf(e)
+      if (currentIndex < (this.tabsList.length - 1)) {
+        this.tabsList.forEach((item, index) => {
           if (index > currentIndex) {
             this.remove(item)
           }
@@ -88,8 +89,8 @@ export default {
       }
     },
     closeAll (e) {
-      const currentIndex = this.fullPathList.indexOf(e)
-      this.fullPathList.forEach((item, index) => {
+      const currentIndex = this.tabsList.indexOf(e)
+      this.tabsList.forEach((item, index) => {
         if (index !== currentIndex) {
           this.remove(item)
         }
@@ -121,14 +122,21 @@ export default {
   },
   watch: {
     '$route': function (newVal) {
-      this.activeKey = newVal.fullPath
-      if (this.fullPathList.indexOf(newVal.fullPath) < 0) {
-        this.fullPathList.push(newVal.fullPath)
+      this.activeKey = newVal.name
+      const index = this.tabsList.indexOf(newVal.name)
+      // 不存在
+      if (index < 0) {
+        this.tabsList.push(newVal.name)
         this.pages.push(newVal)
+      } else {
+        // 已存在
+        this.pages.splice(index, 1, newVal)
       }
     },
     activeKey: function (newPathKey) {
-      this.$router.push({ path: newPathKey })
+      const row = this.pages.find(item => item.name == newPathKey)
+      console.log(row.fullPath)
+      this.$router.push({ path: row.fullPath })
     }
   },
   render () {
@@ -137,10 +145,10 @@ export default {
       return (
         <a-tab-pane
           style={{ height: 0 }}
-          key={page.fullPath} closable={pages.length > 1}
+          key={page.name} closable={pages.length > 1}
         >
           <span slot="tab">
-            {this.renderTabPane(page.meta.customTitle || page.meta.title, page.fullPath)}
+            {this.renderTabPane(page.meta.customTitle || page.meta.title, page.name)}
           </span>
         </a-tab-pane>)
     })

+ 53 - 10
src/components/NoticeIcon/NoticeIcon.vue

@@ -1,5 +1,5 @@
 <template>
-  <a-popover
+  <!-- <a-popover
     v-model="visible"
     trigger="click"
     placement="bottomRight"
@@ -45,10 +45,16 @@
         <a-icon style="font-size: 16px; padding: 4px" type="bell" />
       </a-badge>
     </span>
-  </a-popover>
+  </a-popover> -->
+  <span @click="fetchNotice" class="header-notice" ref="noticeRef">
+    <a-badge :count="unreadCount">
+      <a-icon style="font-size: 16px; padding: 0 5px" type="bell" />
+    </a-badge>
+  </span>
 </template>
 
 <script>
+import { mapGetters, mapActions } from 'vuex'
 export default {
   name: 'HeaderNotice',
   data () {
@@ -57,17 +63,54 @@ export default {
       visible: false
     }
   },
+  computed: {
+    ...mapGetters([
+      'unreadCount'
+    ]),
+    unreadCount () {
+      return this.$store.getters.unreadCount
+    },
+    // 接受到ws消息
+    wsMessage () {
+      return this.$store.getters.wsMessageData()
+    }
+  },
+  mounted () {
+    // webSocket 连接
+    this.WEBSOCKET_INIT()
+  },
+  destroyed () {
+    this.WEBSOCKET_CLOSE()
+  },
   methods: {
+    ...mapActions([
+      'WEBSOCKET_INIT',
+      'WEBSOCKET_CLOSE',
+      'updateUnreadcount'
+    ]),
     fetchNotice () {
-      if (!this.visible) {
-        this.loading = true
-        setTimeout(() => {
-          this.loading = false
-        }, 2000)
-      } else {
-        this.loading = false
+      // if (!this.visible) {
+      //   this.loading = true
+      //   setTimeout(() => {
+      //     this.loading = false
+      //   }, 2000)
+      // } else {
+      //   this.loading = false
+      // }
+      // this.visible = !this.visible
+      this.$router.push({ path: '/notice' })
+    }
+  },
+  watch: {
+    // 监听ws消息通知
+    wsMessage (a, b) {
+      if (a !== b && a) {
+        console.log(a)
+        // 新未读消息
+        if (a.type == 'no_read_count') {
+          this.updateUnreadcount(a.data.no_read_count)
+        }
       }
-      this.visible = !this.visible
     }
   }
 }

+ 1 - 1
src/components/PageHeader/PageHeader.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="page-header">
     <div class="page-header-index-wide">
-      <s-breadcrumb />
+      <!-- <s-breadcrumb /> -->
       <div class="detail">
         <div class="main" v-if="!$route.meta.hiddenHeaderContent">
           <!-- <div class="row">

+ 28 - 4
src/components/Table/index.js

@@ -19,6 +19,10 @@ export default {
       type: [String, Function],
       default: 'key'
     },
+    rowClassName: {
+      type: [String, Function],
+      default: ''
+    },
     data: {
       type: Function,
       required: true
@@ -74,6 +78,19 @@ export default {
     pageURI: {
       type: Boolean,
       default: false
+    },
+    /** 是否首次加载数据 */
+    defaultLoadData: {
+      type: Boolean,
+      default: true
+    },
+    tableId: {
+      type: String,
+      default: ''
+    },
+    index: {
+      type: [String,Number],
+      default: ''
     }
   }),
   watch: {
@@ -112,7 +129,9 @@ export default {
     }) || false
     console.log('this.localPagination', this.localPagination)
     this.needTotalList = this.initTotalList(this.columns)
-    this.loadData()
+    if(this.defaultLoadData){
+      this.loadData()
+    }
   },
   methods: {
     /**
@@ -138,7 +157,7 @@ export default {
         pageNo: (pagination && pagination.current) ||
           this.showPagination && this.localPagination.current || this.pageNum,
         pageSize: (pagination && pagination.pageSize) ||
-          this.showPagination && this.localPagination.pageSize || this.pageSize
+          this.showPagination && this.localPagination.pageSize || this.pageSize,
       },
       (sorter && sorter.field && {
         sortField: sorter.field
@@ -149,6 +168,12 @@ export default {
         ...filters
       }
       )
+      if(this.tableId != ''){
+        parameter.tableId = this.tableId
+      }
+      if(this.index != ''){
+        parameter.index = this.index
+      }
       console.log('parameter', parameter)
       const result = this.data(parameter)
       // 对接自己的通用数据接口需要修改下方代码中的 r.pageNo, r.count, r.data
@@ -175,12 +200,11 @@ export default {
           // 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能
           try {
             if ((['auto', true].includes(this.showPagination) && r.count <= (r.pageNo * this.localPagination.pageSize))) {
-              this.localPagination.hideOnSinglePage = true
+              // this.localPagination.hideOnSinglePage = true
             }
           } catch (e) {
             this.localPagination = false
           }
-          console.log('loadData -> this.localPagination', this.localPagination)
           this.localDataSource = list // 返回结果中的数组数据
           this.localLoading = false
         })

+ 72 - 30
src/components/UploadFile/index.vue

@@ -4,10 +4,10 @@
       :action="action"
       :listType="listType"
       :fileList="fileList"
+      :disabled="disabled"
       @preview="handlePreview"
       @change="handleChange"
       :beforeUpload="beforeUpload"
-      :preview-file="previewFile"
       :data="params"
       :value="comVal"
     >
@@ -19,7 +19,7 @@
         <a-button> <a-icon type="upload" /> {{ upText }} </a-button>
       </div>
     </a-upload>
-    <a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
+    <a-modal :visible="previewVisible" :footer="null" centered :maskClosable="false" @cancel="handleCancel">
       <video v-if="fileType=='video/mp4'" controls="controls" style="width: 100%" :src="previewImage" />
       <img v-else alt="example" style="width: 100%" :src="previewImage" />
     </a-modal>
@@ -57,7 +57,7 @@ export default {
     },
     upText: {
       type: String,
-      default: '上传'
+      default: ''
     },
     value: {
       type: String
@@ -66,14 +66,21 @@ export default {
       type: Object,
       default: function () {
         return {
-          savePathType: 'ali' // 存储类型 local 服务器本地,ali 阿里云
+          savePathType: 'ali' // 存储类型 local 服务器本地,ali 阿里云, web
         }
       }
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    uploadType: { //  上传类型  img图片;attach附件;import导入
+      type: String,
+      default: 'img'
     }
   },
   watch: {
     value (a, b) {
-      console.log(a, '=--====')
       this.comVal = a || ''
       if (a == undefined) {
         this.fileList = []
@@ -93,19 +100,37 @@ export default {
     setFileList (a) {
       const temp = []
       if (a && a.length > 0) {
-        a.split(',').map((item, index) => {
-          if (item) {
-            temp.push({
-              uid: index,
-              name: item,
-              status: 'done',
-              url: item,
-              response: {
-                data: item
-              }
-            })
-          }
-        })
+        if (this.uploadType == 'img' || this.uploadType == 'import') { // 图片/导入
+          a.split(',').map((item, index) => {
+            if (item) {
+              temp.push({
+                uid: index,
+                name: item,
+                status: 'done',
+                url: item,
+                response: {
+                  data: item
+                }
+              })
+            }
+          })
+        } else if (this.uploadType == 'attach') { // 附件
+          a.map((item, index) => {
+            if (item) {
+              const arr = []
+              arr.push(item) //  包裹成与新上传文件数据返回结构一致
+              temp.push({
+                uid: index,
+                name: item.fileName,
+                status: 'done',
+                url: item.filePath,
+                response: {
+                  data: arr
+                }
+              })
+            }
+          })
+        }
       }
       this.fileList = temp
     },
@@ -116,39 +141,49 @@ export default {
       if (this.listType == 'text') {
         return
       }
-      console.log(file, '8888888888')
       this.previewImage = file.url || file.thumbUrl
-      // this.previewImage = file.response.data
       this.previewVisible = true
     },
     handleChange ({ file, fileList }) {
-      if (file.status == 'error') {
+      // console.log(file, fileList, '-----change')
+      if (file.status == 'error' || (file.response && (file.response.status == 500))) {
         this.$message.error('上传失败,请重试!')
         return
       }
       this.fileList = this.validaFile(file, fileList)
       this.$emit('change', this.formatFile())
+      this.$emit('input', this.formatFile())
     },
     // 格式化文件列表数据,给表单
     formatFile () {
       const a = this.fileList
-      const temp = []
+      let temp = []
+      let obj = null
       if (a && a.length) {
-        a.map(item => {
-          if (item.response && item.status == 'done') {
-            temp.push(item.response.data)
-          }
-        })
+        if (this.uploadType == 'img' || this.uploadType == 'import') { // 图片/导入    将接口的返回图片地址逗号拼接后返回页面
+          a.map(item => {
+            if (item.response && item.status == 'done') {
+              temp.push(item.response.data)
+            }
+          })
+          obj = temp.join(',')
+        } else if (this.uploadType == 'attach') { // 附件    将接口的返回数据返回页面
+          a.map(item => {
+            if (item.response && item.status == 'done') {
+              temp = [...temp, ...item.response.data]
+            }
+          })
+          obj = JSON.stringify(temp)
+        }
       }
-      return temp.join(',')
+      return obj
     },
     // 文件校验
     validaFile (file, filesList) {
       if (filesList.length == 0) {
         return []
       }
-
-      console.log(file, filesList, this.beforeUpload(file, 0))
+      // console.log(file, filesList, this.beforeUpload(file, 0))
       if (!this.beforeUpload(file, 0) && file.status != 'removed') {
         const index = filesList.findIndex(item => item.uid == file.uid)
         filesList.splice(index, 1)
@@ -192,10 +227,12 @@ export default {
   .upload-file{
     float: left;
     overflow: hidden;
+    height: 80px;
     /* you can make up upload button and sample style by using stylesheets */
     .ant-upload-select-picture-card i {
       font-size: 32px;
       color: #999;
+      margin-top: 9px;
     }
     .ant-upload-select-picture-card .ant-upload-text {
       margin-top: 8px;
@@ -207,11 +244,16 @@ export default {
         padding: 4px 0;
       }
     }
+    .ant-upload-list-picture-card-container{
+      height: 80px;
+      width: 80px;
+    }
     .ant-upload.ant-upload-select-picture-card,
     .ant-upload-list-picture-card .ant-upload-list-item{
       width:80px;
       height:80px;
       padding: 4px;
+      margin: 0;
     }
     .ant-upload-list-item-info{
       padding: 0 22px 0 4px;

+ 224 - 2
src/components/global.less

@@ -527,10 +527,232 @@ body {
 
 .content {
   .table-operator {
-    margin-bottom: 18px;
-
+    padding: 15px 0;
+    border-top: 1px solid #eee;
     button {
       margin-right: 8px;
     }
   }
+  .table-operator-nobor{
+    padding: 0 0 15px 0;
+    button {
+      margin-right: 8px;
+    }
+  }
+}
+
+/* 扩展ant design pro按钮组件颜色 */
+.ant-btn-primary.button-primary {
+  background-color: #39f;
+  border-color: #39f;
+  margin: 0 5px;
+  font-size: 12px;
+  &:hover, &:focus {
+    background-color: #52a6fb;
+    border-color: #52a6fb;
+  }
+ 
+  &:active, &.active {
+    background-color: #3d80bf;
+    border-color: #3d80bf;
+  }
+}
+ 
+.ant-btn-primary.button-info {
+  background-color: #2db7f5;
+  border-color: #2db7f5;
+  margin: 0 5px;
+  font-size: 12px;
+  &:hover, &:focus {
+    background-color: #32c8f5;
+    border-color: #32c8f5;
+  }
+ 
+  &:active, &.active {
+    background-color: #27a3d8;
+    border-color: #27a3d8;
+  }
+}
+ 
+.ant-btn-primary.button-success {
+  background-color: #0c6;
+  border-color: #0c6;
+  margin: 0 5px;
+  font-size: 12px;
+  &:hover, &:focus {
+    background-color: #01dc8c;
+    border-color: #01dc8c;
+  }
+ 
+  &:active, &.active {
+    background-color: #00af57;
+    border-color: #00af57;
+  }
+}
+ 
+.ant-btn-primary.button-warning {
+  background-color: #f90;
+  border-color: #f90;
+  margin: 0 5px;
+  font-size: 12px;
+  &:hover, &:focus {
+    background-color: #ffb60a;
+    border-color: #ffb60a;
+  }
+ 
+  &:active, &.active {
+    background-color: #dd8500;
+    border-color: #dd8500;
+  }
+}
+ 
+.ant-btn-primary.button-error {
+  background-color: #f30;
+  border-color: #f30;
+  margin: 0 5px;
+  font-size: 12px;
+  &:hover, &:focus {
+    background-color: #ff6666;
+    border-color: #ff6666;
+  }
+ 
+  &:active, &.active {
+    background-color: #d62a00;
+    border-color: #d62a00;
+  }
+}
+ 
+.ant-btn-primary.button-geekblue {
+  background-color: #2F54EB;
+  border-color: #2F54EB;
+  margin: 0 5px;
+  font-size: 12px;
+  &:hover, &:focus {
+    background-color: #1d39c4;
+    border-color: #1d39c4;
+  }
+ 
+  &:active, &.active {
+    background-color: #597ef7;
+    border-color: #597ef7;
+  }
+}
+ 
+.ant-btn-primary.button-purple {
+  background-color: #722ED1;
+  border-color: #722ED1;
+  margin: 0 5px;
+  font-size: 12px;
+  &:hover, &:focus {
+    background-color: #9254de;
+    border-color: #9254de;
+  }
+ 
+  &:active, &.active {
+    background-color: #531dab;
+    border-color: #531dab;
+  }
 }
+.ant-btn-primary.button-grey {
+  background-color: #82848a;
+  border-color: #82848a;
+  margin: 0 5px;
+  font-size: 12px;
+  &:hover, &:focus {
+    background-color: #909399;
+    border-color: #909399;
+  }
+ 
+  &:active, &.active {
+    background-color: #c8c9cc;
+    border-color: #c8c9cc;
+  }
+}
+
+// btn-link
+.ant-btn-link.button-primary {
+  color: #39f;
+  &:hover, &:focus {
+    color: #52a6fb;
+  }
+ 
+  &:active, &.active {
+    color: #3d80bf;
+  }
+}
+ 
+.ant-btn-link.button-info {
+  color: #2db7f5;
+  &:hover, &:focus {
+    color: #32c8f5;
+  }
+ 
+  &:active, &.active {
+    color: #27a3d8;
+  }
+}
+ 
+.ant-btn-link.button-success {
+  color: #0c6;
+  &:hover, &:focus {
+    color: #01dc8c;
+  }
+ 
+  &:active, &.active {
+    color: #00af57;
+  }
+}
+ 
+.ant-btn-link.button-warning {
+  color: #e89105;
+  &:hover, &:focus {
+    color: #ffb60a;
+  }
+ 
+  &:active, &.active {
+    color: #dd8500;
+  }
+}
+ 
+.ant-btn-link.button-error {
+  color: #f30;
+  &:hover, &:focus {
+    color: #ff6666;
+  }
+ 
+  &:active, &.active {
+    color: #d62a00;
+  }
+}
+ 
+.ant-btn-link.button-geekblue {
+  color: #2F54EB;
+  &:hover, &:focus {
+    color: #1d39c4;
+  }
+ 
+  &:active, &.active {
+    color: #597ef7;
+  }
+}
+ 
+.ant-btn-link.button-purple {
+  color: #722ED1;
+  &:hover, &:focus {
+    color: #9254de;
+  }
+ 
+  &:active, &.active {
+    color: #531dab;
+  }
+}
+.ant-btn-link.button-grey {
+  color: #82848a;
+  &:hover, &:focus {
+    color: #909399;
+  }
+ 
+  &:active, &.active {
+    color: #c8c9cc;
+  }
+}

+ 4 - 2
src/components/tools/UserMenu.vue

@@ -1,6 +1,7 @@
 <template>
   <div class="user-wrapper">
     <div class="content-box">
+		<notice-icon class="action"/>
       <!-- <a href="https://pro.loacg.com/docs/getting-started" target="_blank">
         <span class="action">
           <a-icon type="question-circle-o"></a-icon>
@@ -32,7 +33,7 @@
             <span>测试</span>
           </a-menu-item> -->
           <a-menu-divider/>
-          <a-menu-item key="3">
+          <a-menu-item key="1">
             <a href="javascript:;" @click="handleLogout">
               <a-icon type="logout"/>
               <span>退出登录</span>
@@ -66,7 +67,8 @@ export default {
     handleLogout () {
       this.$confirm({
         title: '提示',
-        content: '真的要注销登录吗 ?',
+        content: '真的要退出登录吗 ?',
+        centered: true,
         onOk: () => {
           return this.Logout({}).then(() => {
             setTimeout(() => {

文件差异内容过多而无法显示
+ 1510 - 28
src/config/router.config.js


+ 7 - 3
src/layouts/BasicLayout.vue

@@ -39,7 +39,7 @@
         @toggle="toggle"
       />
       <!-- layout content -->
-      <a-layout-content :style="{ height: '100%', margin: '24px 24px 0', paddingTop: fixedHeader ? '105px' : '0' }">
+      <a-layout-content :style="{ height: '100%', margin: '24px 24px 0', paddingTop: multiTab&&fixedHeader ? '105px' : (!multiTab&&fixedHeader?'65px':'0') }">
         <transition name="page-transition">
           <route-view/>
         </transition>
@@ -47,7 +47,7 @@
 
       <!-- layout footer -->
       <a-layout-footer>
-        <global-footer />
+        <!-- <global-footer /> -->
       </a-layout-footer>
 
       <!-- Setting Drawer (show in development mode) -->
@@ -90,7 +90,9 @@ export default {
   computed: {
     ...mapState({
       // 动态主路由
-      mainMenu: state => state.permission.routers
+      mainMenu: state => state.permission.routers,
+      multiTab: state => state.app.multiTab,
+      fixedHeader: state => state.app.fixedHeader
     }),
     contentPaddingLeft () {
       if (!this.fixSidebar || this.isMobile()) {
@@ -116,6 +118,8 @@ export default {
       this.menus = [noqx.find(item => item.path === '/home')]
     }
     this.collapsed = !this.sidebarOpened
+    this.$store.dispatch('ToggleMultiTab', true)
+	  this.$store.dispatch('ToggleColor', '#1890FF')
   },
   mounted () {
     const userAgent = navigator.userAgent

+ 3 - 2
src/layouts/PageView.vue

@@ -1,7 +1,8 @@
 <template>
   <div :style="!$route.meta.hiddenHeaderContent ? 'margin: -24px -24px 0px;' : null">
     <!-- pageHeader , route meta :true on hide -->
-    <page-header v-if="!$route.meta.hiddenHeaderContent" :title="pageTitle" :logo="logo" :avatar="avatar">
+    <!-- <page-header v-if="!$route.meta.hiddenHeaderContent" :title="pageTitle" :logo="logo" :avatar="avatar"> -->
+    <page-header v-if="false" :title="pageTitle" :logo="logo" :avatar="avatar">
       <slot slot="action" name="action"></slot>
       <slot slot="content" name="headerContent"></slot>
       <div slot="content" v-if="!this.$slots.headerContent && description">
@@ -124,7 +125,7 @@ export default {
 
 <style lang="less" scoped>
   .content {
-    margin: 24px 24px 0;
+    margin: 12px 12px 0;
     .link {
       margin-top: 16px;
       &:not(:empty) {

+ 31 - 0
src/libs/commonData.js

@@ -0,0 +1,31 @@
+// 品牌  排序字母  下拉数据
+export default {
+  sortCharList: [
+    { id: 'A', name: 'A' },
+    { id: 'B', name: 'B' },
+    { id: 'C', name: 'C' },
+    { id: 'D', name: 'D' },
+    { id: 'E', name: 'E' },
+    { id: 'F', name: 'F' },
+    { id: 'G', name: 'G' },
+    { id: 'H', name: 'H' },
+    { id: 'I', name: 'I' },
+    { id: 'J', name: 'J' },
+    { id: 'K', name: 'K' },
+    { id: 'L', name: 'L' },
+    { id: 'M', name: 'M' },
+    { id: 'N', name: 'N' },
+    { id: 'O', name: 'O' },
+    { id: 'P', name: 'P' },
+    { id: 'Q', name: 'Q' },
+    { id: 'R', name: 'R' },
+    { id: 'S', name: 'S' },
+    { id: 'T', name: 'T' },
+    { id: 'U', name: 'U' },
+    { id: 'V', name: 'V' },
+    { id: 'W', name: 'W' },
+    { id: 'X', name: 'X' },
+    { id: 'Y', name: 'Y' },
+    { id: 'Z', name: 'Z' }
+  ]
+}

+ 85 - 61
src/libs/getDate.js

@@ -1,65 +1,89 @@
 // 引入 moment 时间插件
-import moment from "moment";
-//获取今日/昨日/本周/上周/本月/上月 时间
+import moment from 'moment'
+moment.updateLocale('en', { week: {
+  dow: 1, // 星期的第一天是星期一
+  doy: 7 // 年份的第一周必须包含1月1日 (7 + 1 - 1)
+} })
+// 获取今日/昨日/本周/上周/本月/上月 时间
 export default {
-    // 获取今日的开始结束时间
-    getToday() {
-        let obj = {
-            starttime: '',
-            endtime: ''
-        }
-        obj.starttime = moment(moment().startOf("day").valueOf()).format("YYYY-MM-DD HH:mm:ss");
-        obj.endtime = moment(moment().valueOf()).format("YYYY-MM-DD HH:mm:ss");
-        return obj
-    },
-    // 获取昨日的开始结束时间
-    getYesterday() {
-        let obj = {
-            starttime: '',
-            endtime: ''
-        }
-        obj.starttime = moment(moment().add(-1, 'days').startOf("day").valueOf()).format("YYYY-MM-DD");
-        obj.endtime = moment(moment().add(-1, 'days').endOf('day').valueOf()).format('YYYY-MM-DD');
-        return obj
-    },
-    // 获取当前周的开始结束时间
-    getCurrWeekDays() {
-        let obj = {
-            starttime: '',
-            endtime: ''
-        }
-        obj.starttime = moment(moment().week(moment().week()).startOf('week').add(1, 'days').valueOf()).format('YYYY-MM-DD')
-        obj.endtime = moment(moment().week(moment().week()).endOf('week').add(1, 'days').valueOf()).format('YYYY-MM-DD');
-        return obj
-    },
-    // 获取上一周的开始结束时间
-    getLastWeekDays() {
-        let obj = {
-            starttime: '',
-            endtime: ''
-        }
-        obj.starttime = moment(moment().week(moment().week() - 1).startOf('week').add(1, 'days').valueOf()).format('YYYY-MM-DD')
-        obj.endtime = moment(moment().week(moment().week() - 1).endOf('week').add(1, 'days').valueOf()).format('YYYY-MM-DD');
-        return obj
-    },
-    // 获取当前月的开始结束时间
-    getCurrMonthDays() {
-        let obj = {
-            starttime: '',
-            endtime: ''
-        }
-        obj.starttime = moment(moment().month(moment().month()).startOf('month').valueOf()).format('YYYY-MM-DD');
-        obj.endtime = moment(moment().month(moment().month()).endOf('month').valueOf()).format('YYYY-MM-DD');
-        return obj
-    },
-    // 获取上一个月的开始结束时间
-    getLastMonthDays() {
-        let obj = {
-            starttime: '',
-            endtime: ''
-        }
-        obj.starttime = moment(moment().month(moment().month() - 1).startOf('month').valueOf()).format('YYYY-MM-DD');
-        obj.endtime = moment(moment().month(moment().month() - 1).endOf('month').valueOf()).format('YYYY-MM-DD');
-        return obj
+  // 获取今日的开始结束时间
+  getToday () {
+    const obj = {
+      starttime: '',
+      endtime: ''
     }
+    obj.starttime = moment(moment().startOf('day').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  //  近7天
+  getRecentday () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment().subtract('days', 6).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取昨日的开始结束时间
+  getYesterday () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().add(-1, 'days').startOf('day').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().add(-1, 'days').endOf('day').valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取当前周的开始到当天结束时间
+  getCurrWeekDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().week(moment().week()).startOf('week').add('days').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取上一周的开始结束时间
+  getLastWeekDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().week(moment().week() - 1).startOf('week').add('days').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().week(moment().week() - 1).endOf('week').add('days').valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取当前月的开始到当天结束时间
+  getCurrMonthDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().month(moment().month()).startOf('month').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取上一个月的开始结束时间
+  getLastMonthDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().month(moment().month() - 1).startOf('month').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().month(moment().month() - 1).endOf('month').valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取近三个月的开始结束时间
+  getThreeMonthDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().month(moment().month() - 2).startOf('month').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().month(moment().month() - 2).endOf('month').valueOf()).format('YYYY-MM-DD')
+    return obj
+  }
 }

+ 5 - 0
src/libs/tools.js

@@ -0,0 +1,5 @@
+// 小数运算精度处理  4位小数运算后结果保留2位小数
+export const getOperationalPrecision = (num1, num2) => {
+  const val = ((num1 * 10000) * (num2 * 10000) / 100000000).toFixed(2) || 0
+  return val != 0 ? val : 0
+}

+ 1 - 0
src/store/getters.js

@@ -5,6 +5,7 @@ const getters = {
   token: state => state.user.token,
   avatar: state => state.user.avatar,
   nickname: state => state.user.name,
+  mustChangePwd: state => state.user.mustChangePwd,
   welcome: state => state.user.welcome,
   roles: state => state.user.roles,
   userInfo: state => state.user.info,

+ 3 - 1
src/store/index.js

@@ -3,6 +3,7 @@ import Vuex from 'vuex'
 
 import app from './modules/app'
 import user from './modules/user'
+import socket from './modules/websocketStore'
 
 // default router permission control
 import permission from './modules/permission'
@@ -17,7 +18,8 @@ export default new Vuex.Store({
   modules: {
     app,
     user,
-    permission
+    permission,
+    socket
   },
   state: {
 

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

@@ -7,6 +7,7 @@ const user = {
   state: {
     token: '',
     name: '',
+    mustChangePwd: null,
     welcome: '',
     avatar: '',
     roles: { permissionList: [] },
@@ -31,6 +32,9 @@ const user = {
     },
     SET_INFO: (state, info) => {
       state.info = info
+    },
+    SET_MUSTCHANGEPWD: (state, status) => {
+      state.mustChangePwd = status
     }
   },
 
@@ -47,7 +51,9 @@ const user = {
               const users = res.auth_user
               Vue.ls.set('hasError', 0)
               commit('SET_TOKEN', res.access_token)
+              commit('SET_INFO', users)
               commit('SET_NAME', { name: users.userNameCN, welcome: welcome() })
+              commit('SET_MUSTCHANGEPWD', users.mustChangePwd)
               Vue.ls.set('rolesAccess', { permissionList: users.permCodes }, 7 * 24 * 60 * 60 * 1000)
               commit('SET_AVATAR', res.avatar ? res.avatar : '')
               // 记住密码
@@ -87,7 +93,9 @@ const user = {
         }).catch((error) => {
           resolve(error)
         }).finally(() => {
+          commit('SET_INFO', {})
           commit('SET_NAME', { name: '', welcome: '' })
+          commit('SET_MUSTCHANGEPWD', '')
           commit('SET_AVATAR', '')
           commit('SET_TOKEN', '')
           commit('SET_ROLES', { permissionList: [] })

+ 121 - 0
src/store/modules/websocketStore.js

@@ -0,0 +1,121 @@
+// import Vue from 'vue'
+import { noticeUserList, hasRead, getUnreadCount } from '@/api/noticeUser'
+export default {
+  state: {
+    websock: null,
+    wsMessageData: null,
+    wsMessageHomeData: null,
+    unreadCount: 0,
+    updateMessage: null, // 判断是否刷新未读消息数据
+    heartInterId: null
+  },
+  getters: {
+    wsMessageData: state => {
+      return () => state.wsMessageData
+    },
+    wsMessageHomeData: state => {
+      return () => state.wsMessageHomeData
+    },
+    unreadCount: state => state.unreadCount,
+    updateMessage: state => {
+      return () => state.updateMessage
+    }
+  },
+  mutations: {
+    WEBSOCKET_INIT (state, url) {
+      const _this = this
+      const baseUrl = process.env.VUE_APP_WX_BASE_URL
+      const sid = 'pc/u' + this.getters.userInfo.userid + 'epc'
+      const protocol = process.env.NODE_ENV == 'production' ? (window.location.protocol == 'http:' ? 'ws:' : 'wss:') : 'ws:'
+      const wsUrl = protocol + baseUrl + sid
+      console.log(process.env.NODE_ENV, wsUrl)
+      state.websock = new WebSocket(wsUrl)
+      state.websock.onopen = function () {
+        console.log('连接成功!')
+        _this.dispatch('getUnreadMessageCount')
+      }
+      state.websock.onmessage = function (e) {
+        console.log('ws接收!', e.data)
+        if (e.data != 'pong') {
+          console.log('进来----------')
+          state.wsMessageData = JSON.parse(e.data)
+        }
+      }
+      state.websock.οnerrοr = function (e) { // 错误
+        console.log('ws错误!', e)
+      }
+      state.websock.onclose = function (e) { // 关闭
+        console.log('ws关闭!', e)
+      }
+
+      // 发送心跳包
+      state.heartInterId = setInterval(function () {
+        console.log('ws发送心跳!')
+        if (state.websock.readyState == 3) {
+          clearInterval(state.heartInterId)
+          _this.commit('WEBSOCKET_INIT', url)
+        }
+        state.websock.send('ping')
+      }, 10000)
+    },
+    WEBSOCKET_CLOSE (state) {
+      state.websock.close()
+      clearInterval(state.heartInterId)
+    },
+    WEBSOCKET_SEND (state, p) {
+      console.log('ws发送!', p)
+      state.websock.send(p)
+    },
+    UPDATE_HOME (state, p) {
+      state.wsMessageHomeData = p
+    },
+    setMessageCount (state, count) {
+      state.unreadCount = count
+    }
+  },
+  actions: {
+    WEBSOCKET_INIT ({ commit }, url) {
+      commit('WEBSOCKET_INIT', url)
+    },
+    WEBSOCKET_SEND ({ commit }, p) {
+      commit('WEBSOCKET_SEND', p)
+    },
+    UPDATE_HOME ({ commit }, p) {
+      commit('UPDATE_HOME', p)
+    },
+    WEBSOCKET_CLOSE ({ commit }) {
+      commit('WEBSOCKET_CLOSE')
+    },
+    // 此方法用来获取未读消息条数,接口只返回数值,不返回消息列表
+    getUnreadMessageCount ({ state, commit }) {
+      getUnreadCount().then(res => {
+        console.log(res, '---------------请求未读消息', res.data ? res.data.no_read_count : 0)
+        commit('setMessageCount', res.data ? res.data.no_read_count : 0)
+      })
+    },
+    // 获取消息列表,其中包含未读、已读、回收站三个列表
+    getMessageList ({ state, commit }, params) {
+      return new Promise((resolve, reject) => {
+        noticeUserList(params).then(res => {
+          resolve(res)
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+    // 把一个未读消息标记为已读
+    hasRead ({ state, commit }, { msg_id }) {
+      return new Promise((resolve, reject) => {
+        hasRead(msg_id).then((res) => {
+          resolve(res)
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+    // 更新未读数
+    updateUnreadcount ({ state, commit }, count) {
+      commit('setMessageCount', count)
+    }
+  }
+}

+ 3 - 1
src/utils/mixin.js

@@ -57,7 +57,9 @@ const AppDeviceEnquire = {
       switch (deviceType) {
         case DEVICE_TYPE.DESKTOP:
           $store.commit('TOGGLE_DEVICE', 'desktop')
-          $store.dispatch('setSidebar', true)
+          // $store.dispatch('setSidebar', true)
+          // 默认收起侧边栏
+          $store.dispatch('setSidebar', false)
           break
         case DEVICE_TYPE.TABLET:
           $store.commit('TOGGLE_DEVICE', 'tablet')

+ 1 - 1
src/utils/request.js

@@ -48,7 +48,7 @@ service.interceptors.request.use(config => {
 service.interceptors.response.use((response) => {
   // console.log(response, 'response.data.status')
   const et = sessionStorage.getItem('errorTips')
-  if (response.data.status == '1001' && !et) {
+  if ((response.data.status == '1001' || response.data.status == '1099') && !et) {
     sessionStorage.setItem('errorTips', 1)
     modal.destroyAll()
     modal.error({

+ 32 - 3
src/views/Home.vue

@@ -1,22 +1,51 @@
 <template>
   <div class="home">
     <a-alert :message="message" type="info" showIcon />
+    <!-- 重置密码 -->
+    <a-modal
+      class="resetPwdModal"
+      title="重置密码"
+      width="60%"
+      centered
+      :footer="null"
+      :closable="false"
+      :maskClosable="false"
+      :destroyOnClose="true"
+      @cancel="openResetPwd=false"
+      v-model="openResetPwd">
+      <ResetPwd />
+    </a-modal>
   </div>
 </template>
 
 <script>
+import { mapGetters } from 'vuex'
+import ResetPwd from '@/views/user/ResetPwd.vue'
 export default {
   name: 'Home',
-  components: {
-  },
+  components: { ResetPwd },
   data () {
     return {
-      message: '欢迎登录' + process.env.VUE_APP_PRO_NAME
+      message: '欢迎登录' + process.env.VUE_APP_PRO_NAME,
+      openResetPwd: false //  重置密码是否显示
     }
   },
+  computed: {
+    ...mapGetters(['mustChangePwd'])
+  },
   created () {
   },
   methods: {
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      //  判断登录用户是否重置过密码(首次登陆需强制重置密码)
+      if (vm.mustChangePwd == 0) {
+        vm.openResetPwd = false
+      } else {
+        vm.openResetPwd = true
+      }
+    })
   }
 }
 </script>

+ 217 - 0
src/views/allocationManagement/transferOut/basicInfoModal.vue

@@ -0,0 +1,217 @@
+<template>
+  <a-modal
+    centered
+    class="allocateBill-basicInfo-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="新增"
+    v-model="isShow"
+    @cancle="isShow = false"
+    :width="800">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        id="allocateBill-basicInfo-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol"
+      >
+        <a-form-model-item label="调往对象" prop="targetType">
+          <a-radio-group v-model="form.targetType" @change="targetTypeChange">
+            <a-radio v-for="(item,index) in targetTypeList" :key="index" :value="item.code">{{ item.dispName }}</a-radio>
+          </a-radio-group>
+        </a-form-model-item>
+        <a-form-model-item label="调往对象名称" :prop="isDealer ? 'targetSn' : 'targetName'">
+          <a-select
+            v-if="isDealer"
+            show-search
+            id="allocateBill-basicInfo-dealerName"
+            v-model="form.targetSn"
+            placeholder="请选择"
+            :filter-option="false"
+            :not-found-content="fetching ? undefined : null"
+            @search="fetchUser"
+            @change="handleChange"
+          >
+            <a-spin v-if="fetching" slot="notFoundContent" size="small" />
+            <a-select-option v-for="item in dealerData" :key="item.dealerSn" :value="item.dealerSn">{{ item.dealerName }}</a-select-option>
+          </a-select>
+          <a-input v-if="!isDealer" v-model="form.targetName" placeholder="请输入调往对象名称(最多30个字符)" allowClear :maxLength="30" />
+        </a-form-model-item>
+        <a-form-model-item label="调拨类型" prop="allocateTypeSn">
+          <a-select id="allocateBill-basicInfo-allocateTypeSn" v-model="form.allocateTypeSn" placeholder="请选择调拨类型" allowClear >
+            <a-select-option v-for="item in allocateTypeList" :key="item.allocateTypeSn" :value="item.allocateTypeSn">{{ item.name }}</a-select-option>
+          </a-select>
+        </a-form-model-item>
+        <a-form-model-item label="备注" prop="remark">
+          <a-textarea id="allocateBill-basicInfo-remark" :maxLength="120" v-model="form.remark" placeholder="请输入备注(最多120个字符)" allowClear />
+        </a-form-model-item>
+      </a-form-model>
+      <div class="btn-cont">
+        <a-button type="primary" id="allocateBill-basicInfo-modal-save" @click="handleSave">保存</a-button>
+        <a-button id="allocateBill-basicInfo-modal-back" @click="isShow = false" style="margin-left: 15px;">取消</a-button>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import debounce from 'lodash/debounce'
+import { VSelect } from '@/components'
+import { allocateBillSave } from '@/api/allocateBill'
+import { dealerSubareaScopeList } from '@/api/dealer'
+import { getLookUpData } from '@/api/data'
+import { allocateTypeAllList } from '@/api/allocateType'
+export default {
+  name: 'StoreTransferOutBasicInfoModal',
+  components: { VSelect },
+  props: {
+    openModal: {
+      //  弹框显示状态
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    this.fetchUser = debounce(this.fetchUser, 800)
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      spinning: false,
+      formItemLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 20 }
+      },
+      form: {
+        targetType: 'DEALER',
+        targetSn: undefined,
+        targetName: '',
+        allocateTypeSn: undefined,
+        remark: ''
+      },
+      rules: {
+        targetType: [{ required: true, message: '请选择调往对象', trigger: 'change' }],
+        targetSn: [{ required: true, message: '请选择调往对象名称', trigger: 'change' }],
+        targetName: [{ required: true, message: '请输入调往对象名称', trigger: 'blur' }],
+        allocateTypeSn: [{ required: true, message: '请选择调拨类型', trigger: 'change' }]
+      },
+      fetching: false,
+      dealerData: [], //  经销商  下拉数据
+      targetTypeList: [], //  调往对象类型
+      allocateTypeList: [] //  调拨类型
+    }
+  },
+  computed: {
+    // 当前所选调往对象是否为经销商
+    isDealer () {
+      return this.form.targetType == 'DEALER'
+    }
+  },
+  methods: {
+    // 搜索经销商
+    fetchUser (value) {
+      console.log('fetching user', value)
+      this.fetching = true
+      dealerSubareaScopeList({ nameLike: value, pageNo: 1, pageSize: 20 }).then(res => {
+        if (res.status == 200) {
+          this.dealerData = res.data.list
+          this.fetching = false
+        } else {
+          this.dealerData = []
+          this.fetching = false
+        }
+      })
+    },
+    // 调往对象名称  change
+    handleChange (value) {
+      const ind = this.dealerData.findIndex(item => item.dealerSn == value)
+      this.form.targetName = this.dealerData[ind].dealerName
+    },
+    //  保存
+    handleSave () {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const form = JSON.parse(JSON.stringify(_this.form))
+          _this.spinning = true
+          allocateBillSave(form).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              setTimeout(() => {
+                _this.isShow = false
+                _this.$emit('ok', res.data)
+                _this.spinning = false
+              }, 1000)
+            } else {
+              _this.spinning = false
+            }
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    // 调往对象  change
+    targetTypeChange (e) {
+      this.$refs.ruleForm.resetFields()
+      this.form.targetSn = undefined
+      this.form.targetName = ''
+      this.form.targetType = e.target.value
+    },
+    // 调往对象类型
+    getTargetTypeList () {
+      const _this = this
+      getLookUpData({
+        pageNo: 1,
+        pageSize: 1000,
+        lookupCode: 'TARGET_TYPE'
+      }).then(res => {
+        if (res.status == 200) {
+          _this.targetTypeList = res.data.list
+        } else {
+          _this.targetTypeList = []
+        }
+      })
+    },
+    //  调拨类型
+    getAllocateTypeAllList () {
+      allocateTypeAllList().then(res => {
+        if (res.status == 200) {
+          this.allocateTypeList = res.data
+        } else {
+          this.allocateTypeList = []
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.$refs.ruleForm.resetFields()
+      } else {
+        this.getTargetTypeList()
+        this.getAllocateTypeAllList()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+.allocateBill-basicInfo-modal {
+	.ant-modal-body {
+		padding: 40px 40px 24px;
+	}
+	.btn-cont {
+		text-align: center;
+		margin: 35px 0 10px;
+	}
+}
+</style>

+ 187 - 0
src/views/allocationManagement/transferOut/detail.vue

@@ -0,0 +1,187 @@
+<template>
+  <div class="allocateBillDetail-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" class="allocateBillDetail-back" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a id="allocateBillDetail-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+          <a-button
+            v-if="isEdit"
+            type="primary"
+            size="small"
+            style="background-color: #1890ff;margin-left: 20px;border: #1890ff;"
+            id="allocateBillDetail-edit-btn"
+            @click.stop="handleEdit">编辑</a-button>
+        </template>
+        <!-- 操作区,位于 title 行的行尾 -->
+        <template slot="extra">
+          <a-button key="2" id="allocateBillDetail-preview-btn" :disabled="localDataSource.length==0" @click="handlePrint('preview')">打印预览</a-button>
+          <a-button key="1" type="primary" id="allocateBillDetail-print-btn" :disabled="localDataSource.length==0" @click="handlePrint('print')">快捷打印</a-button>
+        </template>
+      </a-page-header>
+      <a-card size="small" :bordered="false" class="allocateBillDetail-cont">
+        <a-collapse :activeKey="['1']">
+          <a-collapse-panel key="1" header="基础信息">
+            <a-descriptions :column="3">
+              <a-descriptions-item label="调往对象">{{ (basicInfoData&&basicInfoData.targetName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="调拨单号">{{ (basicInfoData&&basicInfoData.allocateNo) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="调拨类型">{{ (basicInfoData&&basicInfoData.allocateTypeName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="业务状态">{{ (basicInfoData&&basicInfoData.stateDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="备注">{{ (basicInfoData&&basicInfoData.remark) || '--' }}</a-descriptions-item>
+            </a-descriptions>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+      <a-card size="small" :bordered="false" class="allocateBillDetail-cont">
+        <!-- 总计 -->
+        <a-alert type="info" showIcon style="margin-bottom:15px">
+          <div slot="message">总数量:<strong>{{ (productTotal&&productTotal.totalQty) || 0 }}</strong> ,总成本(¥):<strong>{{ (productTotal&&productTotal.totalCost) || 0 }}</strong> ,总售价(¥):<strong>{{ (productTotal&&productTotal.totalPrice) || 0 }}</strong></div>
+        </a-alert>
+        <!-- 列表 -->
+        <s-table
+          class="sTable"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.id"
+          :columns="columns"
+          :data="loadData"
+          :scroll="{ x: 1335 }"
+          bordered>
+        </s-table>
+      </a-card>
+    </a-spin>
+    <!-- 打印 -->
+    <div id="print"></div>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import { getOperationalPrecision } from '@/libs/tools.js'
+import { allocateBillDetailList, allocateBillDetail, allocateBillDetailCount, allocateBillDetailPrint } from '@/api/allocateBill'
+export default {
+  components: { STable, VSelect },
+  data () {
+    return {
+      spinning: false,
+      // 表头
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center', fixed: 'left' },
+        { title: '产品编码', dataIndex: 'productEntity.code', width: 220, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productEntity.name', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '原厂编码', dataIndex: 'productEntity.origCode', width: 220, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '单位', dataIndex: 'productEntity.unit', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '成本价', dataIndex: 'cost', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '售价', dataIndex: 'price', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '调出数量', dataIndex: 'qty', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '成本小计(¥)', dataIndex: 'costSubtotal', width: 115, align: 'center' },
+        { title: '售价小计(¥)', dataIndex: 'priceSubtotal', width: 100, align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        return allocateBillDetailList(Object.assign(parameter, { allocateSn: this.$route.params.sn })).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+            // 成本小计  由于数据库内小数位数为4位,页面则需显示2位。因此会做小数运算精度处理
+            data.list[i].costSubtotal = getOperationalPrecision(data.list[i].cost, data.list[i].qty)
+            data.list[i].priceSubtotal = getOperationalPrecision(data.list[i].price, data.list[i].qty)
+          }
+          this.localDataSource = data.list
+          return data
+        })
+      },
+      basicInfoData: null, //  基本信息
+      productTotal: null, //  合计
+      localDataSource: []
+    }
+  },
+  computed: {
+    isEdit () {
+      return (this.basicInfoData && this.basicInfoData.state == 'WAIT_SUBMIT') || (this.basicInfoData && this.basicInfoData.state == 'WAIT_AUDIT')
+    }
+  },
+  methods: {
+    //  返回列表
+    handleBack () {
+      this.$router.push({ path: '/allocationManagement/transferOut/list' })
+    },
+    // 基本信息
+    getDetail () {
+      allocateBillDetail({ sn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.basicInfoData = res.data
+        } else {
+          this.basicInfoData = null
+        }
+      })
+    },
+    // 合计
+    getDetailCount () {
+      allocateBillDetailCount({ allocateSn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.productTotal = res.data
+        } else {
+          this.productTotal = null
+        }
+      })
+    },
+    //  编辑
+    handleEdit () {
+      this.$router.push({ path: `/allocationManagement/transferOut/edit/${this.basicInfoData.allocateSn}/${this.basicInfoData.targetName}/${this.basicInfoData.dealerLevel}` })
+    },
+    // 打印预览/快捷打印
+    handlePrint (type) {
+      const _this = this
+      _this.spinning = true
+      allocateBillDetailPrint({ sn: this.$route.params.sn, isPreview: type == 'preview' ? 1 : 0 }).then(res => {
+        _this.spinning = false
+        if (res.type == 'application/json') {
+          var reader = new FileReader()
+          reader.addEventListener('loadend', function () {
+            const obj = JSON.parse(reader.result)
+            _this.$notification.error({
+              message: '提示',
+              description: obj.message
+            })
+          })
+          reader.readAsText(res)
+        } else {
+          this.print(res, type)
+        }
+      })
+    },
+    print (data, type) {
+      if (!data) {
+        return
+      }
+      const url = window.URL.createObjectURL(new Blob([data], { type: 'application/pdf' }))
+      document.getElementById('print').innerHTML = '<iframe id="printf" name="printf" src="' + url + '" hidden></iframe>'
+      if (type == 'preview') { //  预览
+        window.open(url)
+      } else if (type == 'print') { //  打印
+        window.frames['printf'].focus()
+        window.frames['printf'].print()
+      }
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.getDetail()
+      vm.getDetailCount()
+    })
+  }
+}
+</script>
+
+<style lang="less">
+  .allocateBillDetail-wrap{
+    .allocateBillDetail-back{
+      margin-bottom: 10px;
+    }
+    .allocateBillDetail-cont{
+      margin-bottom: 10px;
+    }
+  }
+</style>

+ 469 - 0
src/views/allocationManagement/transferOut/edit.vue

@@ -0,0 +1,469 @@
+<template>
+  <div class="allocateBillEdit-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" class="allocateBillEdit-back" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a id="allocateBillEdit-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+          <span style="margin: 0 15px;color: #666;">调往对象:{{ $route.params.name || '--' }}</span>
+        </template>
+        <!-- 操作区,位于 title 行的行尾 -->
+        <template slot="extra">
+          <a-button key="2" id="allocateBillEdit-preview-btn" :disabled="chooseLoadData.length==0" @click="handlePrint('preview')">打印预览</a-button>
+          <a-button key="1" type="primary" id="allocateBillEdit-print-btn" :disabled="chooseLoadData.length==0" @click="handlePrint('print')">快捷打印</a-button>
+        </template>
+      </a-page-header>
+      <!-- 选择产品 -->
+      <a-card size="small" :bordered="false" class="allocateBillEdit-cont">
+        <a-collapse :activeKey="['1']">
+          <a-collapse-panel key="1" header="选择产品">
+            <!-- 筛选条件 -->
+            <div class="table-page-search-wrapper">
+              <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
+                <a-row :gutter="15">
+                  <a-col :md="6" :sm="24">
+                    <a-form-item label="产品编码" prop="productCode">
+                      <a-input id="allocateBillEdit-productCode" v-model="queryParam.productCode" placeholder="请输入产品编码" allowClear />
+                    </a-form-item>
+                  </a-col>
+                  <a-col :md="6" :sm="24">
+                    <a-form-item label="产品名称" prop="productName">
+                      <a-input id="allocateBillEdit-productName" v-model="queryParam.productName" placeholder="请输入产品名称" allowClear />
+                    </a-form-item>
+                  </a-col>
+                  <a-col :md="6" :sm="24">
+                    <a-form-item label="原厂编码" prop="productOrigCode">
+                      <a-input id="allocateBillEdit-productOrigCode" v-model="queryParam.productOrigCode" placeholder="请输入原厂编码" allowClear />
+                    </a-form-item>
+                  </a-col>
+                  <a-col :md="6" :sm="24" style="margin-bottom: 24px;">
+                    <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="storeTransferOutList-refresh">查询</a-button>
+                    <a-button style="margin-left: 8px" @click="resetSearchForm" :disabled="disabled" id="storeTransferOutList-reset">重置</a-button>
+                  </a-col>
+                </a-row>
+              </a-form>
+            </div>
+            <!-- 列表 -->
+            <s-table
+              class="sTable"
+              ref="table"
+              size="small"
+              :rowKey="(record) => record.stockSn"
+              :columns="columns"
+              :customRow="handleClickRow"
+              :data="loadData"
+              :scroll="{ x: 1240, y: 300 }"
+              bordered>
+              <!-- 操作 -->
+              <template slot="action" slot-scope="text, record">
+                <a-button size="small" type="primary" class="button-primary" @click="handleAdd(record)" id="allocateBillEdit-add-btn">添加</a-button>
+              </template>
+            </s-table>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+      <!-- 已选产品 -->
+      <a-card size="small" :bordered="false" class="allocateBillEdit-cont">
+        <a-collapse :activeKey="['1']">
+          <a-collapse-panel key="1" header="已选产品">
+            <!-- 总计 -->
+            <a-alert type="info" showIcon style="margin-bottom:15px">
+              <div slot="message">总数量:<strong>{{ (productTotal&&productTotal.totalQty) || 0 }}</strong> ,总成本(¥):<strong>{{ (productTotal&&productTotal.totalCost) || 0 }}</strong> ,总售价(¥):<strong>{{ (productTotal&&productTotal.totalPrice) || 0 }}</strong></div>
+            </a-alert>
+            <!-- 筛选条件 -->
+            <a-row :gutter="15">
+              <a-col :span="17">
+                <div class="table-page-search-wrapper">
+                  <a-form layout="inline" @keyup.enter.native="getChooseProductList(1)">
+                    <a-row :gutter="15">
+                      <a-col :md="9" :sm="24">
+                        <a-form-item label="产品编码" prop="productCode">
+                          <a-input id="allocateBillEdit-productCode" v-model="chooseQueryParam.productCode" placeholder="请输入产品编码" allowClear />
+                        </a-form-item>
+                      </a-col>
+                      <a-col :md="9" :sm="24">
+                        <a-form-item label="产品名称" prop="productName">
+                          <a-input id="allocateBillEdit-productName" v-model="chooseQueryParam.productName" placeholder="请输入产品名称" allowClear />
+                        </a-form-item>
+                      </a-col>
+                      <a-col :md="6" :sm="24" style="margin-bottom: 24px;">
+                        <a-button type="primary" @click="getChooseProductList(1)" :disabled="chooseDisabled" id="storeTransferOutList-refresh">查询</a-button>
+                        <a-button style="margin-left: 8px" @click="chooseResetSearchForm" :disabled="chooseDisabled" id="storeTransferOutList-reset">重置</a-button>
+                      </a-col>
+                    </a-row>
+                  </a-form>
+                </div>
+              </a-col>
+              <a-col :span="7" style="text-align: right;">
+                <!-- <a-button size="small" id="allocateBillEdit-import-btn">导入明细</a-button> -->
+                <a-button size="small" type="danger" style="margin-left: 8px" @click.stop="handleDel('', 'all')" id="chainTransferOutEdit-del-all-btn">整单删除</a-button>
+              </a-col>
+            </a-row>
+            <!-- 列表 -->
+            <a-table
+              class="sTable"
+              ref="chooseTable"
+              size="small"
+              :rowKey="(record) => record.id"
+              :columns="chooseColumns"
+              :dataSource="chooseLoadData"
+              :scroll="{ x: 1335, y: 300 }"
+              :pagination="choosePaginationProps"
+              bordered>
+              <!-- 调出数量 -->
+              <template slot="qty" slot-scope="text, record">
+                <a-input-number
+                  id="allocateBillEdit-qty"
+                  v-model="record.qty"
+                  :precision="0"
+                  :min="1"
+                  :max="999999"
+                  placeholder="请输入"
+                  @blur="e => qtyBlur(e.target.value, record)"
+                  style="width: 100%;" />
+              </template>
+              <!-- 操作 -->
+              <template slot="action" slot-scope="text, record">
+                <a-button size="small" type="primary" class="button-error" @click="handleDel(record)" id="allocateBillEdit-del-btn">删除</a-button>
+              </template>
+            </a-table>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+      <a-affix :offset-bottom="0">
+        <div style="text-align: center;width: 100%;background-color: #fff;padding: 12px 0;box-shadow: 0 0 20px #dcdee2;">
+          <a-button
+            type="primary"
+            id="allocateBillEdit-submit"
+            size="large"
+            class="button-primary"
+            @click="handleSubmit"
+            style="padding: 0 60px;">提交</a-button>
+        </div>
+      </a-affix>
+    </a-spin>
+    <!-- 打印 -->
+    <div id="print"></div>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import { queryStockProductPage } from '@/api/stock'
+import { allocateBillDetailList, allocateBillDetailCount, allocateBillDetailSave, allocateBillSubmit, allocateBillDetailDel, allocateBillDetailDelAll, allocateBillDetailPrint } from '@/api/allocateBill'
+export default {
+  components: { STable, VSelect },
+  data () {
+    return {
+      spinning: false,
+      queryParam: {
+        productCode: '',
+        productName: '',
+        productOrigCode: ''
+      },
+      chooseQueryParam: {
+        productCode: '',
+        productName: ''
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      chooseDisabled: false, //  查询、重置按钮是否可操作
+      advanced: false, // 高级搜索 展开/关闭
+      productBrandList: [], //  产品品牌  下拉数据
+      productTypeList: [], //  产品分类  下拉数据
+      productType: [],
+      warehouseList: [], //  仓库  下拉数据
+      // 表头
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '产品编码', dataIndex: 'productCode', width: 220, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productName', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '原厂编码', dataIndex: 'productOrigCode', width: 220, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '成本价', dataIndex: 'lastStockCost', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '售价', dataIndex: 'productPrice', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '库存数量', dataIndex: 'currentStockQty', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'productUnit', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 100, align: 'center', fixed: 'right' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        return queryStockProductPage(Object.assign(parameter, this.queryParam, { zeroQtyFlag: '0', dealerLevel: this.$route.params.dealerLevel })).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.disabled = false
+          return data
+        })
+      },
+      // 表头
+      chooseColumns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '产品编码', dataIndex: 'productEntity.code', width: 220, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productEntity.name', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '原厂编码', dataIndex: 'productEntity.origCode', width: 220, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '成本价', dataIndex: 'cost', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '售价', dataIndex: 'price', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '库存数量', dataIndex: 'currentStockQty', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '调出数量', scopedSlots: { customRender: 'qty' }, width: 140, align: 'center' },
+        { title: '单位', dataIndex: 'productEntity.unit', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 100, align: 'center', fixed: 'right' }
+      ],
+      chooseLoadData: [],
+      choosePageNo: 1, //  分页页码
+      choosePageSize: 10, //  分页 每页多少条
+      choosePaginationProps: {
+        showSizeChanger: true, //  是否可以改变 pageSize
+        total: 0, //  分页总条数
+        current: 1,
+        onShowSizeChange: (current, pageSize) => this.changeChoosePageSize(current, pageSize),
+        onChange: (current) => this.changeChoosePage(current)
+      },
+      productTotal: null //  合计
+    }
+  },
+  methods: {
+    //  重置
+    resetSearchForm () {
+      this.queryParam.productCode = ''
+      this.queryParam.productName = ''
+      this.queryParam.productOrigCode = ''
+      this.$refs.table.refresh(true)
+    },
+    // 双击快速添加
+    handleClickRow (record) {
+      return {
+        on: {
+          dblclick: (event) => {
+            this.handleAdd(record)
+          }
+        }
+      }
+    },
+    // 已选产品  重置
+    chooseResetSearchForm () {
+      this.chooseQueryParam.productCode = ''
+      this.chooseQueryParam.productName = ''
+      this.choosePageNo = 1
+      this.choosePageSize = 10
+      this.choosePaginationProps.total = 0
+      this.choosePaginationProps.current = 1
+      this.getChooseProductList(1)
+    },
+    //  添加/编辑
+    handleAdd (row, isEdit) {
+      const params = {
+        id: isEdit ? row.id : undefined,
+        allocateSn: this.$route.params.sn,
+        cost: isEdit ? row.cost : row.lastStockCost,
+        price: isEdit ? row.price : row.productPrice,
+        qty: isEdit ? row.qty : 1, //  添加时调出数量默认为1
+        productSn: row.productSn
+      }
+      if (isEdit) { // 编辑
+        // 清空数量时,值应保持未清空前的值,因数量不可为空
+        if (!row.qty || row.qty == row.qtyBackups) {
+          row.qty = row.qtyBackups
+          return
+        }
+      }
+      this.spinning = true
+      allocateBillDetailSave(params).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          this.$refs.table.refresh()
+          this.getChooseProductList()
+          this.spinning = false
+        } else {
+          row.qty = row.qtyBackups
+          this.spinning = false
+        }
+      })
+    },
+    //  删除
+    handleDel (row, isAll) {
+      const _this = this
+      const content = isAll ? '删除后不可恢复,确定要进行整单删除吗?' : '删除后不可恢复,确定要进行删除吗?'
+      this.$confirm({
+        title: '提示',
+        content: content,
+        centered: true,
+        onOk () {
+          if (isAll) { //  整单删除
+            _this.spinning = true
+            allocateBillDetailDelAll({ sn: _this.$route.params.sn }).then(res => {
+              if (res.status == 200) {
+                _this.$message.success(res.message)
+                _this.$refs.table.refresh()
+                _this.getChooseProductList()
+                _this.spinning = false
+              } else {
+                _this.spinning = false
+              }
+            })
+          } else { //  单个删除
+            _this.spinning = true
+            allocateBillDetailDel({ id: row.id }).then(res => {
+              if (res.status == 200) {
+                _this.$message.success(res.message)
+                _this.$refs.table.refresh()
+                _this.getChooseProductList()
+                _this.spinning = false
+              } else {
+                _this.spinning = false
+              }
+            })
+          }
+        }
+      })
+    },
+    //  提交
+    handleSubmit () {
+      const _this = this
+      _this.spinning = true
+      allocateBillSubmit({ sn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          setTimeout(() => {
+            _this.handleBack()
+            _this.spinning = false
+          }, 1000)
+        } else {
+          _this.spinning = false
+        }
+      })
+    },
+    // 合计
+    getDetailCount (params) {
+      allocateBillDetailCount(params).then(res => {
+        if (res.status == 200) {
+          this.productTotal = res.data
+        } else {
+          this.productTotal = null
+        }
+      })
+    },
+    //  返回列表
+    handleBack () {
+      this.$router.push({ path: '/allocationManagement/transferOut/list' })
+    },
+    //  已选产品 分页  一页多少条change
+    changeChoosePageSize (current, pageSize) {
+      this.choosePageNo = current
+      this.choosePageSize = pageSize
+      this.getChooseProductList()
+    },
+    //  已选产品 分页 页码change
+    changeChoosePage (current) {
+      this.choosePageNo = current
+      this.getChooseProductList()
+    },
+    // 已选产品列表数据
+    getChooseProductList (pageNo) {
+      this.choosePageNo = this.choosePageNo || pageNo
+      this.chooseDisabled = true
+      const params = {
+        pageNo: this.choosePageNo,
+        pageSize: this.choosePageSize,
+        allocateSn: this.$route.params.sn
+      }
+      allocateBillDetailList(Object.assign(params, this.chooseQueryParam)).then(res => {
+        if (res.status == 200) {
+          //  合计
+          this.getDetailCount(Object.assign(params, this.chooseQueryParam))
+          const data = res.data
+          this.choosePaginationProps.total = Number(res.data.count) || 0
+          this.choosePaginationProps.current = data.pageNo
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+            data.list[i].qtyBackups = data.list[i].qty
+          }
+          this.chooseLoadData = data.list
+          this.chooseDisabled = false
+        } else {
+          this.choosePaginationProps.total = 0
+          this.choosePaginationProps.current = 1
+          this.chooseLoadData = []
+        }
+      })
+    },
+    // 已选产品 调出数量  blur
+    qtyBlur (val, record) {
+      //  光标移出,值发生改变再调用编辑接口
+      if (val != record.qtyBackups) {
+        this.handleAdd(record, 'edit')
+      }
+    },
+    // 打印预览/快捷打印
+    handlePrint (type) {
+      const _this = this
+      _this.spinning = true
+      allocateBillDetailPrint({ sn: this.$route.params.sn, isPreview: type == 'preview' ? 1 : 0 }).then(res => {
+        _this.spinning = false
+        if (res.type == 'application/json') {
+          var reader = new FileReader()
+          reader.addEventListener('loadend', function () {
+            const obj = JSON.parse(reader.result)
+            _this.$notification.error({
+              message: '提示',
+              description: obj.message
+            })
+          })
+          reader.readAsText(res)
+        } else {
+          this.print(res, type)
+        }
+      })
+    },
+    print (data, type) {
+      if (!data) {
+        return
+      }
+      const url = window.URL.createObjectURL(new Blob([data], { type: 'application/pdf' }))
+      document.getElementById('print').innerHTML = '<iframe id="printf" name="printf" src="' + url + '" hidden></iframe>'
+      if (type == 'preview') { //  预览
+        window.open(url)
+      } else if (type == 'print') { //  打印
+        window.frames['printf'].focus()
+        window.frames['printf'].print()
+      }
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.getChooseProductList(1)
+    })
+  }
+}
+</script>
+
+<style lang="less">
+  .allocateBillEdit-wrap{
+    .allocateBillEdit-back{
+      margin-bottom: 10px;
+    }
+    .allocateBillEdit-cont{
+      margin-bottom: 10px;
+      .sub-title{
+        font-size: 12px;
+        color: #808695;
+        margin-left: 10px;
+      }
+      .tag-txt{
+        font-size: 12px;
+        color: #ed1c24;
+      }
+      .edit-circle-btn{
+        margin-left: 15px;
+        i{
+          vertical-align: text-bottom;
+        }
+      }
+      .import-btn{
+        margin-left: 15px;
+      }
+    }
+  }
+</style>

+ 290 - 0
src/views/allocationManagement/transferOut/list.vue

@@ -0,0 +1,290 @@
+<template>
+  <a-card size="small" :bordered="false" class="allocateBillList-wrap">
+    <!-- 搜索条件 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
+        <a-row :gutter="15">
+          <a-col :md="6" :sm="24">
+            <a-form-item label="创建时间">
+              <rangeDate ref="rangeDate" @change="dateChange" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="调往对象">
+              <a-input id="allocateBillList-targetName" v-model.trim="queryParam.targetName" allowClear placeholder="请输入调往对象"/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="调拨类型">
+              <a-select id="allocateBillList-allocateTypeSn" v-model="queryParam.allocateTypeSn" placeholder="请选择调拨类型" allowClear >
+                <a-select-option v-for="item in allocateTypeList" :key="item.allocateTypeSn" :value="item.allocateTypeSn">{{ item.name }}</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+          <template v-if="advanced">
+            <a-col :md="6" :sm="24">
+              <a-form-item label="业务状态">
+                <v-select
+                  v-model="queryParam.state"
+                  ref="state"
+                  id="allocateBillList-state"
+                  code="ALLOCATE_STATUS"
+                  placeholder="请选择业务状态"
+                  allowClear
+                ></v-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="调拨单号">
+                <a-input id="allocateBillList-allocateNo" v-model.trim="queryParam.allocateNo" allowClear placeholder="请输入调拨单号"/>
+              </a-form-item>
+            </a-col>
+          </template>
+          <a-col :md="6" :sm="24">
+            <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="allocateBillList-refresh">查询</a-button>
+            <a-button style="margin-left: 5px" @click="resetSearchForm" :disabled="disabled" id="allocateBillList-reset">重置</a-button>
+            <!-- <a-button
+              style="margin: 0 0 18px 5px"
+              type="primary"
+              class="button-warning"
+              @click="handleExport"
+              :disabled="disabled"
+              :loading="exportLoading"
+              id="allocateBillList-export">导出</a-button> -->
+            <a @click="advanced=!advanced" style="margin-left: 8px">
+              {{ advanced ? '收起' : '展开' }}
+              <a-icon :type="advanced ? 'up' : 'down'"/>
+            </a>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 操作按钮 -->
+    <div class="table-operator">
+      <a-button id="allocateBillList-add" type="primary" class="button-error" @click="openModal=true">新增</a-button>
+    </div>
+    <!-- 列表 -->
+    <s-table
+      class="sTable"
+      ref="table"
+      size="default"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :data="loadData"
+      :scroll="{ x: 1940, y: tableHeight }"
+      bordered>
+      <!-- 单号 -->
+      <template slot="allocateNo" slot-scope="text, record">
+        <span style="color: #ed1c24;cursor: pointer;" @click="handleDetail(record)">{{ record.allocateNo }}</span>
+      </template>
+      <!-- 财务状态 -->
+      <template slot="settleState" slot-scope="text, record">
+        <a-badge :color="text=='FINISH'?'#87d068':'gold'" :text="record.settleStateDictValue" />
+      </template>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-button
+          size="small"
+          type="link"
+          v-if="record.state == 'WAIT_AUDIT'"
+          class="button-warning"
+          @click="handleExamine(record)"
+          id="allocateBillList-examine-btn">审核</a-button>
+        <a-button
+          size="small"
+          type="link"
+          v-if="(record.state == 'WAIT_SUBMIT') || (record.state == 'WAIT_AUDIT') || (record.state == 'AUDIT_REJECT')"
+          class="button-info"
+          @click="handleEdit(record)"
+          id="allocateBillList-edit-btn">编辑</a-button>
+        <a-button
+          size="small"
+          type="link"
+          v-if="(record.state == 'WAIT_SUBMIT') || (record.state == 'WAIT_AUDIT') || (record.state == 'AUDIT_REJECT')"
+          class="button-error"
+          @click="handleDel(record)"
+          id="allocateBillList-del-btn">删除</a-button>
+        <span v-if="(record.state != 'WAIT_SUBMIT') && (record.state != 'WAIT_AUDIT') && (record.state != 'AUDIT_REJECT')">--</span>
+      </template>
+    </s-table>
+    <!-- 新增 -->
+    <basic-info-modal :openModal="openModal" @ok="handleOk" @close="openModal=false" />
+  </a-card>
+</template>
+
+<script>
+import moment from 'moment'
+import { STable, VSelect } from '@/components'
+import basicInfoModal from './basicInfoModal.vue'
+import rangeDate from '@/views/common/rangeDate.vue'
+import { allocateBillList, allocateBillDel, allocateBillAudit, allocateBillExport } from '@/api/allocateBill'
+import { allocateTypeAllList } from '@/api/allocateType'
+export default {
+  components: { STable, VSelect, basicInfoModal, rangeDate },
+  data () {
+    return {
+      advanced: false, // 高级搜索 展开/关闭
+      tableHeight: 0,
+      queryParam: { //  查询条件
+        beginDate: '',
+        endDate: '',
+        targetName: '', //  调往对象
+        allocateTypeSn: undefined, //  调拨类型
+        state: undefined, //  业务状态
+        allocateNo: '' //  调拨单号
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      exportLoading: false,
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '创建时间', dataIndex: 'createDate', width: 160, align: 'center' },
+        { title: '调拨单号', scopedSlots: { customRender: 'allocateNo' }, align: 'center' },
+        { title: '调往对象', dataIndex: 'targetName', width: 220, align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '客户类型', dataIndex: 'dealerLevelDictValue', width: 160, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '总数量', dataIndex: 'totalQty', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '总成本', dataIndex: 'totalCost', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '总售价', dataIndex: 'totalPrice', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '审核时间', dataIndex: 'auditTime', width: 160, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '调拨类型', dataIndex: 'allocateTypeName', width: 140, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '业务状态', dataIndex: 'stateDictValue', width: 110, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '打印状态', dataIndex: 'printStateDictValue', width: 110, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '打印次数', dataIndex: 'printCount', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 180, align: 'center', fixed: 'right' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        if (this.tableHeight == 0) {
+          this.tableHeight = window.innerHeight - 380
+        }
+        return allocateBillList(Object.assign(parameter, this.queryParam)).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.disabled = false
+          return data
+        })
+      },
+      allocateTypeList: [], //  调拨类型
+      openModal: false //  新增编辑  弹框
+    }
+  },
+  methods: {
+    //  创建时间  change
+    dateChange (date) {
+      this.queryParam.beginDate = date[0]
+      this.queryParam.endDate = date[1]
+    },
+    //  重置
+    resetSearchForm () {
+      this.$refs.rangeDate.resetDate()
+      this.queryParam.beginDate = ''
+      this.queryParam.endDate = ''
+      this.queryParam.targetName = ''
+      this.queryParam.allocateTypeSn = undefined
+      this.queryParam.state = undefined
+      this.queryParam.allocateNo = ''
+      this.$refs.table.refresh(true)
+    },
+    //  基本信息  保存
+    handleOk (data) {
+      this.$router.push({ path: `/allocationManagement/transferOut/add/${data.allocateSn}/${data.targetName}/${data.dealerLevel}` })
+    },
+    //  删除
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '删除后不可恢复,确定要进行删除吗?',
+        centered: true,
+        onOk () {
+          allocateBillDel({ sn: row.allocateSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+            }
+          })
+        }
+      })
+    },
+    //  审核
+    handleExamine (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认要审核通过吗?',
+        centered: true,
+        closable: true,
+        okText: '审核通过',
+        cancelText: '审核不通过',
+        onOk () {
+          _this.auditOrder(row.allocateSn, 'WAIT_OUT_WAREHOUSE')
+        },
+        onCancel (e) {
+          if (!e.triggerCancel) {
+            _this.auditOrder(row.allocateSn, 'AUDIT_REJECT')
+          }
+          _this.$destroyAll()
+        }
+      })
+    },
+    // 审核
+    auditOrder (sn, state) {
+      const _this = this
+      allocateBillAudit({ sn: sn, state: state }).then(res => {
+        if (res.status == 200) {
+          _this.$message.success(res.message)
+          _this.$refs.table.refresh()
+        }
+      })
+    },
+    //  详情
+    handleDetail (row) {
+      this.$router.push({ path: `/allocationManagement/transferOut/detail/${row.allocateSn}` })
+    },
+    //  编辑
+    handleEdit (row) {
+      this.$router.push({ path: `/allocationManagement/transferOut/edit/${row.allocateSn}/${row.targetName}/${row.dealerLevel}` })
+    },
+    //  导出
+    handleExport () {
+      const params = this.queryParam
+      this.exportLoading = true
+      allocateBillExport(params).then(res => {
+        this.exportLoading = false
+        this.download(res)
+      })
+    },
+    download (data) {
+      if (!data) { return }
+      const url = window.URL.createObjectURL(new Blob([data]))
+      const link = document.createElement('a')
+      link.style.display = 'none'
+      link.href = url
+      const a = moment().format('YYYYMMDDHHmmss')
+      const fname = '调拨列表' + a
+      link.setAttribute('download', fname + '.xlsx')
+      document.body.appendChild(link)
+      link.click()
+    },
+    //  调拨类型
+    getAllocateTypeAllList () {
+      allocateTypeAllList().then(res => {
+        if (res.status == 200) {
+          this.allocateTypeList = res.data
+        } else {
+          this.allocateTypeList = []
+        }
+      })
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.openModal = false
+      vm.getAllocateTypeAllList()
+    })
+  }
+}
+</script>

+ 159 - 0
src/views/basicData/transferTypeManagement/editModal.vue

@@ -0,0 +1,159 @@
+<template>
+  <a-modal
+    centered
+    class="transferTypeManagementEdit-modal"
+    :footer="null"
+    :maskClosable="false"
+    :title="modalTit"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="800">
+    <!-- 表单 -->
+    <div>
+      <a-spin :spinning="spinning" tip="Loading...">
+        <a-form-model
+          id="transferTypeManagementEdit-form"
+          ref="ruleForm"
+          :model="form"
+          :rules="rules"
+          :label-col="formItemLayout.labelCol"
+          :wrapper-col="formItemLayout.wrapperCol"
+        >
+          <a-form-model-item label="调拨类别" prop="allocateCategory">
+            <v-select code="ALLOCATE_CATEGORY" id="transferTypeManagementEdit-allocateCategory" v-model="form.allocateCategory" allowClear placeholder="请选择调拨类别"></v-select>
+          </a-form-model-item>
+          <a-form-model-item label="调拨类型名称" prop="name">
+            <a-input
+              id="transferTypeManagementEdit-name"
+              :maxLength="30"
+              v-model.trim="form.name"
+              @change="filterEmpty"
+              placeholder="请输入调拨类型名称(最多30个字符)"
+              allowClear />
+          </a-form-model-item>
+        </a-form-model>
+        <div class="btn-cont">
+          <a-button type="primary" id="storeTransferOut-type-edit-modal-save" @click="handleSave">保存</a-button>
+          <a-button id="storeTransferOut-type-edit-modal-back" @click="isShow = false" style="margin-left: 15px;">返回列表</a-button>
+        </div>
+      </a-spin>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { VSelect } from '@/components'
+import { allocateTypeSave } from '@/api/allocateType'
+export default {
+  name: 'TransferTypeManagementEditModal',
+  components: { VSelect },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemSn: {
+      type: [Number, String],
+      default: ''
+    },
+    nowData: {
+      type: Object,
+      default: null
+    }
+  },
+  computed: {
+    modalTit () {
+      return (this.itemSn ? '编辑' : '新增') + '调拨类型'
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      spinning: false,
+      detailsData: null, //  品牌数据
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 16 }
+      },
+      form: {
+        name: '', // 调拨类型名称
+        allocateCategory: undefined //  调拨类别
+      },
+      rules: {
+        name: [
+          { required: true, message: '请输入调拨类型名称', trigger: 'blur' }
+        ],
+        allocateCategory: [
+          { required: true, message: '请选择调拨类别', trigger: 'change' }
+        ]
+      }
+    }
+  },
+  methods: {
+    filterEmpty () {
+      let str = this.form.name
+      str = str.replace(/\ +/g, '')
+      str = str.replace(/[ ]/g, '')
+      str = str.replace(/[\r\n]/g, '')
+      this.form.name = str
+    },
+    //  保存
+    handleSave () {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const form = _this.form
+          form.allocateTypeSn = _this.itemSn ? _this.itemSn : null
+          _this.spinning = true
+          allocateTypeSave(form).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.isShow = false
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.$refs.ruleForm.resetFields()
+      }
+    },
+    itemSn (newValue, oldValue) {
+      if (this.isShow && newValue) { //  编辑
+        this.form.name = this.nowData && this.nowData.name ? this.nowData.name : ''
+        this.form.allocateCategory = this.nowData && this.nowData.allocateCategory ? this.nowData.allocateCategory : ''
+      } else { //  添加
+        this.form.name = ''
+        this.form.allocateCategory = undefined
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .transferTypeManagementEdit-modal{
+    .ant-modal-body {
+      padding: 40px 40px 24px;
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>

+ 104 - 0
src/views/basicData/transferTypeManagement/list.vue

@@ -0,0 +1,104 @@
+<template>
+  <a-card size="small" :bordered="false" class="transferTypeManagementList-wrap">
+    <!-- 操作按钮 -->
+    <div class="table-operator-nobor">
+      <a-button
+        id="transferTypeManagementList-add"
+        type="primary"
+        class="button-error"
+        @click="handleEdit()">新增</a-button>
+    </div>
+    <!-- 列表 -->
+    <s-table
+      class="sTable"
+      ref="table"
+      size="default"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :data="loadData"
+      bordered>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-button
+          size="small"
+          type="link"
+          class="button-info"
+          @click="handleEdit(record)"
+          id="transferTypeManagementList-edit-btn">编辑</a-button>
+        <a-button
+          size="small"
+          type="link"
+          class="button-error"
+          @click="handleDel(record)"
+          id="transferTypeManagementList-del-btn">删除</a-button>
+      </template>
+    </s-table>
+    <!-- 新增/编辑 -->
+    <transfer-type-management-edit-modal :openModal="openModal" :nowData="nowData" :itemSn="itemSn" @close="closeModal" />
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import transferTypeManagementEditModal from './editModal.vue'
+import { allocateTypeList, allocateTypeDel } from '@/api/allocateType'
+export default {
+  components: { STable, VSelect, transferTypeManagementEditModal },
+  data () {
+    return {
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '创建时间', dataIndex: 'createDate', width: 160, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '调拨类别', dataIndex: 'allocateCategoryDictValue', width: 200, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '调拨类型名称', dataIndex: 'name', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 200, align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        return allocateTypeList(Object.assign(parameter, {})).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          return data
+        })
+      },
+      openModal: false, //  新增编辑调拨类型  弹框
+      itemSn: '', //  当前sn
+      nowData: null //  当前记录数据
+    }
+  },
+  methods: {
+    //  新增/编辑
+    handleEdit (row) {
+      this.itemSn = row ? row.allocateTypeSn : null
+      this.nowData = row || null
+      this.openModal = true
+    },
+    //  删除
+    handleDel (row) {
+      const _this = this
+      _this.$confirm({
+        title: '提示',
+        content: '删除后原数据不可恢复,是否删除?',
+        centered: true,
+        onOk () {
+          allocateTypeDel({ sn: row.allocateTypeSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+            }
+          })
+        }
+      })
+    },
+    //  关闭弹框
+    closeModal () {
+      this.itemSn = ''
+      this.openModal = false
+      this.$refs.table.refresh(true)
+    }
+  }
+}
+</script>

+ 162 - 0
src/views/basicData/warehouse/editModal.vue

@@ -0,0 +1,162 @@
+<template>
+  <a-modal
+    centered
+    class="warehouseEdit-modal"
+    :footer="null"
+    :maskClosable="false"
+    :title="modalTit"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="800">
+    <!-- 表单 -->
+    <div>
+      <a-spin :spinning="spinning" tip="Loading...">
+        <a-form-model
+          id="warehouseEdit-form"
+          ref="ruleForm"
+          :model="form"
+          :rules="rules"
+          :label-col="formItemLayout.labelCol"
+          :wrapper-col="formItemLayout.wrapperCol"
+        >
+          <a-form-model-item label="仓库名称" prop="name">
+            <a-input
+              id="warehouseEdit-name"
+              :maxLength="30"
+              v-model.trim="form.name"
+              @change="filterEmpty"
+              placeholder="请输入仓库名称(最多30个字符)"
+              allowClear />
+          </a-form-model-item>
+        </a-form-model>
+        <div class="btn-cont">
+          <a-button type="primary" id="warehouse-edit-modal-save" @click="handleSave">保存</a-button>
+          <a-button id="warehouse-edit-modal-back" @click="isShow = false" style="margin-left: 15px;">返回列表</a-button>
+        </div>
+      </a-spin>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { STable } from '@/components'
+import { warehouseSave } from '@/api/warehouse'
+export default {
+  name: 'WarehouseEditModal',
+  components: { STable },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemSn: {
+      type: [Number, String],
+      default: ''
+    },
+    nowData: {
+      type: Object,
+      default: null
+    }
+  },
+  computed: {
+    modalTit () {
+      return (this.itemSn ? '编辑' : '新增') + '仓库'
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      spinning: false,
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 16 }
+      },
+      form: {
+        name: '' // 仓库名称
+      },
+      rules: {
+        name: [
+          { required: true, message: '请输入仓库名称', trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  methods: {
+    filterEmpty () {
+      let str = this.form.name
+      str = str.replace(/\ +/g, '')
+      str = str.replace(/[ ]/g, '')
+      str = str.replace(/[\r\n]/g, '')
+      this.form.name = str
+    },
+    //  详情
+    getDetail () {
+      this.form = {
+        name: this.nowData && this.nowData.name ? this.nowData.name : ''
+      }
+    },
+    //  保存
+    handleSave () {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const params = {
+            warehouseSn: this.itemSn ? this.itemSn : undefined,
+            name: this.form.name //  仓库名称
+          }
+          _this.spinning = true
+          warehouseSave(params).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$emit('ok')
+              setTimeout(function () {
+                _this.isShow = false
+                _this.$refs.ruleForm.resetFields()
+                _this.spinning = false
+              }, 300)
+            } else {
+              _this.spinning = false
+            }
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+      } else {
+        this.form = {
+          name: ''
+        }
+      }
+    },
+    itemSn (newValue, oldValue) {
+      if (this.isShow && newValue) {
+        this.getDetail()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .warehouseEdit-modal{
+    .ant-modal-body {
+    	padding: 40px 40px 24px;
+    }
+    .btn-cont {
+    	text-align: center;
+    	margin: 35px 0 10px;
+    }
+  }
+</style>

+ 147 - 0
src/views/basicData/warehouse/list.vue

@@ -0,0 +1,147 @@
+<template>
+  <a-card size="small" :bordered="false" class="warehouseList-wrap">
+    <!-- 搜索条件 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
+        <a-row :gutter="15">
+          <a-col :md="6" :sm="24">
+            <a-form-item label="仓库名称">
+              <a-input id="warehouseList-name" v-model.trim="queryParam.name" allowClear placeholder="请输入仓库名称"/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="warehouseList-refresh">查询</a-button>
+            <a-button style="margin-left: 8px" @click="resetSearchForm" :disabled="disabled" id="warehouseList-reset">重置</a-button>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 操作按钮 -->
+    <div class="table-operator">
+      <a-button id="warehouseList-add" type="primary" class="button-error" @click="handleEdit()">新增</a-button>
+    </div>
+    <!-- 列表 -->
+    <s-table
+      class="sTable"
+      ref="table"
+      size="default"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :data="loadData"
+      :scroll="{ y: tableHeight }"
+      bordered>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-button
+          size="small"
+          type="link"
+          class="button-warning"
+          @click="goStoringLocation(record)"
+          id="warehouseList-storingLocation-btn">仓位管理</a-button>
+        <a-button
+          size="small"
+          type="link"
+          class="button-info"
+          v-if="record.defaultFlag!='1'"
+          @click="handleEdit(record)"
+          id="warehouseList-edit-btn">编辑</a-button>
+        <a-button
+          size="small"
+          type="link"
+          class="button-error"
+          v-if="record.defaultFlag!='1'"
+          @click="handleDel(record)"
+          id="warehouseList-del-btn">删除</a-button>
+      </template>
+    </s-table>
+    <!-- 新增/编辑仓库 -->
+    <warehouse-edit-modal :openModal="openModal" :nowData="nowData" :itemSn="itemSn" @ok="handleOk" @close="closeModal" />
+  </a-card>
+</template>
+
+<script>
+import { warehouseList, warehouseDel } from '@/api/warehouse'
+import { STable } from '@/components'
+import warehouseEditModal from './editModal.vue'
+export default {
+  components: { STable, warehouseEditModal },
+  data () {
+    return {
+      queryParam: { //  查询条件
+        name: '' //  仓库名称
+      },
+      tableHeight: 0,
+      disabled: false, //  查询、重置按钮是否可操作
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '仓库名称', dataIndex: 'name', align: 'center', ellipsis: true, customRender: function (text) { return text || '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        if (this.tableHeight == 0) {
+          this.tableHeight = window.innerHeight - 380
+        }
+        return warehouseList(Object.assign(parameter, this.queryParam)).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.disabled = false
+          return data
+        })
+      },
+      openModal: false, //  新增编辑  弹框
+      itemSn: '', //  当前sn
+      nowData: null //  当前记录数据
+    }
+  },
+  methods: {
+    //  重置
+    resetSearchForm () {
+      this.queryParam.name = ''
+      this.$refs.table.refresh(true)
+    },
+    //  新增/编辑
+    handleEdit (row) {
+      this.itemSn = row ? row.warehouseSn : null
+      this.nowData = row || null
+      this.openModal = true
+    },
+    //  新增/编辑  成功
+    handleOk () {
+      this.$refs.table.refresh(true)
+    },
+    //  关闭弹框
+    closeModal () {
+      this.itemSn = ''
+      this.openModal = false
+    },
+    //  删除
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '删除后不可恢复,确定要进行删除吗?',
+        centered: true,
+        onOk () {
+          warehouseDel({
+            sn: row.warehouseSn
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+            }
+          })
+        }
+      })
+    },
+    //  查看仓位
+    goStoringLocation (row) {
+      this.$router.push({ path: `/basicData/storingLocation/${row.warehouseSn}`, query: { name: row.name } })
+    }
+  }
+}
+</script>

+ 183 - 0
src/views/basicData/warehouse/storingLocation/editModal.vue

@@ -0,0 +1,183 @@
+<template>
+  <a-modal
+    centered
+    class="storingLocationEdit-modal"
+    :footer="null"
+    :maskClosable="false"
+    :title="modalTit"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="800">
+    <!-- 表单 -->
+    <div>
+      <a-spin :spinning="spinning" tip="Loading...">
+        <a-form-model
+          id="storingLocationEdit-form"
+          ref="ruleForm"
+          :model="form"
+          :rules="rules"
+          :label-col="formItemLayout.labelCol"
+          :wrapper-col="formItemLayout.wrapperCol"
+        >
+          <a-form-model-item label="仓位名称" prop="name">
+            <a-input
+              id="storingLocationEdit-name"
+              :maxLength="30"
+              v-model="form.name"
+              placeholder="请输入仓位名称(最多30个字符)"
+              allowClear />
+          </a-form-model-item>
+          <a-form-model-item label="所属仓库" prop="warehouseSn">
+            <a-select id="storingLocationEdit-warehouseSn" disabled placeholder="请选择所属仓库" allowClear v-model="form.warehouseSn">
+              <a-select-option v-for="item in warehouseList" :key="item.id" :value="item.warehouseSn">{{ item.name }}</a-select-option>
+            </a-select>
+          </a-form-model-item>
+        </a-form-model>
+        <div class="btn-cont">
+          <a-button type="primary" id="storingLocation-edit-modal-save" @click="handleSave">保存</a-button>
+          <a-button id="storingLocation-edit-modal-back" @click="isShow = false" style="margin-left: 15px;">返回列表</a-button>
+        </div>
+      </a-spin>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { STable } from '@/components'
+import { warehouseLocSave, warehouseAllList } from '@/api/warehouse'
+export default {
+  name: 'StoringLocationEditModal',
+  components: { STable },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemSn: {
+      type: [Number, String],
+      default: ''
+    },
+    nowData: {
+      type: Object,
+      default: null
+    }
+  },
+  computed: {
+    modalTit () {
+      return (this.itemSn ? '编辑' : '新增') + '仓位'
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      spinning: false,
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 16 }
+      },
+      form: {
+        name: '', // 仓位名称
+        warehouseSn: undefined //  所属仓库
+      },
+      rules: {
+        name: [
+          { required: true, message: '请输入仓位名称', trigger: 'blur' }
+        ],
+        warehouseSn: [
+          { required: true, message: '请选择所属仓库', trigger: 'change' }
+        ]
+      },
+      warehouseList: [] //  仓库  下拉数据
+    }
+  },
+  methods: {
+    //  获取仓库列表数据
+    getWarehouseList () {
+      warehouseAllList({}).then(res => {
+        if (res.status == 200) {
+          this.warehouseList = res.data
+        } else {
+          this.warehouseList = []
+        }
+      })
+    },
+    //  详情
+    getDetail () {
+      this.form = {
+        name: this.nowData && this.nowData.name ? this.nowData.name : '',
+        warehouseSn: this.nowData && this.nowData.warehouseSn ? this.nowData.warehouseSn : ''
+      }
+    },
+    //  保存
+    handleSave () {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const params = {
+            warehouseLocationSn: this.itemSn ? this.itemSn : undefined,
+            warehouseSn: this.form.warehouseSn, //  所属仓库
+            name: this.form.name //  仓库名称
+          }
+          _this.spinning = true
+          warehouseLocSave(params).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$emit('ok')
+              setTimeout(function () {
+                _this.isShow = false
+                _this.$refs.ruleForm.resetFields()
+                _this.spinning = false
+              }, 300)
+            } else {
+              _this.spinning = false
+            }
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$refs.ruleForm.resetFields()
+        this.form = {
+          name: '',
+          warehouseSn: ''
+        }
+        this.$emit('close')
+      } else {
+        this.getWarehouseList()
+        this.form = {
+          name: '',
+          warehouseSn: this.nowData && this.nowData.warehouseSn ? this.nowData.warehouseSn : ''
+        }
+      }
+    },
+    itemSn (newValue, oldValue) {
+      if (this.isShow && newValue) {
+        this.getDetail()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .storingLocationEdit-modal{
+    .ant-modal-body {
+      padding: 40px 40px 24px;
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>

+ 167 - 0
src/views/basicData/warehouse/storingLocation/list.vue

@@ -0,0 +1,167 @@
+<template>
+  <div class="storingLocationList-wrap">
+    <a-page-header :ghost="false" :backIcon="false" class="storingLocationList-back">
+      <!-- 自定义的二级文字标题 -->
+      <template slot="subTitle">
+        <a id="storingLocationList-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+        <strong style="color: rgba(0, 0, 0, 0.65);margin-left: 50px;">所属仓库:{{ $route.query.name }}</strong>
+      </template>
+    </a-page-header>
+    <a-card size="small" :bordered="false" class="storingLocationList-cont">
+      <!-- 搜索条件 -->
+      <div class="table-page-search-wrapper">
+        <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
+          <a-row :gutter="15">
+            <a-col :md="6" :sm="24">
+              <a-form-item label="仓位名称">
+                <a-input id="storingLocationList-name" v-model.trim="queryParam.name" allowClear placeholder="请输入仓位名称"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="storingLocationList-refresh">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetSearchForm" :disabled="disabled" id="storingLocationList-reset">重置</a-button>
+            </a-col>
+          </a-row>
+        </a-form>
+      </div>
+      <!-- 操作按钮 -->
+      <div class="table-operator" style="border: 0;padding: 0 0 15px;">
+        <a-button id="storingLocationList-add" type="primary" class="button-error" @click="handleEdit()">新增</a-button>
+      </div>
+      <!-- 列表 -->
+      <s-table
+        class="sTable"
+        ref="table"
+        size="default"
+        :rowKey="(record) => record.id"
+        :columns="columns"
+        :data="loadData"
+        :scroll="{ y: tableHeight }"
+        bordered>
+        <!-- 操作 -->
+        <template slot="action" slot-scope="text, record">
+          <a-button
+            size="small"
+            type="link"
+            class="button-info"
+            v-if="record.defaultFlag!='1'"
+            @click="handleEdit(record)"
+            id="storingLocationList-edit-btn">编辑</a-button>
+          <a-button
+            size="small"
+            type="link"
+            class="button-error"
+            v-if="record.defaultFlag!='1'"
+            @click="handleDel(record)"
+            id="storingLocationList-del-btn">删除</a-button>
+          <span v-if="record.defaultFlag=='1'">--</span>
+        </template>
+      </s-table>
+    </a-card>
+    <!-- 新增/编辑仓位 -->
+    <storing-location-edit-modal :openModal="openModal" :nowData="nowData" :itemSn="itemSn" @ok="handleOk" @close="closeModal" />
+  </div>
+</template>
+
+<script>
+import { warehouseLocList, warehouseLocDel } from '@/api/warehouse'
+import { STable } from '@/components'
+import storingLocationEditModal from './editModal.vue'
+export default {
+  components: { STable, storingLocationEditModal },
+  data () {
+    return {
+      tableHeight: 0,
+      queryParam: { //  查询条件
+        warehouseSn: this.$route.params.sn, //  仓库sn
+        name: '' //  仓位名称
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '仓位名称', dataIndex: 'name', align: 'center', ellipsis: true },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 160, align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        if (this.tableHeight == 0) {
+          this.tableHeight = window.innerHeight - 380
+        }
+        return warehouseLocList(Object.assign(parameter, this.queryParam)).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.disabled = false
+          return data
+        })
+      },
+      openModal: false, //  新增编辑产品品牌  弹框
+      itemSn: '', //  当前sn
+      nowData: null //  当前记录数据
+    }
+  },
+  methods: {
+    //  重置
+    resetSearchForm () {
+      this.queryParam.warehouseSn = this.$route.params.sn
+      this.queryParam.name = ''
+      this.$refs.table.refresh(true)
+    },
+    //  新增/编辑
+    handleEdit (row) {
+      if (row) {
+        this.itemSn = row.warehouseLocationSn
+        row.warehouseSn = this.$route.params.sn
+        this.nowData = row
+      } else {
+        this.itemSn = null
+        this.nowData = { warehouseSn: this.$route.params.sn }
+      }
+      this.openModal = true
+    },
+    //  新增/编辑  成功
+    handleOk () {
+      this.$refs.table.refresh(true)
+    },
+    //  关闭弹框
+    closeModal () {
+      this.itemSn = ''
+      this.openModal = false
+    },
+    //  删除
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '删除后不可恢复,确定要进行删除吗?',
+        centered: true,
+        onOk () {
+          warehouseLocDel({
+            sn: row.warehouseLocationSn
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+            }
+          })
+        }
+      })
+    },
+    //  返回列表
+    handleBack () {
+      this.$router.push({ path: '/basicData/warehouse/list' })
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .storingLocationList-wrap{
+    .storingLocationList-back{
+      margin-bottom: 10px;
+    }
+  }
+</style>

+ 162 - 0
src/views/common/chooseBrandModal.vue

@@ -0,0 +1,162 @@
+<template>
+  <a-modal
+    centered
+    class="chooseBrand-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="选择产品品牌"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="800">
+    <div class="chooseBrand-con">
+      <div>
+        <a-checkbox :checked="checkAll" @change="onCheckAllChange">全选</a-checkbox>
+      </div>
+      <a-divider />
+      <a-checkbox-group v-model="checkedList" @change="onChange" style="width: 100%;">
+        <a-row style="height: 400px;overflow-y: scroll;">
+          <a-col :span="6" v-for="item in brandList" :key="item.brandSn">
+            <a-checkbox :value="item.brandSn">
+              {{ item.brandName }}
+            </a-checkbox>
+          </a-col>
+        </a-row>
+      </a-checkbox-group>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="chooseBrand-submit"
+          size="large"
+          class="button-primary"
+          @click="handleSave"
+          style="padding: 0 60px;">保存</a-button>
+        <a-button
+          id="chooseBrand-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 60px;margin-left: 15px;">取消</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { productBrandQuery } from '@/api/productBrand'
+export default {
+  name: 'ChooseBrandModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    chooseData: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      checkAll: false, //  全选
+      checkedList: [], //  选中项
+      checkedRowList: [], //  选中项
+      brandList: [] //  品牌数据
+    }
+  },
+  methods: {
+    // 保存
+    handleSave () {
+      const _this = this
+      if (this.checkedList.length < 1) {
+        this.$message.warning('请在列表勾选后再进行操作!')
+        return
+      }
+      this.checkedRowList = []
+      _this.brandList.map(item => {
+        if (_this.checkedList.indexOf(item.brandSn) != -1) {
+          _this.checkedRowList.push(item)
+        }
+      })
+      this.$emit('ok', this.checkedRowList)
+      this.isShow = false
+    },
+    // change
+    onChange (checkedList) {
+      const _this = this
+      this.checkAll = checkedList.length === this.brandList.length
+      this.brandList.map(item => {
+        if (_this.checkedList.indexOf(item.brandSn) != -1) {
+          _this.checkedRowList.push(item)
+        }
+      })
+    },
+    // 全选
+    onCheckAllChange (e) {
+      const _this = this
+      this.checkAll = e.target.checked
+      if (e.target.checked) {
+        this.checkedList = []
+        this.checkedRowList = []
+        this.brandList.map(item => {
+          _this.checkedList.push(item.brandSn)
+          _this.checkedRowList.push(item)
+        })
+      } else {
+        this.checkedList = []
+        this.checkedRowList = []
+      }
+    },
+    // 获取品牌数据
+    getBrandList () {
+      productBrandQuery({}).then(res => {
+        if (res.status == 200) {
+          this.brandList = res.data
+        } else {
+          this.brandList = []
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.checkAll = false
+      } else {
+        const _this = this
+        this.checkedRowList = this.chooseData
+        this.checkedList = []
+        this.chooseData.map(item => {
+          _this.checkedList.push(item.goodsSn)
+        })
+        if (this.brandList.length == 0) {
+          this.getBrandList()
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseBrand-modal{
+    .chooseBrand-con{
+      .btn-con{
+        text-align: center;
+        margin: 30px 0 20px;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 248 - 0
src/views/common/chooseCustomerModal.vue

@@ -0,0 +1,248 @@
+<template>
+  <a-modal
+    centered
+    class="chooseCustomer-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="选择客户"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="900">
+    <div class="chooseCustomer-con">
+      <!-- 搜索条件 -->
+      <div class="table-page-search-wrapper">
+        <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
+          <a-row :gutter="15">
+            <a-col :md="6" :sm="24">
+              <a-form-item label="客户名称">
+                <a-input id="chooseCustomer-dealerName" v-model.trim="queryParam.dealerName" allowClear placeholder="请输入客户名称"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-row>
+                <a-form-item label="地区">
+                  <a-col span="7">
+                    <a-form-item prop="provinceSn" style="margin: 0;">
+                      <a-select v-model="queryParam.provinceSn" @change="getCityList" placeholder="请选择省">
+                        <a-select-option v-for="item in addrProvinceList" :value="item.id" :key="item.id + 'a'">{{ item.name }}</a-select-option>
+                      </a-select>
+                    </a-form-item>
+                  </a-col>
+                  <a-col span="7" offset="1">
+                    <a-form-item prop="citySn" style="margin: 0;">
+                      <a-select v-model="queryParam.citySn" @change="getAreaList" placeholder="请选择市">
+                        <a-select-option v-for="item in addrCityList" :value="item.id" :key="item.id + 'b'">{{ item.name }}</a-select-option>
+                      </a-select>
+                    </a-form-item>
+                  </a-col>
+                  <a-col span="7" offset="1">
+                    <a-form-item prop="districtSn" style="margin: 0;">
+                      <a-select v-model="queryParam.districtSn" placeholder="请选择区/县">
+                        <a-select-option v-for="item in addrDistrictList" :value="item.id" :key="item.id + 'c'">{{ item.name }}</a-select-option>
+                      </a-select>
+                    </a-form-item>
+                  </a-col>
+                </a-form-item>
+              </a-row>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-button style="margin-bottom: 18px;" type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="promotionRulesList-refresh">查询</a-button>
+              <a-button style="margin: 0 0 18px 8px" @click="resetSearchForm" :disabled="disabled" id="promotionRulesList-reset">重置</a-button>
+            </a-col>
+          </a-row>
+        </a-form>
+      </div>
+      <p style="font-weight: bold;">当前已选:{{ selectedRowKeys.length }}个</p>
+      <!-- 列表 -->
+      <s-table
+        class="sTable"
+        ref="table"
+        size="small"
+        :row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
+        :rowKey="(record) => record.dealerSn"
+        :columns="columns"
+        :data="loadData"
+        :defaultLoadData="false"
+        bordered>
+      </s-table>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="chooseCustomer-submit"
+          size="large"
+          class="button-primary"
+          style="padding: 0 60px;"
+          @click="handleSubmit">确定</a-button>
+        <a-button
+          id="chooseCustomer-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 60px;margin-left: 15px;">取消</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { STable } from '@/components'
+import { getArea } from '@/api/data'
+import { dealerQueryList } from '@/api/dealer'
+export default {
+  name: 'ChooseCustomerModal',
+  components: { STable },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    chooseCust: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      disabled: false, //  查询、重置按钮是否可操作
+      queryParam: {
+        dealerName: '',
+        provinceSn: undefined,
+        citySn: undefined,
+        districtSn: undefined
+      },
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '客户名称', dataIndex: 'dealerName', align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        return dealerQueryList(Object.assign(parameter, this.queryParam)).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.disabled = false
+          return data
+        })
+      },
+      selectedRowKeys: [],
+      addrProvinceList: [], //  省下拉
+      addrCityList: [], //  市下拉
+      addrDistrictList: [] //  区下拉
+    }
+  },
+  methods: {
+    //  重置
+    resetSearchForm () {
+      this.resetData()
+      this.$refs.table.refresh(true)
+    },
+    resetData () {
+      console.log('重置艾迪康')
+      this.queryParam.dealerName = ''
+      this.queryParam.provinceSn = undefined
+      this.queryParam.citySn = undefined
+      this.queryParam.districtSn = undefined
+      this.addrCityList = []
+      this.addrDistrictList = []
+    },
+    //  确定
+    handleSubmit () {
+      if (this.selectedRowKeys.length < 1) {
+        this.$message.warning('请在列表勾选后再进行操作!')
+        return
+      }
+      this.$emit('ok', this.selectedRowKeys)
+      this.isShow = false
+    },
+    onSelectChange (selectedRowKeys, selectedRows) {
+      console.log('selectedRowKeys changed: ', selectedRowKeys, selectedRows)
+      this.selectedRowKeys = selectedRowKeys
+    },
+    // 获取城市列表
+    getCityList (val) {
+      this.addrCityList = []
+      this.addrDistrictList = []
+      this.queryParam.citySn = undefined
+      this.queryParam.districtSn = undefined
+      this.getArea('city', val)
+    },
+    // 获取区县列表
+    getAreaList (val) {
+      this.addrDistrictList = []
+      this.queryParam.districtSn = undefined
+      this.getArea('district', val)
+    },
+    //  省/市/区
+    getArea (leve, sn) {
+      let params
+      if (leve == 'province') {
+        params = { type: '2' }
+      } else {
+        params = { parentId: sn, type: leve == 'city' ? '3' : '4' }
+      }
+      getArea(params).then(res => {
+        if (res.status == 200) {
+          if (leve == 'province') {
+            this.addrProvinceList = res.data || []
+          } else if (leve == 'city') {
+            this.addrCityList = res.data || []
+          } else if (leve == 'district') {
+            this.addrDistrictList = res.data || []
+          }
+        } else {
+          if (leve == 'province') {
+            this.addrProvinceList = []
+          } else if (leve == 'city') {
+            this.addrCityList = []
+          } else if (leve == 'district') {
+            this.addrDistrictList = []
+          }
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.resetData()
+      } else {
+        this.selectedRowKeys = this.chooseCust
+        if (this.addrProvinceList.length == 0) {
+          this.getArea('province')
+        }
+        const _this = this
+        setTimeout(() => {
+          _this.$refs.table.refresh(true)
+        }, 200)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseCustomer-modal{
+    .chooseCustomer-con{
+      .btn-con{
+        text-align: center;
+        margin: 30px 0 20px;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 227 - 0
src/views/common/chooseImportModal.vue

@@ -0,0 +1,227 @@
+<template>
+  <a-modal
+    centered
+    class="chooseImport-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="导入"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="900">
+    <div class="chooseImport-con">
+      <!-- 可导入数据 -->
+      <p class="">可导入数据{{ loadData.length }}条</p>
+      <a-table
+        class="sTable"
+        ref="table"
+        size="small"
+        :rowKey="(record) => record.goodsSn"
+        :columns="nowColumns"
+        :dataSource="loadData"
+        :scroll="{ y: 200 }"
+        :pagination="false"
+        bordered>
+      </a-table>
+      <a-divider />
+      <!-- 不可导入数据 -->
+      <p class="red">不可导入数据{{ unLoadData.length }}条</p>
+      <a-table
+        class="unTable"
+        ref="unTable"
+        size="small"
+        :rowKey="(record) => record.goodsCode"
+        :columns="nowUnColumns"
+        :dataSource="unLoadData"
+        :scroll="{ y: 200 }"
+        :pagination="false"
+        bordered>
+      </a-table>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="chooseImport-submit"
+          size="large"
+          :class="loadData.length==0?'button-grey':'button-primary'"
+          @click="handleSubmit"
+          style="padding: 0 60px;">确认导入</a-button>
+        <a-button
+          id="chooseImport-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 60px;margin-left: 15px;">取消</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { promoRuleGoods } from '@/api/promoRule'
+export default {
+  name: 'ChooseImportModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemId: {
+      type: [Number, String],
+      default: ''
+    },
+    paramsData: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  computed: {
+    nowColumns () {
+      let columns = this.columns
+      if ((this.paramsData && this.paramsData.promoRuleType == 'BUY_PROD_GIVE_PROD') || (this.paramsData && this.paramsData.promoRuleType == 'BUY_PROD_GIVE_MONEY')) { //  买产品送产品/买产品送采购额
+        if (this.paramsData && this.paramsData.promoGoodsType == 'NORMAL_PROD') { //  正品
+          columns = this.columns
+        } else if (this.paramsData && this.paramsData.promoGoodsType == 'PROMO_PROD') { //  促销
+          columns = this.promoColumns
+        }
+      } else if (this.paramsData && this.paramsData.promoRuleType == 'PROMO_PROD') { //  特价产品
+        if (this.paramsData && this.paramsData.promoGoodsType == 'PROMO_PROD') { //  促销
+          columns = this.promoSpecialColumns
+        }
+      } else if (this.paramsData && this.paramsData.promoRuleType == 'ADD_PRICE_PURCH') { //  加价换购
+        if (this.paramsData && this.paramsData.promoGoodsType == 'NORMAL_PROD') { //  正品
+          columns = this.columns
+        } else if (this.paramsData && this.paramsData.promoGoodsType == 'PROMO_PROD') { //  促销
+          columns = this.promoSpecialColumns
+        }
+      }
+      return columns
+    },
+    nowUnColumns () {
+      let columns = this.unColumns
+      if ((this.paramsData && this.paramsData.promoRuleType == 'BUY_PROD_GIVE_PROD') || (this.paramsData && this.paramsData.promoRuleType == 'BUY_PROD_GIVE_MONEY')) { //  买产品送产品/买产品送采购额
+        if (this.paramsData && this.paramsData.promoGoodsType == 'NORMAL_PROD') { //  正品
+          columns = this.unColumns
+        } else if (this.paramsData && this.paramsData.promoGoodsType == 'PROMO_PROD') { //  促销
+          columns = this.unPromoColumns
+        }
+      } else if (this.paramsData && this.paramsData.promoRuleType == 'PROMO_PROD') { //  特价产品
+        if (this.paramsData && this.paramsData.promoGoodsType == 'PROMO_PROD') { //  促销
+          columns = this.unPromoSpecialColumns
+        }
+      } else if (this.paramsData && this.paramsData.promoRuleType == 'ADD_PRICE_PURCH') { //  加价换购
+        if (this.paramsData && this.paramsData.promoGoodsType == 'NORMAL_PROD') { //  正品
+          columns = this.unColumns
+        } else if (this.paramsData && this.paramsData.promoGoodsType == 'PROMO_PROD') { //  促销
+          columns = this.unPromoSpecialColumns
+        }
+      }
+      return columns
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      columns: [ //  正品
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '产品编码', dataIndex: 'goodsCode', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '起订量限制', dataIndex: 'orderGoodsUnitDictValue', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '起订数量', dataIndex: 'orderGoodsQty', align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      promoColumns: [ //  促销品
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '产品编码', dataIndex: 'goodsCode', align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      promoSpecialColumns: [ //  特价产品/加价促销品
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '产品编码', dataIndex: 'goodsCode', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: this.paramsData && this.paramsData.promoRuleType == 'PROMO_PROD' ? '特惠单价(¥)' : '换购单价(¥)', dataIndex: 'goodsPrice', width: 200, align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      loadData: [],
+      unColumns: [ //  不可导入产品 正品
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '产品编码', dataIndex: 'goodsCode', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '起订量限制', dataIndex: 'orderGoodsUnitDictValue', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '起订数量', dataIndex: 'orderGoodsQty', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '备注', dataIndex: 'remark', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true }
+      ],
+      unPromoColumns: [ //  不可导入产品 促销品
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '产品编码', dataIndex: 'goodsCode', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '备注', dataIndex: 'remark', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true }
+      ],
+      unPromoSpecialColumns: [ //  不可导入产品 特价产品/加价促销品
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '产品编码', dataIndex: 'goodsCode', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: this.paramsData && this.paramsData.promoRuleType == 'PROMO_PROD' ? '特惠单价(¥)' : '换购单价(¥)', dataIndex: 'goodsPrice', width: 200, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '备注', dataIndex: 'remark', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true }
+      ],
+      unLoadData: []
+    }
+  },
+  methods: {
+    getData () {
+      const _this = this
+      promoRuleGoods(this.paramsData).then(res => {
+        if (res.status == 200) {
+          if (res.data.okGoodsList && res.data.okGoodsList.length > 0) {
+            res.data.okGoodsList.map((item, index) => {
+              item.no = index + 1
+            })
+          }
+          if (res.data.erroGoodsList && res.data.erroGoodsList.length > 0) {
+            res.data.erroGoodsList.map((item, index) => {
+              item.no = index + 1
+            })
+          }
+          _this.loadData = res.data.okGoodsList || []
+          _this.unLoadData = res.data.erroGoodsList || []
+        }
+      })
+    },
+    // 确认导入
+    handleSubmit () {
+      if (this.loadData.length == 0) {
+        this.$message.warning('无可导入产品!')
+      } else {
+        this.$emit('ok', this.loadData)
+        this.isShow = false
+      }
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.loadData = []
+        this.unLoadData = []
+      } else {
+        this.getData()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseImport-modal{
+    .chooseImport-con{
+      .red{
+        color: #f30;
+      }
+      .btn-con{
+        text-align: center;
+        margin: 30px 0 20px;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 424 - 0
src/views/common/chooseProductsModal.vue

@@ -0,0 +1,424 @@
+<template>
+  <a-modal
+    centered
+    class="chooseProducts-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="选择产品"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="900">
+    <div class="products-con">
+      <div>
+        <!-- 搜索条件 -->
+        <div class="table-page-search-wrapper">
+          <a-form-model
+            layout="inline"
+            ref="ruleForm"
+            :model="queryParam"
+            :rules="rules"
+            @keyup.enter.native="getProductList(1)"
+            :label-col="formItemLayout.labelCol"
+            :wrapper-col="formItemLayout.wrapperCol">
+            <a-row :gutter="15">
+              <a-col :md="6" :sm="24">
+                <a-form-model-item label="产品编码" prop="code">
+                  <a-input id="chooseProducts-code" v-model.trim="queryParam.code" allowClear placeholder="请输入产品编码"/>
+                </a-form-model-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-model-item label="产品品牌" :prop="type=='dealership'?'productBrandSn':''">
+                  <a-select
+                    placeholder="请选择产品品牌"
+                    id="chooseProducts-productBrandSn"
+                    allowClear
+                    v-model="queryParam.productBrandSn"
+                    :showSearch="true"
+                    option-filter-prop="children"
+                    :filter-option="filterOption">
+                    <a-select-option v-for="item in productBrandList" :key="item.brandSn" :value="item.brandSn">{{ item.brandName }}</a-select-option>
+                  </a-select>
+                </a-form-model-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-model-item label="产品分类" :prop="type=='dealership'?'productType':''">
+                  <a-cascader
+                    @change="changeProductType"
+                    change-on-select
+                    v-model="queryParam.productType"
+                    expand-trigger="hover"
+                    :options="productTypeList"
+                    :fieldNames="{ label: 'productTypeName', value: 'productTypeSn', children: 'children' }"
+                    id="chooseProducts-productType"
+                    placeholder="请选择产品分类"
+                    allowClear />
+                </a-form-model-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-button style="margin-bottom: 18px;" type="primary" @click="handleSearch" :disabled="disabled" id="chooseProducts-refresh">查询</a-button>
+                <a-button style="margin: 0 0 18px 8px" @click="resetSearchForm" :disabled="disabled" id="chooseProducts-reset">重置</a-button>
+              </a-col>
+            </a-row>
+          </a-form-model></a-form>
+        </div>
+        <p style="font-weight: bold;">当前已选:{{ selectedRowKeys.length }}个</p>
+        <!-- 列表 -->
+        <a-table
+          class="sTable"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.productSn"
+          :row-selection="{
+            selectedRowKeys: selectedRowKeys,
+            onChange: onChange,
+            onSelect: onSelectChange,
+            onSelectAll: onSelectAllChange,
+            getCheckboxProps:record =>({props: {
+              disabled: (this.type == 'supplier') && (this.selectedRowKeys.indexOf(record.productSn) > -1)
+            }})
+          }"
+          :data-source="loadData"
+          :columns="columns"
+          :pagination="paginationProps"
+          :loading="loading"
+          :scroll="{ y: 450 }"
+          bordered>
+        </a-table>
+      </div>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="chooseProducts-save"
+          size="large"
+          class="button-primary"
+          @click="handleSave"
+          style="padding: 0 60px;">保存</a-button>
+        <a-button
+          id="chooseProducts-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 60px;margin-left: 15px;">取消</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { STable } from '@/components'
+import { productBrandQuery } from '@/api/productBrand'
+import { productTypeQuery } from '@/api/productType'
+import { dealerScopeValidProduct } from '@/api/dealerScope'
+import { productPricedList, productPricingList } from '@/api/product'
+export default {
+  name: 'ChooseProductsModal',
+  components: { STable },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    chooseData: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    type: { //  类型,经销权设置dealership,  供应商添加产品supplier
+      type: String,
+      default: ''
+    },
+    dealerSn: {
+      type: String || Number,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      formItemLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 20 }
+      },
+      queryParam: { //  查询条件
+        code: '', //  产品编码
+        productBrandSn: undefined, //  产品品牌
+        productType: [],
+        productTypeSn1: '', //  产品一级分类
+        productTypeSn2: '', //  产品二级分类
+        productTypeSn3: '' //  产品三级分类
+      },
+      rules: {
+        productBrandSn: [ { required: true, message: '请选择产品品牌', trigger: 'change' } ],
+        productType: [ { required: true, message: '请选择产品分类', trigger: 'change' } ]
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      loading: false, //  表格加载中
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '产品编码', dataIndex: 'code', align: 'center' },
+        { title: '产品名称', dataIndex: 'name', align: 'center', ellipsis: true, customRender: function (text) { return text || '--' } }
+      ],
+      loadData: [],
+      pageNo: 1, //  分页页码
+      pageSize: 10, //  分页 每页多少条
+      paginationProps: {
+        showSizeChanger: true, //  是否可以改变 pageSize
+        total: 0, //  分页总条数
+        current: 1,
+        onShowSizeChange: (current, pageSize) => this.changePageSize(current, pageSize),
+        onChange: (current) => this.changePage(current)
+      },
+      productBrandList: [], //  品牌下拉数据
+      productTypeList: [], //  分类下拉数据
+      selectedRowKeys: [],
+      selectedRows: []
+    }
+  },
+  methods: {
+    // 查询
+    handleSearch () {
+      const _this = this
+      _this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          if (_this.type == 'dealership') { //  设置经销权时选择产品
+            // 校验产品是否被包含在品牌分类中
+            const params = []
+            if (_this.queryParam.productBrandSn) {
+              params.push({
+                dealerSn: _this.dealerSn,
+                goodsType: 'BRAND',
+                goodsSn: _this.queryParam.productBrandSn
+              })
+            }
+            if (_this.queryParam.productTypeSn1) {
+              params.push({
+                dealerSn: _this.dealerSn,
+                goodsType: 'CATEGORY',
+                goodsSn: _this.queryParam.productTypeSn1
+              })
+            }
+            if (_this.queryParam.productTypeSn2) {
+              params.push({
+                dealerSn: _this.dealerSn,
+                goodsType: 'CATEGORY',
+                goodsSn: _this.queryParam.productTypeSn2
+              })
+            }
+            if (_this.queryParam.productTypeSn3) {
+              params.push({
+                dealerSn: _this.dealerSn,
+                goodsType: 'CATEGORY',
+                goodsSn: _this.queryParam.productTypeSn3
+              })
+            }
+            dealerScopeValidProduct(params).then(res => {
+              if (res.status == 200) {
+                _this.getProductList(1)
+              }
+            })
+          } else {
+            _this.getProductList(1)
+          }
+        } else {
+          return false
+        }
+      })
+    },
+    // 重置数据
+    resetData () {
+      this.queryParam.code = ''
+      this.queryParam.productBrandSn = undefined
+      this.queryParam.productTypeSn1 = ''
+      this.queryParam.productTypeSn2 = ''
+      this.queryParam.productTypeSn3 = ''
+      this.queryParam.productType = []
+      this.pageNo = 1
+      this.pageSize = 10
+      this.paginationProps.total = 0
+      this.paginationProps.current = 1
+    },
+    //  重置
+    resetSearchForm () {
+      this.resetData()
+      this.loadData = []
+      this.disabled = false
+    },
+    // 保存
+    handleSave () {
+      const _this = this
+      if (this.selectedRowKeys.length < 1) {
+        this.$message.warning('请在列表勾选后再进行操作!')
+        return
+      }
+      if (this.type == 'supplier') { //  供应商增加产品
+        const arr = []
+        this.selectedRowKeys.map(item => {
+          if (_this.chooseData.indexOf(item) == -1) {
+            arr.push(item)
+          }
+        })
+        this.$emit('ok', arr)
+      } else {
+        this.$emit('ok', this.selectedRows)
+      }
+      this.isShow = false
+    },
+    onChange (selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys
+    },
+    onSelectChange (record, selected, selectedRows, nativeEvent) {
+      const _this = this
+      if (this.type != 'supplier') { //  供应商增加产品
+        if (selected) { //  选择
+          this.selectedRows.push(record)
+        } else { //  取消
+          this.selectedRows.map((item, index) => {
+            if (item.productSn == record.productSn) {
+              _this.selectedRows.splice(index, 1)
+            }
+          })
+        }
+      }
+    },
+    // 本页全选/取消全选
+    onSelectAllChange (selected, selectedRows, changeRows) {
+      const _this = this
+      if (this.type != 'supplier') { //  供应商增加产品
+        if (selected) { //  选择
+          this.selectedRows = [...this.selectedRows, ...changeRows]
+        } else { //  取消
+          this.selectedRows.map((item, index) => {
+            this.selectedRows.map((subItem, ind) => {
+              if (item.productSn == subItem.productSn) {
+                _this.selectedRows.splice(index, 1)
+              }
+            })
+          })
+        }
+      }
+    },
+    // 产品列表
+    getProductList (pageNo) {
+      this.pageNo = pageNo || this.pageNo
+      this.disabled = true
+      const params = {
+        pageNo: this.pageNo,
+        pageSize: this.pageSize
+      }
+      this.loading = true
+      let url = productPricedList //  获取定过价的产品
+      if (this.type == 'supplier') { //  供应商增加产品
+        url = productPricingList //  获取定价产品
+      }
+      url(Object.assign(params, this.queryParam)).then(res => {
+        this.loading = false
+        if (res.status == 200) {
+          const data = res.data
+          this.paginationProps.total = Number(res.data.count) || 0
+          this.paginationProps.current = data.pageNo
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.loadData = data.list
+          this.disabled = false
+        } else {
+          this.paginationProps.total = 0
+          this.paginationProps.current = 1
+          this.loadData = []
+        }
+      })
+    },
+    //  已选产品 分页  一页多少条change
+    changePageSize (current, pageSize) {
+      this.pageNo = current
+      this.pageSize = pageSize
+      this.getProductList()
+    },
+    //  已选产品 分页 页码change
+    changePage (current) {
+      this.pageNo = current
+      this.getProductList()
+    },
+    //  产品分类  change
+    changeProductType (val, opt) {
+      this.queryParam.productTypeSn1 = val[0] ? val[0] : ''
+      this.queryParam.productTypeSn2 = val[1] ? val[1] : ''
+      this.queryParam.productTypeSn3 = val[2] ? val[2] : ''
+    },
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    },
+    //  产品品牌  列表
+    getProductBrand () {
+      productBrandQuery({}).then(res => {
+        if (res.status == 200) {
+          this.productBrandList = res.data
+        } else {
+          this.productBrandList = []
+        }
+      })
+    },
+    //  产品分类  列表
+    getProductType () {
+      productTypeQuery({}).then(res => {
+        if (res.status == 200) {
+          this.productTypeList = res.data
+        } else {
+          this.productTypeList = []
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.loadData = []
+        this.disabled = false
+        this.resetData()
+      } else {
+        if (this.type == 'supplier') { //  供应商增加产品
+          this.selectedRows = []
+          this.selectedRowKeys = this.chooseData
+        } else {
+          this.selectedRows = this.chooseData
+          this.selectedRowKeys = []
+          this.chooseData.map(item => {
+            this.selectedRowKeys.push(item.goodsSn)
+          })
+        }
+        if (this.productBrandList.length == 0) {
+          this.getProductBrand()
+        }
+        if (this.productTypeList.length == 0) {
+          this.getProductType()
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseProducts-modal{
+    .products-con{
+      .btn-con{
+        text-align: center;
+        margin: 30px 0 20px;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 280 - 0
src/views/common/chooseSupplierModal.vue

@@ -0,0 +1,280 @@
+<template>
+  <a-modal
+    centered
+    class="chooseSupplier-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="选择供应商"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="900">
+    <div class="products-con">
+      <div>
+        <!-- 搜索条件 -->
+        <div class="table-page-search-wrapper">
+          <a-form-model
+            layout="inline"
+            ref="ruleForm"
+            :model="queryParam"
+            :rules="rules"
+            @keyup.enter.native="getSupplierList(1)"
+            :label-col="formItemLayout.labelCol"
+            :wrapper-col="formItemLayout.wrapperCol">
+            <a-row :gutter="15">
+              <a-col :md="6" :sm="24">
+                <a-form-model-item label="供应商名称">
+                  <a-input id="chooseSupplier-supplierName" v-model.trim="queryParam.supplierName" allowClear placeholder="请输入供应商名称"/>
+                </a-form-model-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-model-item label="状态">
+                  <v-select code="ENABLE_FLAG" id="chooseSupplier-enabledFlag" v-model="queryParam.enabledFlag" allowClear placeholder="请选择状态"></v-select>
+                </a-form-model-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-button style="margin-bottom: 18px;" type="primary" @click="handleSearch" :disabled="disabled" id="chooseSupplier-refresh">查询</a-button>
+                <a-button style="margin: 0 0 18px 8px" @click="resetSearchForm" :disabled="disabled" id="chooseSupplier-reset">重置</a-button>
+              </a-col>
+            </a-row>
+          </a-form-model></a-form>
+        </div>
+        <p style="font-weight: bold;">当前已选:{{ selectedRowKeys.length }}个</p>
+        <!-- 列表 -->
+        <a-table
+          class="sTable"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.supplierSn"
+          :row-selection="{
+            selectedRowKeys: selectedRowKeys,
+            onChange: onChange,
+            onSelect: onSelectChange,
+            onSelectAll: onSelectAllChange
+          }"
+          :data-source="loadData"
+          :columns="columns"
+          :pagination="paginationProps"
+          :loading="loading"
+          :scroll="{ y: 450 }"
+          bordered>
+        </a-table>
+      </div>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="chooseSupplier-save"
+          size="large"
+          class="button-primary"
+          @click="handleSave"
+          style="padding: 0 60px;">保存</a-button>
+        <a-button
+          id="chooseSupplier-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 60px;margin-left: 15px;">取消</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import { supplierList } from '@/api/supplier'
+export default {
+  name: 'ChooseSupplierModal',
+  components: { STable, VSelect },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    chooseData: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    dealerSn: {
+      type: String || Number,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      formItemLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 20 }
+      },
+      queryParam: { //  查询条件
+        supplierName: '',
+        enabledFlag: undefined
+      },
+      rules: {},
+      disabled: false, //  查询、重置按钮是否可操作
+      loading: false, //  表格加载中
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '供应商名称', dataIndex: 'supplierName', align: 'center', ellipsis: true, customRender: function (text) { return text || '--' } },
+        { title: '状态', dataIndex: 'enableFlagDictValue', align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      loadData: [],
+      pageNo: 1, //  分页页码
+      pageSize: 10, //  分页 每页多少条
+      paginationProps: {
+        showSizeChanger: true, //  是否可以改变 pageSize
+        total: 0, //  分页总条数
+        current: 1,
+        onShowSizeChange: (current, pageSize) => this.changePageSize(current, pageSize),
+        onChange: (current) => this.changePage(current)
+      },
+      selectedRowKeys: [],
+      selectedRows: []
+    }
+  },
+  methods: {
+    // 查询
+    handleSearch () {
+      const _this = this
+      _this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          _this.getSupplierList(1)
+        } else {
+          return false
+        }
+      })
+    },
+    // 重置数据
+    resetData () {
+      this.queryParam.supplierName = ''
+      this.queryParam.enabledFlag = undefined
+      this.pageNo = 1
+      this.pageSize = 10
+      this.paginationProps.total = 0
+      this.paginationProps.current = 1
+    },
+    //  重置
+    resetSearchForm () {
+      this.resetData()
+      this.loadData = []
+      this.disabled = false
+    },
+    // 保存
+    handleSave () {
+      if (this.selectedRowKeys.length < 1) {
+        this.$message.warning('请在列表勾选后再进行操作!')
+        return
+      }
+      this.$emit('ok', this.selectedRows)
+      this.isShow = false
+    },
+    onChange (selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys
+    },
+    onSelectChange (record, selected, selectedRows, nativeEvent) {
+      const _this = this
+      if (selected) { //  选择
+        this.selectedRows.push(record)
+      } else { //  取消
+        this.selectedRows.map((item, index) => {
+          if (item.supplierSn == record.supplierSn) {
+            _this.selectedRows.splice(index, 1)
+          }
+        })
+      }
+    },
+    // 本页全选/取消全选
+    onSelectAllChange (selected, selectedRows, changeRows) {
+      const _this = this
+      if (selected) { //  选择
+        this.selectedRows = [...this.selectedRows, ...changeRows]
+      } else { //  取消
+        this.selectedRows.map((item, index) => {
+          this.selectedRows.map((subItem, ind) => {
+            if (item.supplierSn == subItem.supplierSn) {
+              _this.selectedRows.splice(index, 1)
+            }
+          })
+        })
+      }
+    },
+    // 供应商列表
+    getSupplierList (pageNo) {
+      this.pageNo = pageNo || this.pageNo
+      this.disabled = true
+      const params = {
+        pageNo: this.pageNo,
+        pageSize: this.pageSize
+      }
+      this.loading = true
+      supplierList(Object.assign(params, this.queryParam)).then(res => {
+        this.loading = false
+        if (res.status == 200) {
+          const data = res.data
+          this.paginationProps.total = Number(res.data.count) || 0
+          this.paginationProps.current = data.pageNo
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.loadData = data.list
+          this.disabled = false
+        } else {
+          this.paginationProps.total = 0
+          this.paginationProps.current = 1
+          this.loadData = []
+        }
+      })
+    },
+    //  已选产品 分页  一页多少条change
+    changePageSize (current, pageSize) {
+      this.pageNo = current
+      this.pageSize = pageSize
+      this.getSupplierList()
+    },
+    //  已选产品 分页 页码change
+    changePage (current) {
+      this.pageNo = current
+      this.getSupplierList()
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.loadData = []
+        this.disabled = false
+        this.resetData()
+      } else {
+        this.getSupplierList(1)
+        this.selectedRows = this.chooseData
+        this.selectedRowKeys = []
+        this.chooseData.map(item => {
+          this.selectedRowKeys.push(item.rangeDataSn)
+        })
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseSupplier-modal{
+    .products-con{
+      .btn-con{
+        text-align: center;
+        margin: 30px 0 20px;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 168 - 0
src/views/common/chooseTypeModal.vue

@@ -0,0 +1,168 @@
+<template>
+  <a-modal
+    centered
+    class="chooseType-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="选择产品分类"
+    v-model="isShow"
+    @cancle="isShow=false"
+    width="50%">
+    <div class="chooseType-con">
+      <div>
+        <a-checkbox :checked="checkAll" @change="onCheckAllChange">全选</a-checkbox>
+      </div>
+      <a-divider />
+      <a-tree
+        style="height: 400px;overflow-y: scroll;"
+        checkable
+        @check="onCheck"
+        :checkStrictly="true"
+        v-model="checkedKeys"
+        :treeData="productTypeList"
+        :replaceFields="replaceFields"
+      />
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="chooseType-submit"
+          size="large"
+          class="button-primary"
+          @click="handleSave"
+          style="padding: 0 60px;">保存</a-button>
+        <a-button
+          id="chooseType-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 60px;margin-left: 15px;">取消</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { productTypeQuery } from '@/api/productType'
+export default {
+  name: 'ChooseTypeModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    chooseData: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      checkedKeys: [], //  选中项
+      checkedRows: [], //  选中项  整条数据
+      checkAll: false, //  全选
+      indeterminate: true,
+      replaceFields: {
+        children: 'children',
+        title: 'productTypeName',
+        key: 'productTypeSn'
+      },
+      productTypeList: []
+    }
+  },
+  methods: {
+    //  产品分类  列表
+    getProductType () {
+      productTypeQuery({}).then(res => {
+        if (res.status == 200) {
+          this.productTypeList = res.data
+        } else {
+          this.productTypeList = []
+        }
+      })
+    },
+    // 保存
+    handleSave () {
+      if (this.checkedKeys.length < 1) {
+        this.$message.warning('请在列表勾选后再进行操作!')
+        return
+      }
+      this.$emit('ok', this.checkedRows)
+      this.isShow = false
+    },
+    // 全选
+    onCheckAllChange (e) {
+      this.checkAll = e.target.checked
+      if (e.target.checked) {
+        this.checkedKeys = []
+        this.checkedRows = []
+        this.recursionFun(this.productTypeList)
+      } else {
+        this.checkedKeys = []
+        this.checkedRows = []
+      }
+    },
+    //  递归函数
+    recursionFun (data) {
+      if (data) {
+        data.map((item, index) => {
+          this.checkedKeys.push(item.productTypeSn)
+          this.checkedRows.push(item)
+          if (item.children && item.children.length > 0) {
+            this.recursionFun(item.children)
+          }
+        })
+      }
+    },
+    onCheck (checkedKeys, info) {
+      // console.log('onCheck', checkedKeys, info)
+      // this.checkedData = [...checkedKeys, ...info.halfCheckedKeys]
+      this.checkedKeys = checkedKeys
+      this.checkedRows = []
+      info.checkedNodes.map((item, index) => {
+        this.checkedRows.push(item.data.props)
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.checkAll = false
+      } else {
+        const _this = this
+        this.checkedRows = this.chooseData
+        this.checkedKeys = []
+        this.chooseData.map(item => {
+          _this.checkedKeys.push(item.goodsSn)
+        })
+        if (this.productTypeList.length == 0) {
+          this.getProductType()
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseType-modal{
+    .chooseType-con{
+      .btn-con{
+        text-align: center;
+        margin: 30px 0 20px;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 70 - 0
src/views/common/custList.vue

@@ -0,0 +1,70 @@
+<template>
+  <a-select
+    show-search
+    label-in-value
+    :value="dealerName"
+    placeholder="请输入名称搜索"
+    style="width: 100%"
+    :filter-option="false"
+    :not-found-content="fetching ? undefined : null"
+    @search="fetchUser"
+    @change="handleChange"
+    allowClear
+  >
+    <a-spin v-if="fetching" slot="notFoundContent" size="small" />
+    <a-select-option v-for="item in data" :key="item.dealerSn" :value="item.dealerSn">
+      {{ item.dealerName }}
+    </a-select-option>
+  </a-select>
+</template>
+<script>
+import debounce from 'lodash/debounce'
+import { dealerQueryList, dealerFindUpdateInfoBySn } from '@/api/dealer'
+export default {
+  props: {
+  },
+  data () {
+    this.lastFetchId = 0
+    this.fetchUser = debounce(this.fetchUser, 800)
+    return {
+      data: [],
+      dealerName: [],
+      fetching: false
+    }
+  },
+  methods: {
+    fetchUser (dealerName) {
+      console.log('fetching user', dealerName)
+      if (dealerName == '') return
+      this.lastFetchId += 1
+      const fetchId = this.lastFetchId
+      this.data = []
+      this.fetching = true
+      dealerQueryList({ 'nameLike': dealerName, pageNo: 1, pageSize: 20 }).then(res => {
+        if (fetchId !== this.lastFetchId) {
+          return
+        }
+        this.data = res.data.list || []
+        this.fetching = false
+      })
+    },
+    handleChange (value) {
+      Object.assign(this, {
+        dealerName: value,
+        data: [],
+        fetching: false
+      })
+      this.$emit('change', value || { key: undefined })
+    },
+    resetForm () {
+      this.dealerName = []
+    },
+    // 查询详细
+    getDetail (sn) {
+      dealerFindUpdateInfoBySn({ sn: sn }).then(res => {
+        this.$emit('dealerDetail', res.data || null)
+      })
+    }
+  }
+}
+</script>

+ 30 - 5
src/views/common/editInput.js

@@ -1,11 +1,14 @@
 const EditableCell = {
   template: `
-      <div style="display:flex;align-items: center;">
+      <div style="display:flex;align-items: center;justify-content: center;">
+        <span>
+        {{punit}} 
+        </span>
         <div class="editable-cell-input-wrapper">
           <a-input-number 
-          size="small" 
-          :min="0.1" 
-          :max="100000" 
+          :size="size"
+          :min="min" 
+          :max="max" 
           :value="value" 
           :precision="precision"
           :step="step"
@@ -15,7 +18,8 @@ const EditableCell = {
         <a-icon
           type="check"
           slot="suffix"
-          :style="{color: editable?'#08c':'#666', marginLeft: '10px' }"
+          :title="editable?'保存':''"
+          :style="{color: editable?'#08c':'#666', marginLeft: '5px' }"
           @click="check"
         />
       </div>
@@ -29,6 +33,22 @@ const EditableCell = {
     step: {
       type: [Number],
       default: 1
+    },
+    min: {
+      type: [Number],
+      default: 0
+    },
+    max: {
+      type: [Number],
+      default: 999999
+    },
+    size: {
+      type: String,
+      default: 'default'
+    },
+    punit: {
+      type: String,
+      default: ''
     }
   },
   data() {
@@ -37,6 +57,11 @@ const EditableCell = {
       editable: false,
     };
   },
+  watch:{
+    text(newVal,oldVal){
+      this.value = newVal
+    }
+  },
   methods: {
     handleChange(value) {
       this.value = value;

+ 216 - 0
src/views/common/importGuideModal.vue

@@ -0,0 +1,216 @@
+<template>
+  <a-modal
+    centered
+    class="importGuide-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="导入"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="750">
+    <div class="importGuide-con">
+      <div class="explain-con">
+        <div class="explain-item">
+          <div class="explain-tit">
+            <span>1</span>准备导入
+          </div>
+          <p>所有允许导入的数据字段请参考模板,数据字段不符合规则,整条不予以导入。</p>
+          <ul>
+            <li>1) “产品编码”字段为必填项。</li>
+            <li>2) “起订量限制“为选项,只可选择”按整箱‘或者“按设置数量”,选择“按设置数量”时,“起订数量”为必填项。</li>
+          </ul>
+          <a :href="filePath" style="padding: 5px 0 0 23px;display: block;">
+            <a-icon type="download" style="padding-right: 5px;" />下载导入模板
+          </a>
+        </div>
+        <div class="explain-item">
+          <div class="explain-tit">
+            <span>2</span>上传数据文件
+          </div>
+          <p>目前支持的文件类型*.xls,*.xlsx.</p>
+          <p>
+            <Upload
+              id="importGuide-attachList"
+              ref="importUpload"
+              :maxNums="1"
+              fileType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel"
+              uploadType="import"
+              :action="attachAction"
+              :uploadParams="uploadParams"
+              upText="添加文件"
+              @change="changeImport"></Upload>
+          </p>
+        </div>
+      </div>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="importGuide-nextStep"
+          size="large"
+          class="button-primary"
+          @click="handlerNextStep"
+          style="padding: 0 60px;">下一步</a-button>
+        <a-button
+          id="importGuide-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 60px;margin-left: 15px;">取消</a-button>
+      </div>
+    </div>
+    <!-- 导入 -->
+    <chooseImportModal :openModal="openImportModal" :paramsData="paramsData" @close="handleClose" @ok="hanldeOk" />
+  </a-modal>
+</template>
+
+<script>
+import ChooseImportModal from '@/views/common/chooseImportModal.vue'
+import { Upload } from '@/components'
+export default {
+  name: 'ImportGuideModal',
+  components: { ChooseImportModal, Upload },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    params: {
+      type: Object,
+      default: null
+    },
+    type: { //  类型,促销promo
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      openImportModal: false, //  导入
+      attachAction: process.env.VUE_APP_API_BASE_URL + '/upload',
+      paramsData: null,
+      uploadParams: {
+        savePathType: 'local'
+      },
+      downUrlN: 'http://jg-ocs.oss-cn-beijing.aliyuncs.com/templ/promo/normal_product_templ.xlsx', //  正价品
+      downUrlP: 'http://jg-ocs.oss-cn-beijing.aliyuncs.com/templ/promo/promo_product_templ.xlsx', //  促销品
+      downUrlT: 'http://jg-ocs.oss-cn-beijing.aliyuncs.com/templ/promo/special_offer_templ.xlsx', //  特惠品
+      downUrlA: 'http://jg-ocs.oss-cn-beijing.aliyuncs.com/templ/promo/exchange_price_templ.xlsx' //  换购品
+    }
+  },
+  computed: {
+    filePath () {
+      let columns = this.downUrlN
+      if ((this.params && this.params.promoRuleType == 'BUY_PROD_GIVE_PROD') || (this.params && this.params.promoRuleType == 'BUY_PROD_GIVE_MONEY')) { //  买产品送产品/买产品送采购额
+        if (this.params && this.params.promoGoodsType == 'NORMAL_PROD') { //  正品
+          columns = this.downUrlN
+        } else if (this.params && this.params.promoGoodsType == 'PROMO_PROD') { //  促销
+          columns = this.downUrlP
+        }
+      } else if (this.params && this.params.promoRuleType == 'PROMO_PROD') { //  特价产品
+        if (this.params && this.params.promoGoodsType == 'PROMO_PROD') { //  促销
+          columns = this.downUrlT
+        }
+      } else if (this.params && this.params.promoRuleType == 'ADD_PRICE_PURCH') { //  加价换购
+        if (this.params && this.params.promoGoodsType == 'NORMAL_PROD') { //  正品
+          columns = this.downUrlN
+        } else if (this.params && this.params.promoGoodsType == 'PROMO_PROD') { //  促销
+          columns = this.downUrlA
+        }
+      }
+      return columns
+    }
+  },
+  methods: {
+    // 下一步
+    handlerNextStep () {
+      if (this.paramsData) {
+        this.openImportModal = true
+      } else {
+        this.$message.warning('添加文件后再进行下一步操作!')
+      }
+    },
+    // 上传文件  change
+    changeImport (file) {
+      if (file) {
+        this.paramsData = {
+          promoRuleType: this.params.promoRuleType || '',
+          promoGoodsType: this.params.promoGoodsType || '',
+          path: file
+        }
+      }
+    },
+    // 导入
+    hanldeOk (obj) {
+      if (obj && obj.length > 0) {
+        this.$emit('ok', obj)
+        this.isShow = false
+      }
+    },
+    // 关闭
+    handleClose () {
+      this.openImportModal = false
+      this.isShow = false
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.paramsData = null
+        this.$refs.importUpload.setFileList('')
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .importGuide-modal{
+    .importGuide-con{
+      .explain-con{
+        .explain-item{
+          margin-bottom: 10px;
+          .explain-tit{
+            font-weight: bold;
+            span{
+              display: inline-block;
+              width: 18px;
+              height: 18px;
+              line-height: 16px;
+              text-align: center;
+              margin-right: 5px;
+              border-radius: 50%;
+              border: 1px solid rgba(0, 0, 0, 0.3);
+            }
+          }
+          p{
+            margin: 8px 0;
+            padding-left: 23px;
+          }
+          ul{
+            list-style: none;
+            padding: 0;
+            padding-left: 23px;
+            margin: 0;
+            li{
+              line-height: 26px;
+            }
+          }
+        }
+      }
+      .btn-con{
+        margin: 60px 0 20px;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 68 - 0
src/views/common/productBrand.js

@@ -0,0 +1,68 @@
+import { productBrandQuery } from '@/api/productBrand'
+const ProductBrand = {
+  template: `
+      <a-select
+        placeholder="请选择产品品牌"
+        :id="id"
+        allowClear
+        :value="defaultVal"
+        :showSearch="true"
+        @change="handleChange"
+        option-filter-prop="children"
+        :filter-option="filterOption">
+        <a-select-option v-for="item in productBrandList" :key="item.brandSn" :value="item.brandSn">{{ item.brandName }}</a-select-option>
+      </a-select>
+    `,
+  props: {
+    value: {
+      type: String,
+      defatut: ''
+    },
+    id: {
+      type: String,
+      default: ''
+    },
+    sysFlag: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      defaultVal: this.value,
+      productBrandList: []
+    };
+  },
+  mounted() {
+    this.getProductBrand()
+  },
+  watch: {
+    value(newValue, oldValue) {
+      this.defaultVal = newValue
+    }
+  },
+  methods: {
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    },
+    handleChange(value) {
+      this.defaultVal = value;
+      this.$emit('change', value);
+      this.$emit('input', value);
+    },
+    //  产品品牌列表, sysFlag: 1 箭冠 0 自建
+    getProductBrand () {
+      productBrandQuery({ 'sysFlag': this.sysFlag }).then(res => {
+        if (res.status == 200) {
+          this.productBrandList = res.data
+        } else {
+          this.productBrandList = []
+        }
+      })
+    },
+  },
+};
+
+export default ProductBrand

+ 60 - 0
src/views/common/productType.js

@@ -0,0 +1,60 @@
+import { productTypeQuery } from '@/api/productType'
+const ProductType = {
+  template: `
+      <a-cascader
+        @change="handleChange"
+        change-on-select
+        :value="defaultVal"
+		expand-trigger="hover"
+        :options="productTypeList"
+        :fieldNames="{ label: 'productTypeName', value: 'productTypeSn', children: 'children' }"
+        :id="id"
+        placeholder="请选择产品分类"
+        allowClear />
+    `,
+  props: {
+    value: {
+      type: Array,
+      defatut: function(){
+        return []
+      }
+    },
+    id: {
+      type: String,
+      default: ''
+    },
+  },
+  data() {
+    return {
+      defaultVal: this.value,
+      productTypeList: []
+    };
+  },
+  watch: {
+    value(newValue, oldValue) {
+      this.defaultVal = newValue
+    }
+  },
+  mounted() {
+    this.getProductType()
+  },
+  methods: {
+    handleChange(value) {
+      this.defaultVal = value;
+      this.$emit('change', this.defaultVal);
+      this.$emit('input', this.defaultVal);
+    },
+    //  产品分类列表
+    getProductType () {
+      productTypeQuery({}).then(res => {
+        if (res.status == 200) {
+          this.productTypeList = res.data
+        } else {
+          this.productTypeList = []
+        }
+      })
+    }
+  },
+};
+
+export default ProductType

+ 64 - 0
src/views/common/promoList.vue

@@ -0,0 +1,64 @@
+<template>
+  <a-select
+    show-search
+    label-in-value
+    :value="name"
+    placeholder="请输入名称搜索"
+    style="width: 100%"
+    :filter-option="false"
+    :not-found-content="fetching ? undefined : null"
+    @search="fetchUser"
+    @change="handleChange"
+    allowClear
+  >
+    <a-spin v-if="fetching" slot="notFoundContent" size="small" />
+    <a-select-option v-for="item in data" :key="item.promoActiveSn" :value="item.promoActiveSn">
+      {{ item.name }}
+    </a-select-option>
+  </a-select>
+</template>
+<script>
+import debounce from 'lodash/debounce'
+import { promoActiveList } from '@/api/promoActive'
+export default {
+  props: {
+  },
+  data () {
+    this.lastFetchId = 0
+    this.fetchUser = debounce(this.fetchUser, 800)
+    return {
+      data: [],
+      name: [],
+      fetching: false
+    }
+  },
+  methods: {
+    fetchUser (name) {
+      console.log('fetching user', name)
+      if (name == '') return
+      this.lastFetchId += 1
+      const fetchId = this.lastFetchId
+      this.data = []
+      this.fetching = true
+      promoActiveList({ 'name': name, pageNo: 1, pageSize: 20 }).then(res => {
+        if (fetchId !== this.lastFetchId) {
+          return
+        }
+        this.data = res.data.list || []
+        this.fetching = false
+      })
+    },
+    handleChange (value) {
+      Object.assign(this, {
+        name: value,
+        data: [],
+        fetching: false
+      })
+      this.$emit('change', value || { key: undefined })
+    },
+    resetForm () {
+      this.name = []
+    }
+  }
+}
+</script>

+ 61 - 0
src/views/common/rangeDate.vue

@@ -0,0 +1,61 @@
+<template>
+  <a-range-picker
+    style="width:100%"
+    :value="date"
+    :disabledDate="disabledDate"
+    :format="dateFormat"
+    @change="dateChange"
+    @calendarChange="dateCalendarChange"
+    :placeholder="['开始时间', '结束时间']" />
+</template>
+<script>
+import moment from 'moment'
+export default {
+  props: {
+    value: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data () {
+    return {
+      date: this.value,
+      dateFormat: 'YYYY-MM-DD',
+      selectPriceDate: ''
+    }
+  },
+  methods: {
+    // 不可选日期
+    disabledDate (current) {
+      //  最早可倒推选择两年数据,最晚为今天
+      const minYearVs = moment().subtract(2, 'years') //  两年前   负值
+      const maxYearVs = moment().endOf('day') //  今天,包含今天
+      //  限制最多只能查一年区间的数据
+      if (this.selectPriceDate) {
+        const oMinYearVs = moment(this.selectPriceDate, 'YYYY-MM-DD').subtract(1, 'years') //  当前选中开始日期前推一年
+        const oMaxYearVs = moment(this.selectPriceDate, 'YYYY-MM-DD').add(1, 'years') //  当前选中开始日期后推一年
+        // 判断两个时间段是否相差m天  第二个参数指相差单位,第三个参数指是否返回浮点形式(小数)
+        const beginDate = minYearVs.diff(oMinYearVs, 'days') > 0 ? minYearVs : oMinYearVs // 若当前选中开始日期前推一年超出最多倒推两年数据时,则以两年为标准
+        const endDate = maxYearVs.diff(oMaxYearVs, 'days') > 0 ? oMaxYearVs : maxYearVs // 若当前选中开始日期后推一年超出今天时,则以今天为标准
+        return current && current < beginDate || current && current > endDate
+      } else {
+        return current && current > maxYearVs || current && current < minYearVs
+      }
+    },
+    // 日期  change
+    dateChange (date, dateStrings) {
+      this.selectPriceDate = ''
+      this.date = date
+      this.$emit('change', dateStrings)
+    },
+    dateCalendarChange (date, dateStrings) {
+      this.selectPriceDate = date[0]
+    },
+    resetDate (val) {
+      this.date = val || []
+    }
+  }
+}
+</script>

+ 70 - 0
src/views/common/settleStyle.js

@@ -0,0 +1,70 @@
+import { settleStyleQueryAll } from '@/api/settleStyle'
+const CustList = {
+  template: `
+        <a-select
+          :id="id"
+          placeholder="请选择收款方式"
+          allowClear
+          :value="defaultVal"
+          :showSearch="true"
+          @change="handleChange"
+          :filter-option="filterOption">
+          <a-select-option v-for="item in list" :key="item[defValKey]" :value="item[defValKey]">{{ item.name }}</a-select-option>
+        </a-select>
+    `,
+  props: {
+    value: {
+      type: String,
+      defatut: ''
+    },
+    id: {
+      type: String,
+      default: ''
+    },
+    defValKey: {
+      type: String,
+      default: 'settleStyleSn'
+    }
+  },
+  data() {
+    return {
+      defaultVal: this.value,
+      list: []
+    };
+  },
+  watch: {
+    value(newValue, oldValue) {
+      console.log(newValue)
+      this.defaultVal = newValue
+    }
+  },
+  mounted() {
+    this.getList()
+  },
+  methods: {
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    },
+    handleChange(value) {
+      console.log(value)
+      this.defaultVal = value;
+      this.$emit('change', this.value);
+      this.$emit('input', value);
+    },
+    // 列表数据
+    getList () {
+      const _this = this
+      settleStyleQueryAll().then(res => {
+        if (res.status == 200) {
+          _this.list = res.data || []
+        } else {
+          _this.list = []
+        }
+      })
+    },
+  },
+};
+
+export default CustList

+ 70 - 0
src/views/common/subarea.js

@@ -0,0 +1,70 @@
+import { subareaQueryAll } from '@/api/subarea'
+const Subarea = {
+  template: `
+        <a-select
+          :id="id"
+          placeholder="请选择分区"
+          allowClear
+          :value="defaultVal"
+          :showSearch="true"
+          @change="handleChange"
+          :filter-option="filterOption">
+          <a-select-option v-for="item in list" :key="item[defValKey]" :value="item[defValKey]">{{ item.subareaName }}</a-select-option>
+        </a-select>
+    `,
+  props: {
+    value: {
+      type: String,
+      defatut: ''
+    },
+    id: {
+      type: String,
+      default: ''
+    },
+    defValKey: {
+      type: String,
+      default: 'subareaSn'
+    }
+  },
+  data() {
+    return {
+      defaultVal: this.value,
+      list: []
+    };
+  },
+  watch: {
+    value(newValue, oldValue) {
+      console.log(newValue)
+      this.defaultVal = newValue
+    }
+  },
+  mounted() {
+    this.getList()
+  },
+  methods: {
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    },
+    handleChange(value) {
+      console.log(value)
+      this.defaultVal = value;
+      this.$emit('change', this.value);
+      this.$emit('input', value);
+    },
+    // 列表数据
+    getList () {
+      const _this = this
+      subareaQueryAll().then(res => {
+        if (res.status == 200) {
+          _this.list = res.data || []
+        } else {
+          _this.list = []
+        }
+      })
+    },
+  },
+};
+
+export default Subarea

+ 89 - 0
src/views/dealerManagement/dealerAccountManagement/detailModal.vue

@@ -0,0 +1,89 @@
+<template>
+  <a-modal
+    centered
+    class="dealerAccountDetail-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="详情"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="800">
+    <div v-if="detailData">
+      <a-descriptions bordered size="small" :column="2">
+        <a-descriptions-item label="经销商名称:">{{ (detailData.org&&detailData.org.name) || '--' }}</a-descriptions-item>
+        <a-descriptions-item label="管理员姓名:">{{ detailData.name || '--' }}</a-descriptions-item>
+        <a-descriptions-item label="管理员手机:">{{ detailData.phone || '--' }}</a-descriptions-item>
+        <a-descriptions-item label="管理员账号:">{{ detailData.loginName || '--' }}</a-descriptions-item>
+        <a-descriptions-item label="最大可开通用户数(含管理员账号):">{{ (detailData.org&&detailData.org.childUserMaxNum) || '--' }}</a-descriptions-item>
+      </a-descriptions>
+      <div class="btn-cont"><a-button id="dealerAccountDetail-modal-back" @click="isShow = false">关闭</a-button></div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { dealerUserDetail } from '@/api/dealer'
+export default {
+  name: 'DealerAccountDetailModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemId: {
+      type: [Number, String],
+      default: ''
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      detailData: null //  详情数据
+    }
+  },
+  methods: {
+    //  获取详情
+    getDetail () {
+      dealerUserDetail({ id: this.itemId }).then(res => {
+        if (res.status == 200) {
+          this.detailData = res.data
+        } else {
+          this.detailData = null
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+      }
+    },
+    itemId (newValue, oldValue) {
+      if (this.isShow && newValue) {
+        this.getDetail()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .dealerAccountDetail-modal{
+    .ant-modal-body {
+      padding: 40px 40px 24px;
+    }
+    .ant-descriptions-item-label.ant-descriptions-item-colon{
+      width: 133px;
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>

+ 213 - 0
src/views/dealerManagement/dealerAccountManagement/editModal.vue

@@ -0,0 +1,213 @@
+<template>
+  <a-modal
+    centered
+    class="dealerAccountEdit-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="账号信息"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="800">
+    <!-- 表单 -->
+    <div>
+      <a-spin :spinning="spinning" tip="Loading...">
+        <a-form-model
+          id="dealerAccountEdit-form"
+          ref="ruleForm"
+          :model="form"
+          :rules="rules"
+          :label-col="formItemLayout.labelCol"
+          :wrapper-col="formItemLayout.wrapperCol"
+          >
+          <a-form-model-item label="经销商名称" prop="tenantSn">
+            <custList ref="custList" v-if="itemId==''" id="dealerAccountEdit-tenantSn" @change="custChange"></custList>
+            <span v-else>{{ detailData ? (detailData.org ? detailData.org.name : '--') : '--' }}</span>
+          </a-form-model-item>
+          <a-form-model-item label="管理员姓名" prop="name">
+            <a-input
+            id="dealerAccountEdit-name"
+            :maxLength="30"
+            v-model.trim="form.name"
+            placeholder="请输入管理员姓名(最多30个字符)"
+            allowClear />
+          </a-form-model-item>
+          <a-form-model-item label="管理员手机" prop="phone">
+            <a-input
+            id="dealerAccountEdit-phone"
+            :maxLength="11"
+            v-model.trim="form.phone"
+            placeholder="请输入管理员手机(最多11个字符)"
+            allowClear />
+          </a-form-model-item>
+          <a-form-model-item label="管理员账号" prop="loginName">
+            <a-input
+            id="dealerAccountEdit-loginName"
+            :maxLength="50"
+            v-model.trim="form.loginName"
+            placeholder="请输入管理员账号,字母/数字(最多50个字符)"
+            allowClear />
+          </a-form-model-item>
+          <a-form-model-item label="管理员密码" :prop="itemId=='' ? 'password' : ''" :extra="itemId ? '说明:已录入的密码不会显示,录入新密码将会覆盖原有密码' : ''" >
+            <a-input
+            id="dealerAccountEdit-password"
+            :maxLength="50"
+            type="password"
+            v-model.trim="form.password"
+            placeholder="请输入管理员密码,字母/数字(最多50个字符)"
+            allowClear />
+          </a-form-model-item>
+          <a-form-model-item label="最大可开通用户数" prop="org.childUserMaxNum" extra="(含管理员账号)">
+            <a-input-number
+            id="dealerAccountEdit-childUserMaxNum"
+            v-model="form.org.childUserMaxNum"
+            :precision="0"
+            :min="1"
+            :max="999999"
+            placeholder="请输入数量"
+            style="width: 100%;" />
+          </a-form-model-item>
+        </a-form-model>
+        <div class="btn-cont">
+          <a-button type="primary" id="dealerAccountEdit-save" @click="handleSave">保存</a-button>
+          <a-button id="dealerAccountEdit-back" @click="isShow = false" style="margin-left: 15px;">取消</a-button>
+        </div>
+		  </a-spin>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import custList from '@/views/common/custList.vue'
+import { dealerUserSave, dealerUserDetail } from '@/api/dealer'
+export default {
+  name: 'DealerAccountEditModal',
+  components: { custList },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemId: {
+      type: [Number, String],
+      default: ''
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      spinning: false,
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 18 }
+      },
+      form: {
+        tenantSn: '',
+        name: '',
+        phone: '',
+        loginName: '',
+        password: '',
+        org: {
+          childUserMaxNum: ''
+        }
+      },
+      rules: {
+        tenantSn: [{ required: true, message: '请选择经销商', trigger: 'change' }],
+        name: [{ required: true, message: '请输入管理员姓名', trigger: 'blur' }],
+        phone: [{ required: true, message: '请输入管理员手机', trigger: 'blur' }, { pattern: /^\d{11}$/, message: '请输入正确的手机号' }],
+        loginName: [{ required: true, message: '请输入管理员账号', trigger: 'blur' }, { pattern: /^[0-9a-zA-Z]+$/, message: '管理员账号由字母和数字组成' }],
+        password: [{ required: true, message: '请输入管理员密码', trigger: 'blur' }, { pattern: /^[0-9a-zA-Z]+$/, message: '管理员密码由字母和数字组成' }],
+        'org.childUserMaxNum': [{ required: true, message: '请输入最大可开通用户数', trigger: 'blur' }]
+      },
+      detailData: null //  详情数据
+    }
+  },
+  methods: {
+    custChange (val) {
+      this.form.tenantSn = val.key
+    },
+    //  保存
+    handleSave () {
+      const _this = this
+      _this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const formData = JSON.parse(JSON.stringify(_this.form))
+          formData.id = _this.itemId ? _this.itemId : undefined
+          if (!formData.password) {
+            delete formData.password
+          }
+          _this.spinning = true
+          dealerUserSave(formData).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$emit('ok')
+              _this.isShow = false
+              _this.spinning = false
+            }else{
+              _this.spinning = false
+            }
+          })
+        } else {
+          return false
+        }
+      })
+    },
+    //  获取详情
+    getDetail () {
+      dealerUserDetail({ id: this.itemId }).then(res => {
+        if (res.status == 200) {
+          this.detailData = res.data
+          this.form.tenantSn = this.detailData.tenantSn || ''
+          this.form.name = this.detailData.name || ''
+          this.form.phone = this.detailData.phone || ''
+          this.form.loginName = this.detailData.loginName || ''
+          this.form.password = this.detailData.password || ''
+          const childUserMaxNum = this.detailData ? (this.detailData.org ? (this.detailData.org.childUserMaxNum ? this.detailData.org.childUserMaxNum : '') : '') : ''
+          this.form.org.childUserMaxNum = childUserMaxNum
+        } else {
+          this.detailData = null
+          this.$refs.ruleForm.resetFields()
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.$refs.ruleForm.resetFields()
+        this.form.tenantSn = ''
+        this.form.name = ''
+        this.form.phone = ''
+        this.form.loginName = ''
+        this.form.password = ''
+        this.form.org.childUserMaxNum = ''
+        if (this.itemId == '') {
+          this.$refs.custList.resetForm()
+        }
+      }
+    },
+    itemId (newValue, oldValue) {
+      if (this.isShow && newValue) {
+        this.getDetail()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .dealerAccountEdit-modal{
+    .ant-modal-body {
+      padding: 40px 40px 24px;
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>

+ 188 - 0
src/views/dealerManagement/dealerAccountManagement/list.vue

@@ -0,0 +1,188 @@
+<template>
+  <a-card size="small" :bordered="false" class="dealerAccountList-wrap">
+    <!-- 搜索条件 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
+        <a-row :gutter="15">
+          <a-col :md="6" :sm="24">
+            <a-form-item label="经销商名称">
+              <a-input id="dealerAccountList-name" v-model.trim="queryParam.org.name" allowClear placeholder="请输入经销商名称"/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="管理员账号">
+              <a-input id="dealerAccountList-loginName" v-model.trim="queryParam.loginName" allowClear placeholder="请输入管理员账号"/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="账号状态">
+              <v-select code="ENABLE_FLAG" id="dealerAccountList-loginFlag" v-model="queryParam.loginFlag" allowClear placeholder="请选择账号状态"></v-select>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="dealerAccountList-refresh">查询</a-button>
+            <a-button style="margin-left: 8px" @click="resetSearchForm" :disabled="disabled" id="dealerAccountList-reset">重置</a-button>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 操作按钮 -->
+    <div class="table-operator">
+      <a-button id="dealerAccountList-add" type="primary" class="button-error" @click="handleEdit()">新增</a-button>
+    </div>
+    <!-- 列表 -->
+    <s-table
+      class="sTable"
+      ref="table"
+      size="default"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :data="loadData"
+      :scroll="{ x: 1310, y: tableHeight }"
+      bordered>
+      <!-- 账号状态 -->
+      <template slot="loginFlag" slot-scope="text, record">
+        <a-switch
+          id="dealerAccountList-enable"
+          checkedChildren="启用"
+          unCheckedChildren="禁用"
+          @change="changeStatus(record)"
+          :checked="record.loginFlag == 1 ? true : false" />
+        <!-- <span v-else>{{ record.loginFlag==1?'已启用':'已禁用' }}</span> -->
+      </template>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-button size="small" type="link" class="button-info" @click="handleEdit(record)" id="dealerAccountList-edit-btn">编辑</a-button>
+        <a-button size="small" type="link" class="button-success" @click="handleDetail(record)" id="dealerAccountList-detail-btn">详情</a-button>
+        <a-button
+          size="small"
+          type="link"
+          class="button-warning"
+          @click="handleReset(record)"
+          id="dealerAccountList-reset-btn">重置密码</a-button>
+      </template>
+    </s-table>
+    <!-- 新增/编辑 -->
+    <dealer-account-edit-modal :openModal="openModal" :nowData="nowData" :itemId="itemId" @ok="$refs.table.refresh(true)" @close="closeModal" />
+    <!-- 查看 -->
+    <dealer-account-detail-modal :openModal="openDetailModal" :itemId="itemId" @close="closeDetailModal" />
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import dealerAccountEditModal from './editModal.vue'
+import dealerAccountDetailModal from './detailModal.vue'
+import { dealerUserList, dealerUserEnable, dealerUserResetP } from '@/api/dealer'
+export default {
+  components: { STable, VSelect, dealerAccountEditModal, dealerAccountDetailModal },
+  data () {
+    return {
+      tableHeight: 0,
+      queryParam: { //  查询条件
+        org: {
+          name: ''
+        },
+        loginName: '',
+        loginFlag: undefined
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '创建时间', dataIndex: 'createDate', width: 160, align: 'center' },
+        { title: '经销商名称', dataIndex: 'org.name', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '管理员姓名', dataIndex: 'name', width: 220, align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '管理员账号', dataIndex: 'loginName', width: 140, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '授权用户数', dataIndex: 'org.childUserMaxNum', width: 140, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '状态', scopedSlots: { customRender: 'loginFlag' }, width: 150, align: 'center' },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 200, align: 'center', fixed: 'right' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        if (this.tableHeight == 0) {
+          this.tableHeight = window.innerHeight - 380
+        }
+        return dealerUserList(Object.assign(parameter, this.queryParam)).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+            data.list[i].loginFlag = Number(data.list[i].loginFlag)
+          }
+          this.disabled = false
+          return data
+        })
+      },
+      openModal: false, //  新增编辑  弹框
+      openDetailModal: false, // 详情  弹框
+      itemId: '', //  当前id
+      nowData: null, //  当前记录数据
+      productBrandList: []
+    }
+  },
+  methods: {
+    //  重置
+    resetSearchForm () {
+      this.queryParam.org.name = ''
+      this.queryParam.loginName = ''
+      this.queryParam.loginFlag = undefined
+      this.$refs.table.refresh(true)
+    },
+    //  新增/编辑
+    handleEdit (row) {
+      this.itemId = row ? row.id : ''
+      this.nowData = row || null
+      this.openModal = true
+    },
+    // 详情
+    handleDetail (row) {
+      this.itemId = row ? row.id : ''
+      this.openDetailModal = true
+    },
+    //  关闭弹框
+    closeModal () {
+      this.itemId = ''
+      this.nowData = null
+      this.openModal = false
+    },
+    // 关闭详情弹框
+    closeDetailModal () {
+      this.itemId = ''
+      this.openDetailModal = false
+    },
+    // 重置密码
+    handleReset (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '重置密码后,新的密码会以短信形式发送到【管理员手机】,确定要重置吗?',
+        centered: true,
+        onOk () {
+          dealerUserResetP({ id: row.id }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+            }
+          })
+        }
+      })
+    },
+    // 启用 禁用
+    changeStatus (record) {
+      const params = {
+        id: record.id,
+        flag: record.loginFlag == 1 ? '0' : '1'
+      }
+      dealerUserEnable(params).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          this.$refs.table.refresh()
+        } else {
+          this.$refs.table.refresh()
+        }
+      })
+    }
+  }
+}
+</script>

+ 172 - 0
src/views/dealerManagement/dealerRelationshipBinding/associateModal.vue

@@ -0,0 +1,172 @@
+<template>
+  <a-modal
+    centered
+    class="relationshipBinding-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="关联下级"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="800">
+    <!-- 表单 -->
+    <div>
+      <a-spin :spinning="spinning" tip="Loading...">
+        <a-form-model
+          id="relationshipBinding-form"
+          ref="ruleForm"
+          :model="form"
+          :rules="rules"
+          :label-col="formItemLayout.labelCol"
+          :wrapper-col="formItemLayout.wrapperCol"
+        >
+          <a-form-model-item label="上级名称" v-if="nowData">
+            {{ nowData.dealerName }}
+          </a-form-model-item>
+          <a-form-model-item label="选择下级">
+            <queryChild ref="queryChid" :dealerLevelList="dealerLevelList" @change="handleDisassociate"></queryChild>
+          </a-form-model-item>
+        </a-form-model>
+        <div class="btn-cont">
+          <a-button type="primary" id="product-category-edit-modal-save" @click="handleSave">确定</a-button>
+          <a-button id="product-category-edit-modal-back" @click="isShow = false" style="margin-left: 15px;">关闭</a-button>
+        </div>
+      </a-spin>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { bindRelation } from '@/api/dealerRelation'
+import queryChild from './queryChild.vue'
+export default {
+  name: 'RelationshipBindingModal',
+  components: { queryChild },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    tabInd: {
+      type: [Number, String],
+      default: ''
+    },
+    nowData: {
+      type: Object,
+      default: null
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      spinning: false,
+      form: {},
+      rules: {},
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 16 }
+      },
+      dealerLevelList: [],
+      subDealerSn: '',
+      isRelation: '' //  是否已被关联过
+    }
+  },
+  methods: {
+    handleDisassociate (val, parentDealerSn) {
+      this.subDealerSn = val.key
+      this.isRelation = parentDealerSn
+    },
+    //  保存
+    handleSave () {
+      const _this = this
+      _this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          if (_this.subDealerSn == '') {
+            this.$message.info('请选择下级')
+            return
+          }
+          const formData = {
+            subDealerSn: _this.subDealerSn,
+            parentDealerSn: _this.nowData && _this.nowData.dealerSn ? _this.nowData.dealerSn : undefined
+          }
+          if (_this.isRelation) {
+            _this.$confirm({
+              title: '提示',
+              content: '确认要解除原有绑定关系,建立新的绑定关系吗?',
+              centered: true,
+              closable: true,
+              onOk () {
+                _this.handleBind(formData)
+              }
+            })
+          } else {
+            _this.handleBind(formData)
+          }
+        } else {
+          return false
+        }
+      })
+    },
+    handleBind (formData) {
+      const _this = this
+      _this.spinning = true
+      bindRelation(formData).then(res => {
+        if (res.status == 200) {
+          _this.$message.success(res.message)
+          _this.$emit('ok', formData.parentDealerSn)
+          _this.isShow = false
+          _this.spinning = false
+        } else {
+          _this.spinning = false
+        }
+      })
+    },
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.$refs.ruleForm.resetFields()
+        this.$refs.queryChid.resetForm()
+        this.subDealerSn = []
+      } else {
+        this.dealerLevelList = [this.tabInd == '1' ? 'CITY' : 'SPECIAL']
+      }
+    },
+    tabInd (newValue, oldValue) {
+      if (this.isShow && newValue) {
+        this.dealerLevelList = [newValue == '1' ? 'CITY' : 'SPECIAL']
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .relationshipBinding-modal{
+    .ant-modal-body {
+      padding: 40px 40px 24px;
+    }
+    .search-opt{
+      padding: 0;
+      margin: 0;
+      list-style: none;
+      li{
+        padding: 5px 15px;
+      }
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>

+ 208 - 0
src/views/dealerManagement/dealerRelationshipBinding/list.vue

@@ -0,0 +1,208 @@
+<template>
+  <a-card size="small" :bordered="false" class="relationshipBindingList-wrap">
+    <!-- 搜索条件 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline" @keyup.enter.native="getList()">
+        <a-row :gutter="15">
+          <a-col :md="6" :sm="24">
+            <a-form-item label="经销商名称">
+              <a-input id="relationshipBindingList-dealerName" v-model.trim="queryParam.dealerName" allowClear placeholder="请输入经销商名称"/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-button style="margin-bottom: 18px;" type="primary" @click="getList()" :disabled="disabled" id="relationshipBindingList-refresh">查询</a-button>
+            <a-button style="margin: 0 0 18px 8px" @click="resetSearchForm()" :disabled="disabled" id="relationshipBindingList-reset">重置</a-button>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 列表 -->
+    <a-tabs type="card" @change="tabChange" v-model="tabInd">
+      <a-tab-pane key="1" tab="省市级关系绑定"></a-tab-pane>
+      <a-tab-pane key="2" tab="特约店关系绑定"></a-tab-pane>
+    </a-tabs>
+    <a-table
+      class="sTable"
+      ref="table"
+      size="default"
+      :rowKey="(record) => record.dealerSn"
+      :columns="columns"
+      :pagination="pagination"
+      :data-source="list"
+      @expand="expand"
+      @change="change"
+      :expandedRowKeys="expandedRowKeys"
+      :expandRowByClick="true"
+      :scroll="{ y: tableHeight }">
+      <span slot="expandIcon">
+        1
+      </span>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-button
+          type="link"
+          class="button-info"
+          size="small"
+          icon="plus"
+          :id="'relationshipBindingList-addSubItem'+record.id"
+          v-if="record.children"
+          @click.stop="handleAssociate(record)">关联下级</a-button>
+        <a-button
+          type="link"
+          class="button-error"
+          size="small"
+          icon="close"
+          :id="'relationshipBindingList-delSubItem'+record.id"
+          v-else
+          @click.stop="handleDisassociate(record)">取消关联</a-button>
+      </template>
+    </a-table>
+    <!-- 关联下级 -->
+    <associate-modal :openModal="openModal" :nowData="nowData" :tabInd="tabInd" @ok="addItemOk" @close="closeModal" />
+  </a-card>
+</template>
+I
+<script>
+import { STable, VSelect } from '@/components'
+import associateModal from './associateModal.vue'
+import { dealerRelationList, querySubList, unbindRelation } from '@/api/dealerRelation'
+export default {
+  components: { STable, VSelect, associateModal },
+  data () {
+    return {
+      tableHeight: 0,
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 16 }
+      },
+      queryParam: {
+        dealerName: ''
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      columns: [
+        { title: '经销商名称', dataIndex: 'dealerName', align: 'left' },
+        { title: '操作', scopedSlots: { customRender: 'action' }, align: 'center' }
+      ],
+      expandedRowKeys: [],
+      list: [],
+      parameter: {
+        pageNo: 1,
+        pageSize: 10
+      },
+      pagination: {
+        total: 1,
+        current: 1,
+        showTotal: total => `共 ${total} 条记录 第 ${this.pagination.current} / ${Math.ceil(total / this.pagination.pageSize)} 页`,
+        showQuickJumper: true,
+        showSizeChanger: true,
+        pageSize: 10
+      },
+      openModal: false, //  新增编辑  弹框
+      nowData: null, //  当前记录数据
+      tabInd: '1', //  tabs选中项
+      dealerSn: []
+    }
+  },
+  mounted () {
+    this.tableHeight = window.innerHeight - 380
+    this.getList()
+  },
+  methods: {
+    expand (expanded, record) {
+      this.nowData = record
+      this.expandedRowKeys = [] // 重置展开节点,只展开当前点击的节点(内部数据调用模板,无法做到同时几个内层表格数据直接缓存在页面)
+      if (expanded) {
+        this.getSubItem(record) // 获取表格内部数据
+      }
+    },
+    // 外层表格操作
+    change (pagination, filters, sorter) { // 对页面大小,筛选,排序等条件修改后重新查询数据
+      this.pagination = pagination
+      this.parameter.pageNo = pagination.current
+      this.parameter.pageSize = pagination.pageSize
+      this.getList()
+    },
+    // 获取子节点数据
+    getSubItem (record) {
+      record.children = []
+      querySubList({ parentDealerSn: record.dealerSn }).then(res => {
+        if (res.status == 200 && res.data && res.data.length) {
+          record.children = res.data
+        } else {
+          record.children = this.nowData.children
+        }
+        if (record.children.length == 0) {
+          this.$message.info('暂无下级,请关联下级')
+        } else {
+          this.expandedRowKeys = [record.dealerSn]
+        }
+      })
+    },
+    // 添加子机成功
+    addItemOk () {
+      this.getSubItem(this.nowData)
+    },
+    // 获取列表数据
+    getList () {
+      this.disabled = true
+      console.log(this.queryParam.dealerName)
+      dealerRelationList(Object.assign(this.parameter, this.queryParam, { dealerLevelList: this.tabInd == 1 ? ['PROVINCE'] : ['PROVINCE', 'CITY'] })).then(res => {
+        const data = res.data
+        this.pagination.total = data.count
+        this.pagination.current = data.pageNo
+        this.pagination.pageSize = data.pageSize
+        this.parameter.pageNo = data.pageNo
+        this.parameter.pageSize = data.pageSize
+        const no = (data.pageNo - 1) * data.pageSize
+        for (var i = 0; i < data.list.length; i++) {
+          data.list[i].no = no + i + 1
+          data.list[i].children = []
+        }
+        this.disabled = false
+        this.list = data.list
+      })
+    },
+    //  重置
+    resetSearchForm (flag) {
+      if (!flag) {
+        this.queryParam.dealerName = ''
+        this.parameter.pageNo = 1
+        this.parameter.pageSize = 10
+        this.expandedRowKeys = []
+      }
+      this.getList()
+    },
+    tabChange (key) {
+      this.tabInd = key
+      this.resetSearchForm()
+    },
+    // 关联下级
+    handleAssociate (row) {
+      this.nowData = row
+      this.expandedRowKeys = [row.dealerSn]
+      this.openModal = true
+    },
+    // 取消关联
+    handleDisassociate (row) {
+      const _this = this
+      _this.$confirm({
+        title: '提示',
+        content: '确认要解除上下级的关系吗?',
+        centered: true,
+        onOk () {
+          unbindRelation({ subDealerSn: row.dealerSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.addItemOk()
+            }
+          })
+        }
+      })
+    },
+    //  关闭弹框
+    closeModal () {
+      this.openModal = false
+    }
+  }
+}
+</script>

+ 72 - 0
src/views/dealerManagement/dealerRelationshipBinding/queryChild.vue

@@ -0,0 +1,72 @@
+<template>
+  <a-select
+    show-search
+    label-in-value
+    :value="dealerName"
+    placeholder="请输入下级名称搜索"
+    style="width: 100%"
+    option-label-prop="label"
+    :filter-option="false"
+    :not-found-content="fetching ? undefined : null"
+    @search="fetchUser"
+    @change="handleChange"
+  >
+    <a-spin v-if="fetching" slot="notFoundContent" size="small" />
+    <a-select-option v-for="item in data" :key="item.dealerSn" :value="item.dealerSn" :label="item.dealerName">
+      {{ item.dealerName }} - {{ item.parentDealerSn ? '已关联' : '未关联' }}
+    </a-select-option>
+  </a-select>
+</template>
+<script>
+import debounce from 'lodash/debounce'
+import { dealerRelationList } from '@/api/dealerRelation'
+export default {
+  props: {
+    dealerLevelList: {
+      type: Array,
+      default: function () {
+        return []
+      }
+    }
+  },
+  data () {
+    this.lastFetchId = 0
+    this.fetchUser = debounce(this.fetchUser, 800)
+    return {
+      data: [],
+      dealerName: [],
+      fetching: false
+    }
+  },
+  methods: {
+    fetchUser (dealerName) {
+      console.log('fetching user', dealerName)
+      if (dealerName == '') return
+      this.lastFetchId += 1
+      const fetchId = this.lastFetchId
+      this.data = []
+      this.fetching = true
+      dealerRelationList({ 'dealerName': dealerName, 'dealerLevelList': this.dealerLevelList, pageNo: 1, pageSize: 20 }).then(res => {
+        if (fetchId !== this.lastFetchId) {
+          return
+        }
+        this.data = res.data.list || []
+        this.fetching = false
+      })
+    },
+    handleChange (value) {
+      const ind = this.data.findIndex(item => item.dealerSn == value.key)
+      const parentDealerSn = ind != -1 && this.data[ind].parentDealerSn ? this.data[ind].parentDealerSn : ''
+      Object.assign(this, {
+        dealerName: value,
+        data: [],
+        fetching: false
+      })
+      this.$emit('change', value, parentDealerSn)
+    },
+    resetForm () {
+      this.dealerName = []
+    }
+  }
+}
+</script>

+ 350 - 0
src/views/dealerManagement/marketingDivisionSet/editModal.vue

@@ -0,0 +1,350 @@
+<template>
+  <a-modal
+    centered
+    class="marketingDivisionSetEdit-modal"
+    :footer="null"
+    :maskClosable="false"
+    :title="modalTit"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="800">
+    <!-- 表单 -->
+    <div>
+      <a-spin :spinning="spinning" tip="Loading...">
+        <a-form-model
+          id="marketingDivisionSetEdit-form"
+          ref="ruleForm"
+          :model="form"
+          :rules="rules"
+          :label-col="formItemLayout.labelCol"
+          :wrapper-col="formItemLayout.wrapperCol"
+        >
+          <a-form-model-item label="分区名称" prop="subareaName">
+            <a-input
+              id="marketingDivisionSetEdit-subareaName"
+              :maxLength="30"
+              v-model="form.subareaName"
+              @change="filterEmpty"
+              placeholder="请输入分区名称(最多30个字符)"
+              allowClear />
+          </a-form-model-item>
+          <a-form-model-item label="省份/市">
+            <div class="tree-node" id="treeNode">
+              <div class="tree-box" v-for="item in addrProvinceList" :key="item.id">
+                <div class="tree-parent">
+                  <span>
+                    <a-checkbox style="width: 100%;" :indeterminate="item.indeterminate" v-model="item.checked" @change="onChange(item,$event)">
+                      {{ item.name }}
+                      <!-- <i style="font-size: 12px;color: #999;font-style: normal;">(已选 {{ item.children | hasCheckChild }} 个市区)</i> -->
+                    </a-checkbox>
+                  </span>
+                  <span @click="expend(item)"><a-icon :title="item.isOpen==0?'展开':'收起'" :type="item.isOpen==0?'plus-square':'minus-square'" /></span>
+                </div>
+
+                <!-- 子级 -->
+                <div v-show="item.isOpen==1" class="tree-child">
+                  <div v-for="child in item.children" :key="child.id">
+                    <a-checkbox v-model="child.checked" style="width: 100%;" @change="onChange(child,$event,item)">
+                      {{ child.name }}
+                    </a-checkbox>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </a-form-model-item>
+        </a-form-model>
+        <div class="btn-cont">
+          <a-button type="primary" id="marketingDivisionSetEdit-modal-save" @click="handleSave">保存</a-button>
+          <a-button id="marketingDivisionSetEdit-modal-back" @click="isShow = false" style="margin-left: 15px;">返回列表</a-button>
+        </div>
+      </a-spin>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { STable, Upload } from '@/components'
+import Editor from '@/components/WEeditor'
+import { getArea } from '@/api/data'
+import { subareaSaveSubareaArea, subareaFindBySn } from '@/api/subarea'
+export default {
+  name: 'MarketingDivisionSetEditModal',
+  components: { STable, Upload, Editor },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemId: {
+      type: [Number, String],
+      default: ''
+    },
+    nowData: {
+      type: Object,
+      default: null
+    }
+  },
+  computed: {
+    modalTit () {
+      return (this.itemId ? '编辑' : '新增') + '分区'
+    }
+  },
+  filters: {
+    hasCheckChild: function (value) {
+      return value.filter(item => item.checked).length
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      spinning: false,
+      formItemLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 18 }
+      },
+      form: {
+        subareaName: '' // 分区名称
+      },
+      rules: {
+        subareaName: [
+          { required: true, message: '请输入分区名称', trigger: 'blur' }
+        ]
+      },
+      addrProvinceList: [], //  省下拉
+      subareaAreaList: []
+    }
+  },
+  methods: {
+    filterEmpty () {
+      let str = this.form.subareaName
+      str = str.replace(/\ +/g, '')
+      str = str.replace(/[ ]/g, '')
+      str = str.replace(/[\r\n]/g, '')
+      this.form.subareaName = str
+    },
+    onChange (item, e, parent) {
+      // console.log(item, `checked = ${e.target.checked}`)
+      item.checked = e.target.checked
+      item.noSave = false
+      // 父级
+      if (item.type == 2) {
+        item.children && item.children.map(d => {
+          d.checked = item.checked
+        })
+        item.indeterminate = false
+      }
+      // 子级
+      if (item.type == 3) {
+        // 父级节点
+        const hasCheckd = parent.children.filter(k => k.checked)
+        // 是否全选
+        parent.checked = hasCheckd.length == parent.children.length
+        parent.children.map(d => d.noSave = parent.checked)
+        // indeterminate为true,则为全选,false则为部分选择或者空
+        parent.indeterminate = ((hasCheckd.length < parent.children.length) && (hasCheckd.length != 0))
+      }
+      this.addrProvinceList = JSON.parse(JSON.stringify(this.addrProvinceList))
+    },
+    // 展开收起
+    expend (item) {
+      if (item.children && item.children.length == 0) {
+        item.isOpen = 1
+        this.getArea('city', item, 1)
+      } else {
+        item.isOpen = !item.isOpen
+      }
+    },
+    //  省/市/区
+    getArea (leve, item, openType) {
+      let params
+      if (leve == 'province') {
+        params = { type: '2' }
+      } else {
+        params = { parentId: item.areaSn, type: leve == 'city' ? '3' : '4' }
+      }
+      getArea(params).then(res => {
+        if (res.status == 200) {
+          if (leve == 'province') {
+            this.addrProvinceList = res.data || []
+            this.addrProvinceList.map(item => {
+              item.noSave = true
+              item.checked = false
+              item.children = []
+              item.indeterminate = false
+            })
+            // 编辑时获取已选数据
+            if (this.itemId) {
+              this.getChecked()
+            }
+            document.getElementById('treeNode').scrollTop = 0
+          } else if (leve == 'city') {
+            item.children = res.data || []
+            item.children.map(d => {
+              // 编辑时回显
+              if (this.itemId && openType == 0) {
+                d.checked = !!this.subareaAreaList.find(o => o.areaSn == d.areaSn)
+                d.noSave = false
+              } else {
+                d.checked = item.checked
+                d.noSave = true
+              }
+            })
+
+            // 首次加载子级
+            if (openType == 1) {
+              this.addrProvinceList = JSON.parse(JSON.stringify(this.addrProvinceList))
+            } else {
+              item.isOpen = 1
+              item.indeterminate = true
+            }
+          }
+        } else {
+          if (leve == 'province') {
+            this.addrProvinceList = []
+          } else if (leve == 'city') {
+            item.children = []
+            item.isOpen = 0
+          }
+        }
+      })
+    },
+    // 过滤数据
+    filterData (list) {
+      list.map(item => {
+        if (item.checked && !item.noSave) {
+          this.subareaAreaList.push({
+            areaSn: item.areaSn,
+            areaName: item.name,
+            areaType: item.type,
+            areaParentSn: item.parentId
+          })
+        } else {
+          if (item.children && item.children.length) {
+            this.filterData(item.children)
+          }
+        }
+      })
+    },
+    //  保存
+    handleSave () {
+      const _this = this
+      _this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const formData = JSON.parse(JSON.stringify(_this.form))
+          this.subareaAreaList = []
+          this.filterData(this.addrProvinceList)
+          // console.log(this.subareaAreaList)
+          // 编辑
+          if (this.itemId) {
+            formData.subareaSn = this.itemId
+          }
+          formData.subareaAreaList = this.subareaAreaList
+          // console.log(formData, 'formData')
+          _this.spinning = true
+          subareaSaveSubareaArea(formData).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$emit('ok')
+              _this.isShow = false
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        } else {
+          return false
+        }
+      })
+    },
+    // 编辑
+    getChecked () {
+      subareaFindBySn({ sn: this.itemId }).then(res => {
+        // console.log(res.data)
+        this.form.subareaName = res.data.subareaName
+        this.subareaAreaList = res.data.subareaAreaList
+        this.form.subareaSn = res.data.subareaSn
+        this.form.id = res.data.id
+        // 回显数据
+        this.showChecked()
+      })
+    },
+    showChecked () {
+      // 省回显
+      this.addrProvinceList.map(item => {
+        item.checked = !!this.subareaAreaList.find(d => d.areaSn == item.areaSn)
+        item.noSave = false
+        item.indeterminate = false
+      })
+      // 市回显
+      const hasCity = this.nowData.subareaAreaList.filter(item => item.citySubareaAreaList && item.citySubareaAreaList.length)
+      // console.log(hasCity, 'hasCity.nowData')
+      hasCity.map(item => {
+        // 省
+        const pre = this.addrProvinceList.find(k => k.areaSn == item.areaSn)
+        // 获取子级
+        this.getArea('city', pre, 0)
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.form.subareaName = ''
+        this.form.subareaSn = ''
+        delete this.form.id
+      } else {
+        this.getArea('province')
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .marketingDivisionSetEdit-modal{
+    .ant-modal-body {
+    	padding: 40px 40px 24px;
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+    .tree-node{
+      height: 300px;
+      overflow: auto;
+      .tree-box{
+        .tree-parent{
+          display: flex;
+          align-items: center;
+          border-bottom: 1px solid #eee;
+          padding: 0 10px;
+          > span{
+            margin:0 5px;
+            &:first-child{
+              flex-grow: 1;
+            }
+            &:last-child{
+              cursor: pointer;
+            }
+          }
+        }
+        .tree-child{
+          padding: 10px 10px 10px 35px;
+          display: flex;
+          align-items: center;
+          flex-wrap:wrap ;
+          > div{
+            margin:0 5px;
+          }
+        }
+      }
+
+    }
+  }
+</style>

+ 112 - 0
src/views/dealerManagement/marketingDivisionSet/list.vue

@@ -0,0 +1,112 @@
+<template>
+  <a-card size="small" :bordered="false" class="marketingDivisionSetList-wrap">
+    <!-- 操作按钮 -->
+    <div class="table-operator">
+      <a-button id="marketingDivisionSetList-add" type="primary" class="button-error" @click="handleEdit()">新增</a-button>
+    </div>
+    <!-- 列表 -->
+    <s-table
+      class="sTable"
+      ref="table"
+      size="default"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :showPagination="false"
+      :data="loadData"
+      bordered>
+      <!-- 市区 -->
+      <template slot="cityArea" slot-scope="text, record">
+        <div style="display: inline-block;margin-right: 15px;" v-for="item in record.subareaAreaList" :key="item.id">
+          {{ item.areaName }}
+          <span v-if="item.citySubareaAreaList">(</span>
+          <span style="color: #999;margin:0 3px;" v-for="area in item.citySubareaAreaList" :key="area.id">
+            {{ area.areaName }}
+          </span>
+          <span v-if="item.citySubareaAreaList">)</span>
+        </div>
+      </template>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-button size="small" type="link" class="button-info" @click="handleEdit(record)" id="marketingDivisionSetList-edit-btn">编辑</a-button>
+        <a-button size="small" type="link" class="button-error" @click="handleDel(record)" id="marketingDivisionSetList-del-btn">删除</a-button>
+      </template>
+    </s-table>
+    <!-- 编辑分区 -->
+    <marketing-division-set-edit-modal :nowData="nowData" :openModal="openModal" :itemId="itemId" @ok="$refs.table.refresh()" @close="closeModal" />
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import marketingDivisionSetEditModal from './editModal.vue'
+import { subareaQueryIncludeAreaAll, subareaDeleteBySn } from '@/api/subarea'
+export default {
+  components: { STable, VSelect, marketingDivisionSetEditModal },
+  data () {
+    return {
+      disabled: false, //  查询、重置按钮是否可操作
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '分区名', dataIndex: 'subareaName', width: 200, align: 'center' },
+        { title: '省份/市', scopedSlots: { customRender: 'cityArea' }, align: 'left' },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 150, align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        return subareaQueryIncludeAreaAll(parameter).then(res => {
+          const data = res.data
+          const no = 0
+          for (var i = 0; i < data.length; i++) {
+            data[i].no = no + i + 1
+          }
+          this.disabled = false
+          return data
+        })
+      },
+      openModal: false, //  编辑  弹框
+      nowData: null,
+      itemId: null //  当前产品id
+    }
+  },
+  methods: {
+    //  重置
+    resetSearchForm () {
+      this.$refs.table.refresh(true)
+    },
+    // 删除
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认要删除吗?',
+        centered: true,
+        onOk () {
+          subareaDeleteBySn({ sn: row.subareaSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+            }
+          })
+        }
+      })
+    },
+    //  编辑
+    handleEdit (row) {
+      this.itemId = row && row.subareaSn ? row.subareaSn : null
+      this.nowData = row
+      this.openModal = true
+    },
+    //  关闭弹框
+    closeModal () {
+      this.itemId = null
+      this.nowData = null
+      this.openModal = false
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+    })
+  }
+}
+</script>

+ 207 - 0
src/views/dealerManagement/merchantInfoManagement/detailModal.vue

@@ -0,0 +1,207 @@
+<template>
+  <a-modal
+    centered
+    class="merchantInfoManagement-modal"
+    :footer="null"
+    :maskClosable="false"
+    :title="title"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="960">
+    <div v-if="form">
+      <a-collapse :activeKey="['1','2','3']" class="merchantInfoManagement-cont-m">
+        <a-collapse-panel key="1" header="基础信息">
+          <a-descriptions :column="2" bordered size="small">
+            <a-descriptions-item label="经销商名称">{{ form.dealerName || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="经销商别名">{{ form.dealerAlias || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="商户类型">{{ form.dealerTypeDictValue || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="联系人1">{{ form.contact || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="联系手机1">{{ form.contactMobile || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="联系角色1">{{ form.contactRole || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="联系电话">{{ form.dealerTelephone || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="地址">
+              <span v-if="form.provinceName || form.cityName || form.districtName || form.address">{{ form.provinceName }}{{ form.cityName }}{{ form.districtName }}{{ form.address }}</span>
+              <span v-else>--</span>
+            </a-descriptions-item>
+          </a-descriptions>
+        </a-collapse-panel>
+      </a-collapse>
+      <a-collapse class="merchantInfoManagement-cont-m">
+        <a-collapse-panel key="2" header="公司信息">
+          <a-descriptions :column="2" bordered size="small">
+            <a-descriptions-item label="经营方式">{{ form.busniessMode || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="经营项目">{{ form.busniessItmes || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="公司规模">{{ form.busniessScope || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="成立时间">{{ form.buildDate || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="一般纳税人">
+              <span v-if="form.isTaxpayer">{{ form.isTaxpayer == 1 ? '是':'否' }}</span>
+              <span v-else>--</span>
+            </a-descriptions-item>
+            <a-descriptions-item label="身份证号码">{{ form.indentityCard || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="生日">{{ form.brithday || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="籍贯">{{ form.nativePlace || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="邮箱">{{ form.mail || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="联系人2">{{ form.contact2 || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="联系角色2">{{ form.contractRole2 || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="联系手机2">{{ form.contactMobile2 || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="邮政编码">{{ form.zipCode || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="收货人">{{ form.receiveContact || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="收货人电话">{{ form.receiveMobile || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="收货地址">
+              <span v-if="form.receiveProvinceName || form.receiveCityName || form.receiveDistrictName || form.receiveAddress">{{ form.receiveProvinceName }}{{ form.receiveCityName }}{{ form.receiveDistrictName }}{{ form.receiveAddress }}</span>
+              <span v-else>--</span>
+            </a-descriptions-item>
+            <a-descriptions-item label="银行账户">{{ form.tradeAccountName || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="开户行">{{ form.tradeBankName || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="银行账号">{{ form.tradeBankAccount || '--' }}</a-descriptions-item>
+          </a-descriptions>
+        </a-collapse-panel>
+      </a-collapse>
+      <a-collapse class="merchantInfoManagement-cont-m">
+        <a-collapse-panel key="3" header="总部信息">
+          <a-descriptions :column="2" bordered size="small">
+            <a-descriptions-item label="箭冠汽配代码">{{ form.jgAutoPartsCode || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="门头更换日期">{{ form.jgDoorHeaderChangeTime || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="特约价是否可见">
+              <span v-if="form.isShowSpecialPrice">{{ form.isShowSpecialPrice == 1 ? '是':'否' }}</span>
+              <span v-else>--</span>
+            </a-descriptions-item>
+            <a-descriptions-item label="备注">{{ form.remark || '--' }}</a-descriptions-item>
+          </a-descriptions>
+        </a-collapse-panel>
+      </a-collapse>
+      <div class="btn-cont">
+        <a-button
+          id="merchantInfoManagement-audit"
+          size="large"
+          v-if="isAudit"
+          type="primary"
+          class="button-primary"
+          style="margin-right: 50px;"
+          @click="handleAudit">审核</a-button>
+        <a-button id="merchantInfoManagement-back" size="large" @click="isShow = false" style="font-size: 12px;">返回列表</a-button>
+      </div>
+    </div>
+    <div style="padding: 50px;text-align: center;" v-else>
+      <a-spin />
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { dealerAudit, dealerDetailBySn, dealerFindUpdateInfoBySn } from '@/api/dealer'
+export default {
+  name: 'MerchantInfoManagementModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemId: {
+      type: [Number, String],
+      default: ''
+    },
+    isAudit: Boolean
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      form: null,
+      title: ''
+    }
+  },
+  methods: {
+    // 审核
+    auditOrder (dealerAuditSn, auditState) {
+      dealerAudit({
+        dealerAuditSn,
+        auditState
+      }).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          this.$emit('ok')
+        }
+      })
+    },
+    //  审核确认
+    handleAudit () {
+      const _this = this
+      const row = this.form
+      this.$confirm({
+        title: '提示',
+        content: '请点击下方按钮确认操作?',
+        centered: true,
+        closable: true,
+        okText: '审核通过',
+        cancelText: '审核不通过',
+        onOk () {
+          _this.auditOrder(row.dealerAuditSn, 'PASS')
+        },
+        onCancel (e) {
+          if (!e.triggerCancel) {
+            _this.auditOrder(row.dealerAuditSn, 'REJECT')
+          }
+          _this.$destroyAll()
+        }
+      })
+    },
+    // 详情编辑
+    getDetail () {
+      if (this.isAudit) {
+        dealerFindUpdateInfoBySn({ sn: this.itemId }).then(res => {
+          if (res.status == 200) {
+            this.form = res.data
+          }
+        })
+      } else {
+        dealerDetailBySn({ sn: this.itemId }).then(res => {
+          if (res.status == 200) {
+            this.form = res.data
+          }
+        })
+      }
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.form = null
+      } else {
+        this.title = this.isAudit ? '审核资料' : '查看详细'
+      }
+    },
+    itemId (newValue, oldValue) {
+      if (this.isShow && newValue) {
+        this.getDetail()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .merchantInfoManagement-modal{
+    .ant-modal-body {
+      padding: 24px!important;
+    }
+    .ant-descriptions-item-label.ant-descriptions-item-colon{
+      width: 130px;
+    }
+    .merchantInfoManagement-cont-m{
+      margin-bottom: 10px;
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 30px;
+      button{
+        width: 150px;
+      }
+    }
+  }
+</style>

+ 674 - 0
src/views/dealerManagement/merchantInfoManagement/edit.vue

@@ -0,0 +1,674 @@
+<template>
+  <div class="merchantInfoManagementEdit-wrap">
+    <a-page-header :ghost="false" :backIcon="false" @back="handleBack" class="merchantInfoManagementEdit-cont">
+      <!-- 自定义的二级文字标题 -->
+      <template slot="subTitle">
+        <a id="merchantInfoManagement-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+      </template>
+    </a-page-header>
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        id="merchantInfoManagementEdit-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol">
+        <!-- 基础信息 -->
+        <a-card size="small" :bordered="false" class="merchantInfoManagementEdit-cont">
+          <a-collapse :activeKey="['1']">
+            <a-collapse-panel key="1" header="基础信息">
+              <a-row>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="经销商名称" prop="dealerName">
+                    <a-input v-model.trim="form.dealerName" id="merchantInfoManagementEdit-dealerName" :maxLength="30" allowClear placeholder="请输入经销商名称(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="经销商别名" prop="dealerAlias">
+                    <a-input v-model.trim="form.dealerAlias" id="merchantInfoManagementEdit-dealerAlias" :maxLength="30" allowClear placeholder="请输入经销商别名(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="商户类型" prop="dealerType">
+                    <v-select
+                      code="DEALER_TYPE"
+                      id="merchantInfoManagementEdit-dealerType"
+                      v-model="form.dealerType"
+                      allowClear
+                      placeholder="请选择商户类型"></v-select>
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="联系人1" prop="contact">
+                    <a-input v-model.trim="form.contact" id="merchantInfoManagementEdit-contact" :maxLength="30" allowClear placeholder="请输入联系人1(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="联系手机1" prop="contactMobile">
+                    <a-input v-model.trim="form.contactMobile" id="merchantInfoManagementEdit-contactMobile" :maxLength="11" allowClear placeholder="请输入联系手机1(最多11个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="联系角色1" prop="contactRole">
+                    <a-input v-model.trim="form.contactRole" id="merchantInfoManagementEdit-contactRole" :maxLength="30" allowClear placeholder="请输入联系角色1(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="联系电话" prop="dealerTelephone">
+                    <a-input v-model.trim="form.dealerTelephone" id="merchantInfoManagementEdit-dealerTelephone" :maxLength="13" allowClear placeholder="请输入联系电话" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
+                  <a-form-model-item label="地址" required style="margin: 0;" :label-col="{span:4}" :wrapper-col="{span:20}">
+                    <a-row :gutter="20">
+                      <!-- 地址 -->
+                      <a-col span="8">
+                        <a-form-model-item prop="provinceSn">
+                          <a-select id="merchantInfoManagementEdit-provinceSn" @change="getCityList" v-model="form.provinceSn" placeholder="请选择省">
+                            <a-select-option v-for="item in addrProvinceList" :value="item.areaSn" :key="item.areaSn + 'a'">{{ item.name }}</a-select-option>
+                          </a-select>
+                        </a-form-model-item>
+                      </a-col>
+                      <a-col span="8">
+                        <a-form-model-item prop="citySn">
+                          <a-select id="merchantInfoManagementEdit-citySn" @change="getAreaList" v-model="form.citySn" placeholder="请选择市">
+                            <a-select-option v-for="item in addrCityList" :value="item.areaSn" :key="item.areaSn + 'b'">{{ item.name }}</a-select-option>
+                          </a-select>
+                        </a-form-model-item>
+                      </a-col>
+                      <a-col span="8">
+                        <a-form-model-item prop="districtSn">
+                          <a-select id="merchantInfoManagementEdit-districtSn" @change="areaCharged" v-model="form.districtSn" placeholder="请选择区/县">
+                            <a-select-option v-for="item in addrDistrictList" :value="item.areaSn" :key="item.areaSn + 'c'">{{ item.name }}</a-select-option>
+                          </a-select>
+                        </a-form-model-item>
+                      </a-col>
+                    </a-row>
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="详细地址" prop="address">
+                    <a-input
+                      id="merchantInfoManagementEdit-address"
+                      :maxLength="60"
+                      v-model="form.address"
+                      placeholder="请输入详细地址(最多60个字符)"
+                      allowClear />
+                  </a-form-model-item>
+                </a-col>
+              </a-row>
+            </a-collapse-panel>
+          </a-collapse>
+        </a-card>
+        <!-- 公司信息 -->
+        <a-card size="small" :bordered="false" class="merchantInfoManagementEdit-cont">
+          <a-collapse>
+            <a-collapse-panel key="1" header="公司信息">
+              <a-row>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="经营方式" prop="busniessMode" help="(例:国有企业)">
+                    <a-input
+                      v-model.trim="form.busniessMode"
+                      id="merchantInfoManagementEdit-busniessMode"
+                      :maxLength="30"
+                      allowClear
+                      placeholder="请输入经营方式(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="经营项目" prop="busniessItmes">
+                    <a-input
+                      v-model.trim="form.busniessItmes"
+                      id="merchantInfoManagementEdit-busniessItmes"
+                      :maxLength="30"
+                      allowClear
+                      placeholder="请输入经营项目(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="公司规模" prop="busniessScope" help="(例:100-999人)">
+                    <a-input-number
+                      id="merchantInfoManagementEdit-busniessScope"
+                      v-model="form.busniessScope"
+                      :precision="0"
+                      :min="1"
+                      :max="999999"
+                      placeholder="请输入"
+                      style="width: 100%;" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="成立时间" prop="buildDate">
+                    <a-date-picker
+                      style="width:100%"
+                      id="merchantInfoManagementEdit-buildDate"
+                      :disabledDate="disabledDate"
+                      v-model="form.buildDate"
+                      :format="dateFormat"
+                      placeholder="请选择日期" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="一般纳税人" prop="isTaxpayer">
+                    <v-select
+                      code="FLAG"
+                      id="customerManagementEdit-isTaxpayer"
+                      v-model="form.isTaxpayer"
+                      allowClear
+                      placeholder="请选择是否"
+                    ></v-select>
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="身份证号码" prop="indentityCard">
+                    <a-input
+                      v-model.trim="form.indentityCard"
+                      id="merchantInfoManagementEdit-indentityCard"
+                      :maxLength="18"
+                      allowClear
+                      placeholder="请输入身份证号码(最多18个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="生日" prop="brithday">
+                    <a-date-picker
+                      style="width:100%"
+                      id="merchantInfoManagementEdit-brithday"
+                      :disabledDate="disabledDate"
+                      v-model="form.brithday"
+                      :format="dateFormat"
+                      placeholder="请选择日期" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="籍贯" prop="nativePlace">
+                    <a-input
+                      v-model.trim="form.nativePlace"
+                      id="merchantInfoManagementEdit-nativePlace"
+                      :maxLength="30"
+                      allowClear
+                      placeholder="请输入籍贯(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="邮箱" prop="mail">
+                    <a-input
+                      v-model.trim="form.mail"
+                      id="merchantInfoManagementEdit-mail"
+                      :maxLength="30"
+                      allowClear
+                      placeholder="请输入邮箱(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="联系人2" prop="contact2">
+                    <a-input v-model.trim="form.contact2" id="merchantInfoManagementEdit-contact2" :maxLength="30" allowClear placeholder="请输入联系人2(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="联系手机2" prop="contactMobile2">
+                    <a-input v-model.trim="form.contactMobile2" id="merchantInfoManagementEdit-contactMobile2" :maxLength="11" allowClear placeholder="请输入联系手机2(最多11个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="联系角色2" prop="contractRole2">
+                    <a-input v-model.trim="form.contractRole2" id="merchantInfoManagementEdit-contractRole2" :maxLength="30" allowClear placeholder="请输入联系角色2(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="邮政编码" prop="zipCode">
+                    <a-input v-model.trim="form.zipCode" id="merchantInfoManagementEdit-zipCode" :maxLength="6" allowClear placeholder="请输入邮政编码(最多6个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="收货人" prop="receiveContact">
+                    <a-input v-model.trim="form.receiveContact" id="merchantInfoManagementEdit-receiveContact" :maxLength="30" allowClear placeholder="请输入收货人(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="收货电话" prop="receiveMobile">
+                    <a-input v-model.trim="form.receiveMobile" id="merchantInfoManagementEdit-receiveMobile" :maxLength="13" allowClear placeholder="请输入收货电话" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
+                  <a-form-model-item label="收货地址" style="margin: 0;" :label-col="{span:4}" :wrapper-col="{span:20}">
+                    <a-row :gutter="20">
+                      <!-- 地址 -->
+                      <a-col span="8">
+                        <a-form-model-item prop="receiveProvinceSn">
+                          <a-select id="merchantInfoManagementEdit-receiveProvinceSn" @change="getCityList1" v-model="form.receiveProvinceSn" placeholder="请选择省">
+                            <a-select-option v-for="item in addrProvinceList1" :value="item.areaSn" :key="item.areaSn + 'a'">{{ item.name }}</a-select-option>
+                          </a-select>
+                        </a-form-model-item>
+                      </a-col>
+                      <a-col span="8">
+                        <a-form-model-item prop="receiveCitySn">
+                          <a-select id="merchantInfoManagementEdit-receiveCitySn" @change="getAreaList1" v-model="form.receiveCitySn" placeholder="请选择市">
+                            <a-select-option v-for="item in addrCityList1" :value="item.areaSn" :key="item.areaSn + 'b'">{{ item.name }}</a-select-option>
+                          </a-select>
+                        </a-form-model-item>
+                      </a-col>
+                      <a-col span="8">
+                        <a-form-model-item prop="receiveDistrictSn">
+                          <a-select id="merchantInfoManagementEdit-receiveDistrictSn" @change="areaCharged1" v-model="form.receiveDistrictSn" placeholder="请选择区/县">
+                            <a-select-option v-for="item in addrDistrictList1" :value="item.areaSn" :key="item.areaSn + 'c'">{{ item.name }}</a-select-option>
+                          </a-select>
+                        </a-form-model-item>
+                      </a-col>
+                    </a-row>
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="收货详细地址" prop="receiveAddress">
+                    <a-input
+                      id="merchantInfoManagementEdit-receiveAddress"
+                      :maxLength="60"
+                      v-model="form.receiveAddress"
+                      placeholder="请输入收货详细地址(最多60个字符)"
+                      allowClear />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="银行账户" prop="tradeAccountName" help="(例:张三)">
+                    <a-input
+                      v-model.trim="form.tradeAccountName"
+                      id="merchantInfoManagementEdit-tradeAccountName"
+                      :maxLength="30"
+                      allowClear
+                      placeholder="请输入银行账户(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="开户行" prop="tradeBankName" help="(例:交通银行)">
+                    <a-input
+                      v-model.trim="form.tradeBankName"
+                      id="merchantInfoManagementEdit-tradeBankName"
+                      :maxLength="30"
+                      allowClear
+                      placeholder="请输入开户行(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="银行账号" prop="tradeBankAccount" help="(例:1123 5677 1112 22342 1123)">
+                    <a-input
+                      v-model.trim="form.tradeBankAccount"
+                      id="merchantInfoManagementEdit-tradeBankAccount"
+                      :maxLength="30"
+                      allowClear
+                      placeholder="请输入银行账号(最多30个字符)" />
+                  </a-form-model-item>
+                </a-col>
+              </a-row>
+            </a-collapse-panel>
+          </a-collapse>
+        </a-card>
+        <!-- 总部信息 -->
+        <a-card size="small" :bordered="false" class="merchantInfoManagementEdit-cont">
+          <a-collapse>
+            <a-collapse-panel key="1" header="总部信息">
+              <a-row>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="箭冠汽配代码" prop="jgAutoPartsCode">
+                    <a-input
+                      id="merchantInfoManagementEdit-jgAutoPartsCode"
+                      :maxLength="30"
+                      v-model="form.jgAutoPartsCode"
+                      placeholder="请输入箭冠汽配代码(最多30个字符)"
+                      allowClear />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="门头更换日期" prop="jgDoorHeaderChangeTime">
+                    <a-date-picker
+                      style="width:100%"
+                      id="merchantInfoManagementEdit-jgDoorHeaderChangeTime"
+                      :disabledDate="disabledDate"
+                      v-model="form.jgDoorHeaderChangeTime"
+                      :format="dateFormat"
+                      placeholder="请选择日期" />
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                  <a-form-model-item label="特约价是否可见" prop="isShowSpecialPrice">
+                    <a-radio-group
+                      name="radioGroup"
+                      v-model="form.isShowSpecialPrice"
+                      :disabled="detailData&&detailData.dealerLevel == 'SPECIAL'"
+                      id="merchantInfoManagementEdit-isShowSpecialPrice" >
+                      <a-radio :value="1">是</a-radio>
+                      <a-radio :value="0">否</a-radio>
+                    </a-radio-group>
+                  </a-form-model-item>
+                </a-col>
+                <a-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
+                  <a-form-model-item label="备注" prop="remark" :label-col="{span:4}" :wrapper-col="{span:20}">
+                    <a-textarea
+                      id="merchantInfoManagementEdit-remark"
+                      :maxLength="300"
+                      v-model="form.remark"
+                      placeholder="请输入备注(最多300个字符)"
+                      allowClear />
+                  </a-form-model-item>
+                </a-col>
+              </a-row>
+            </a-collapse-panel>
+          </a-collapse>
+        </a-card>
+      </a-form-model>
+      <a-affix :offset-bottom="0">
+        <div style="text-align: center;width: 100%;background-color: #fff;padding: 12px 0;box-shadow: 0 0 20px #dcdee2;">
+          <a-button
+            type="primary"
+            class="button-primary"
+            id="merchantInfoManagementEdit-submit-btn"
+            size="large"
+            @click="handleSubmit"
+            style="padding: 0 60px;">提交</a-button>
+        </div>
+      </a-affix>
+    </a-spin>
+  </div>
+</template>
+
+<script>
+import { getArea } from '@/api/data'
+import { VSelect } from '@/components'
+import { dealerSave, dealerFindUpdateInfoBySn } from '@/api/dealer'
+import moment from 'moment'
+export default {
+  components: { VSelect },
+  data () {
+    return {
+      spinning: false,
+      formItemLayout: {
+        labelCol: {
+          span: 8
+        },
+        wrapperCol: {
+          span: 16
+        }
+      },
+      form: {
+        dealerName: '',
+        dealerAlias: '',
+        dealerType: undefined,
+        contact: '',
+        contactMobile: '',
+        provinceSn: undefined,
+        citySn: undefined,
+        districtSn: undefined,
+        address: '',
+        contactRole: '',
+        dealerTelephone: '',
+        busniessMode: '',
+        busniessItmes: '',
+        busniessScope: '',
+        buildDate: '',
+        isTaxpayer: undefined,
+        indentityCard: '',
+        brithday: '',
+        nativePlace: '',
+        mail: '',
+        contact2: '',
+        contactMobile2: '',
+        contractRole2: '',
+        zipCode: '',
+        receiveContact: '',
+        receiveMobile: '',
+        receiveProvinceSn: undefined,
+        receiveCitySn: undefined,
+        receiveDistrictSn: undefined,
+        receiveAddress: '',
+        tradeAccountName: '',
+        tradeBankName: '',
+        tradeBankAccount: '',
+        jgAutoPartsCode: '',
+        jgDoorHeaderChangeTime: '',
+        isShowSpecialPrice: 0,
+        remark: ''
+      },
+      rules: {
+        dealerName: [
+          { required: true, message: '请输入经销商名称', trigger: 'change' }
+        ],
+        dealerAlias: [
+          { required: true, message: '请输入经销商别名', trigger: 'change' }
+        ],
+        dealerType: [
+          { required: true, message: '请选择商户类型', trigger: 'change' }
+        ],
+        contact: [
+          { required: true, message: '请输入联系人1', trigger: 'change' }
+        ],
+        contactMobile: [
+          { required: true, message: '请输入联系手机1', trigger: 'change' },
+          { pattern: /^[1][0-9]{10}$/, message: '请输入正确的手机号码!' }
+        ],
+        provinceSn: [
+          { required: true, message: '请选择省', trigger: 'change' }
+        ],
+        citySn: [
+          { required: true, message: '请选择市', trigger: 'change' }
+        ],
+        districtSn: [
+          { required: true, message: '请选择区县', trigger: 'change' }
+        ],
+        address: [
+          { required: true, message: '请输入详细地址', trigger: 'change' }
+        ],
+        dealerTelephone: [
+          { pattern: /^[0-9-]{11,13}$/, message: '请输入正确的电话号码!' }
+        ],
+        contactMobile2: [
+          { pattern: /^[1][0-9]{10}$/, message: '请输入正确的手机号码!' }
+        ],
+        receiveMobile: [
+          { pattern: /^[0-9-]{11,13}$/, message: '请输入正确的电话号码!' }
+        ],
+        indentityCard: [
+          { pattern: /^[0-9a-zA-Z]{15,18}$/, message: '请输入15-18位证件号码' }
+        ],
+        zipCode: [
+          { pattern: /^[1-9][0-9]{5}$/, message: '请输入正确的邮政编码' }
+        ],
+        mail: [
+          { type: 'email', message: '请输入正确的邮箱' }
+        ],
+        tradeBankAccount: [
+          { pattern: /^[0-9a-zA-Z]{16,30}$/, message: '请输入正确银行卡号' }
+        ]
+      },
+      addrProvinceList: [], //  省下拉
+      addrCityList: [], //  市下拉
+      addrDistrictList: [], //  区下拉
+      addrProvinceList1: [], //  省下拉
+      addrCityList1: [], //  市下拉
+      addrDistrictList1: [], //  区下拉
+      dateFormat: 'YYYY-MM-DD',
+      detailData: null
+    }
+  },
+  methods: {
+    // 不可选日期
+    disabledDate (date, dateStrings) {
+      return date && date.valueOf() > Date.now()
+    },
+    // 详情编辑
+    getDetail () {
+      dealerFindUpdateInfoBySn({ sn: this.$route.params.id }).then(res => {
+        if (res.status == 200) {
+          this.detailData = res.data
+          this.form = Object.assign(this.form, res.data)
+          this.form.isShowSpecialPrice = Number(this.form.isShowSpecialPrice)
+          if (this.form.provinceSn) {
+            this.getArea('city', this.form.provinceSn, 0)
+          }
+          if (this.form.citySn) {
+            this.getArea('district', this.form.citySn, 0)
+          }
+          if (this.form.receiveProvinceSn) {
+            this.getArea('city', this.form.receiveProvinceSn, 1)
+          }
+          if (this.form.receiveCitySn) {
+            this.getArea('district', this.form.receiveCitySn, 1)
+          }
+        }
+      })
+    },
+    // 提交
+    handleSubmit () {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          // console.log(this.form, 'form data')
+          const params = JSON.parse(JSON.stringify(_this.form))
+          params.buildDate = params.buildDate ? moment(params.buildDate).format('YYYY-MM-DD hh:mm:ss') : ''
+          params.brithday = params.brithday ? moment(params.brithday).format('YYYY-MM-DD hh:mm:ss') : ''
+          params.cooperateEffectiveTime = params.cooperateEffectiveTime ? moment(params.cooperateEffectiveTime).format('YYYY-MM-DD hh:mm:ss') : ''
+          params.jgDoorHeaderChangeTime = params.jgDoorHeaderChangeTime ? moment(params.jgDoorHeaderChangeTime).format('YYYY-MM-DD hh:mm:ss') : ''
+          _this.spinning = true
+          dealerSave(params).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.handleBack()
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        } else {
+          return false
+        }
+      })
+    },
+    // 返回
+    handleBack () {
+      this.$router.push({ name: 'merchantInfoManagementList' })
+    },
+    // 获取城市列表
+    getCityList (val) {
+      const index = this.addrProvinceList.findIndex(item => item.areaSn == val)
+      if (index >= 0) {
+        this.form.provinceName = this.addrProvinceList[index].name
+      }
+      this.addrCityList = []
+      this.addrDistrictList = []
+      this.form.citySn = undefined
+      this.form.districtSn = undefined
+      this.form.address = ''
+      this.getArea('city', val, 0)
+    },
+    // 获取区县列表
+    getAreaList (val) {
+      const index = this.addrCityList.findIndex(item => item.areaSn == val)
+      if (index >= 0) {
+        this.form.cityName = this.addrCityList[index].name
+      }
+      this.addrDistrictList = []
+      this.form.districtSn = undefined
+      this.form.address = ''
+      this.getArea('district', val, 0)
+    },
+    // 区县变更
+    areaCharged (val) {
+      const index = this.addrDistrictList.findIndex(item => item.areaSn == val)
+      if (index >= 0) {
+        this.form.districtName = this.addrDistrictList[index].name
+      }
+      this.form.address = ''
+    },
+    // 获取城市列表
+    getCityList1 (val) {
+      const index = this.addrProvinceList1.findIndex(item => item.areaSn == val)
+      if (index >= 0) {
+        this.form.receiveProvinceName = this.addrProvinceList1[index].name
+      }
+      this.addrCityList1 = []
+      this.addrDistrictList1 = []
+      this.form.receiveCitySn = undefined
+      this.form.receiveDistrictSn = undefined
+      this.form.receiveAddress = ''
+      this.getArea('city', val, 1)
+    },
+    // 获取区县列表
+    getAreaList1 (val) {
+      const index = this.addrCityList1.findIndex(item => item.areaSn == val)
+      if (index >= 0) {
+        this.form.receiveCityName = this.addrCityList1[index].name
+      }
+      this.addrDistrictList1 = []
+      this.form.receiveDistrictSn = undefined
+      this.form.receiveAddress = ''
+      this.getArea('district', val, 1)
+    },
+    // 区县变更
+    areaCharged1 (val) {
+      const index = this.addrDistrictList1.findIndex(item => item.areaSn == val)
+      if (index >= 0) {
+        this.form.receiveDistrictName = this.addrDistrictList1[index].name
+      }
+      this.form.receiveAddress = ''
+    },
+    //  省/市/区
+    getArea (leve, sn, index) {
+      let params
+      if (leve == 'province') {
+        params = { type: '2' }
+      } else {
+        params = { parentId: sn, type: leve == 'city' ? '3' : '4' }
+      }
+      getArea(params).then(res => {
+        if (res.status == 200) {
+          if (leve == 'province') {
+            this.addrProvinceList = JSON.parse(JSON.stringify(res.data || []))
+            this.addrProvinceList1 = JSON.parse(JSON.stringify(res.data || []))
+          } else if (leve == 'city') {
+            this.addrCityList = JSON.parse(JSON.stringify(res.data || []))
+            if (index == 1) {
+              this.addrCityList1 = JSON.parse(JSON.stringify(res.data || []))
+            }
+          } else if (leve == 'district') {
+            this.addrDistrictList = JSON.parse(JSON.stringify(res.data || []))
+            if (index == 1) {
+              this.addrDistrictList1 = JSON.parse(JSON.stringify(res.data || []))
+            }
+          }
+        } else {
+          if (leve == 'province') {
+            this.addrProvinceList = []
+            this.addrProvinceList1 = []
+          } else if (leve == 'city') {
+            this.addrCityList = []
+            if (index == 1) {
+              this.addrCityList1 = []
+            }
+          } else if (leve == 'district') {
+            this.addrDistrictList = []
+            if (index == 1) {
+              this.addrDistrictList1 = []
+            }
+          }
+        }
+      })
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.getArea('province')
+      vm.$refs.ruleForm.resetFields()
+      if (vm.$route.params.id) { //  编辑页
+        vm.getDetail()
+      }
+    })
+  }
+}
+</script>
+
+<style lang="less">
+  .merchantInfoManagementEdit-wrap{
+    .merchantInfoManagementEdit-cont{
+      margin-bottom: 10px;
+    }
+  }
+</style>

+ 260 - 0
src/views/dealerManagement/merchantInfoManagement/list.vue

@@ -0,0 +1,260 @@
+<template>
+  <a-card size="small" :bordered="false" class="merchantInfoManagementList-wrap">
+    <!-- 搜索条件 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
+        <a-row :gutter="15">
+          <a-col :md="6" :sm="24">
+            <a-form-item label="区域">
+              <subarea id="merchantInfoManagementList-subarea" v-model="queryParam.subareaSn"></subarea>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="商户名称/别名">
+              <a-input id="merchantInfoManagementList-nameLike" v-model.trim="queryParam.nameLike" allowClear placeholder="请输入商户名称/别名"/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="商户类型">
+              <v-select code="DEALER_TYPE" id="merchantInfoManagementList-dealerType" v-model="queryParam.dealerType" allowClear placeholder="请选择商户类型"></v-select>
+            </a-form-item>
+          </a-col>
+          <template v-if="advanced">
+            <a-col :md="6" :sm="24">
+              <a-form-item label="审核状态">
+                <v-select code="AUDIT_STATE" id="merchantInfoManagementList-auditState" v-model="queryParam.auditState" allowClear placeholder="请选择审核状态"></v-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="合作状态">
+                <v-select code="DEALER_COOPERATE_FLAG" id="merchantInfoManagementList-cooperateFlag" v-model="queryParam.cooperateFlag" allowClear placeholder="请选择合作状态"></v-select>
+              </a-form-item>
+            </a-col>
+          </template>
+          <a-col :md="6" :sm="24">
+            <a-button style="margin-bottom: 18px;" type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="merchantInfoManagementList-refresh">查询</a-button>
+            <a-button style="margin: 0 0 18px 5px" @click="resetSearchForm" :disabled="disabled" id="merchantInfoManagementList-reset">重置</a-button>
+            <a-button
+              style="margin-left: 5px"
+              type="primary"
+              class="button-warning"
+              @click="handleExport"
+              :disabled="disabled"
+              :loading="exportLoading"
+              id="merchantInfoManagementList-export">导出</a-button>
+            <a @click="advanced=!advanced" style="margin-left: 8px">
+              {{ advanced ? '收起' : '展开' }}
+              <a-icon :type="advanced ? 'up' : 'down'"/>
+            </a>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 操作按钮 -->
+    <div class="table-operator">
+      <a-button id="merchantInfoManagementList-add" type="primary" class="button-error" @click="handleAdd">新增</a-button>
+    </div>
+    <!-- 总计 -->
+    <a-alert type="info" showIcon style="margin-bottom:15px">
+      <div slot="message">合计:<strong>{{ total }}</strong>条</div>
+    </a-alert>
+    <!-- 列表 -->
+    <s-table
+      class="sTable"
+      ref="table"
+      size="default"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :data="loadData"
+      :scroll="{ x: 2240, y: tableHeight }"
+      bordered>
+      <!-- 经销商 -->
+      <template slot="dealerName" slot-scope="text, record">
+        <span style="color: #ed1c24;cursor: pointer;" @click="handleDetail(record)">{{ record.dealerName }}</span>
+      </template>
+      <!-- 区域 -->
+      <template slot="area" slot-scope="text, record">
+        <div v-if="record.subareaNameSet&&record.subareaNameSet.length!=0">
+          <span v-for="(item, index) in record.subareaNameSet" :key="index">{{ item }}{{ index+1 == record.subareaNameSet.length ? '' : ',' }}</span>
+        </div>
+        <span v-else>--</span>
+      </template>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-button size="small" type="link" class="button-warning" v-if="record.auditState == 'WAIT'" @click="handleAudit(record)" >审核</a-button>
+        <a-button size="small" type="link" class="button-success" @click="handleCooperation(record)" >合作设置</a-button>
+        <a-button size="small" type="link" class="button-error" v-if="record.auditState != 'WAIT'" @click="handleDistribution(record)">经销权</a-button>
+        <a-button size="small" type="link" class="button-primary" @click="handleLevel(record)">级别设置</a-button>
+        <a-button size="small" type="link" class="button-info" @click="handleEdit(record)">编辑</a-button>
+      </template>
+    </s-table>
+    <!-- 产品详情 -->
+    <merchant-info-management-detail-modal :openModal="openModal" :isAudit="isAudit" :itemId="itemId" @ok="resetForm" @close="closeModal" />
+    <!-- 合作设置 -->
+    <UpdateCooperate ref="updateCooperate" :openUcModal="openUcModal" @ok="resetForm" @close="openUcModal=false"></UpdateCooperate>
+    <!-- 级别设置 -->
+    <UpdateDealerLeve ref="updateDealerLevel" :openUdModal="openUdModal" @ok="resetForm" @close="openUdModal=false"></UpdateDealerLeve>
+  </a-card>
+</template>
+
+<script>
+import moment from 'moment'
+import { dealerQueryList, dealerExport } from '@/api/dealer'
+import { STable, VSelect } from '@/components'
+import subarea from '@/views/common/subarea.js'
+import merchantInfoManagementDetailModal from './detailModal.vue'
+import UpdateCooperate from './updateCooperate.vue'
+import UpdateDealerLeve from './updateDealerLevel.vue'
+export default {
+  components: { STable, VSelect, merchantInfoManagementDetailModal, subarea, UpdateCooperate, UpdateDealerLeve },
+  data () {
+    return {
+      advanced: false, // 高级搜索 展开/关闭
+      tableHeight: 0,
+      queryParam: { //  查询条件
+        nameLike: '', //  商户名称、别名
+        dealerType: undefined, //  商户类型
+        subareaSn: undefined, //  区域
+        auditState: undefined, // 审核状态
+        cooperateFlag: undefined //  合作状态
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      exportLoading: false, // 导出loading
+      dateFormat: 'YYYY-MM-DD',
+      total: 0,
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '创建时间', dataIndex: 'createDate', width: 160, align: 'center' },
+        { title: '区域', scopedSlots: { customRender: 'area' }, width: 200, align: 'center' },
+        { title: '商户名称', scopedSlots: { customRender: 'dealerName' }, align: 'center', ellipsis: true },
+        { title: '商户别名', dataIndex: 'dealerAlias', width: 200, align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '商户类型', dataIndex: 'dealerTypeDictValue', width: 140, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '商户级别', dataIndex: 'dealerLevelDictValue', width: 140, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '联系人', dataIndex: 'contact', width: 200, align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '联系电话', dataIndex: 'dealerTelephone', width: 140, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '绑定手机号码', dataIndex: 'managerMobile', width: 120, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '审核状态', dataIndex: 'auditStateDictValue', width: 120, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '合作状态', dataIndex: 'cooperateFlagDictValue', width: 120, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '生效时间', dataIndex: 'cooperateEffectiveTime', width: 160, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 240, align: 'center', fixed: 'right' }
+      ],
+      loading: false,
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        if (this.tableHeight == 0) {
+          this.tableHeight = window.innerHeight - 440
+        }
+        return dealerQueryList(Object.assign(parameter, this.queryParam)).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          this.total = data.count
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.disabled = false
+          return data
+        })
+      },
+      openModal: false, //  查看详情  弹框
+      openUcModal: false, // 合作设置 弹框
+      openUdModal: false, // 级别设置 弹框
+      itemId: '', //  当前商户sn
+      isAudit: false
+    }
+  },
+  methods: {
+    //  重置列表
+    resetSearchForm () {
+      this.queryParam = {
+        nameLike: '', //  商户名称、别名
+        dealerType: undefined, //  商户类型
+        subareaSn: undefined, //  区域
+        auditState: undefined, // 审核状态
+        cooperateFlag: undefined //  合作状态
+      }
+      this.$refs.table.refresh(true)
+    },
+    // 刷新当前列表
+    resetForm () {
+      this.$refs.table.refresh()
+      this.openModal = false
+      this.isAudit = false
+      this.openUcModal = false
+      this.openUdModal = false
+    },
+    // 新增
+    handleAdd () {
+      this.$router.push({ name: `merchantInfoManagementAdd` })
+    },
+    // 编辑
+    handleEdit (row) {
+      this.$router.push({ name: `merchantInfoManagementEdit`, params: { id: row.dealerSn } })
+    },
+    // 合作设置
+    handleCooperation (row) {
+      this.openUcModal = true
+      this.$refs.updateCooperate.setData(row)
+    },
+    // 价格级别
+    handleLevel (row) {
+      this.openUdModal = true
+      this.$refs.updateDealerLevel.setData(row)
+    },
+    // 经销权
+    handleDistribution (row) {
+      this.$router.push({ name: `merchantInfoManagementSet`, params: { sn: row.dealerSn } })
+    },
+    // 审核
+    handleAudit (row) {
+      this.itemId = row.dealerSn
+      this.openModal = true
+      this.isAudit = true
+    },
+    //  详情
+    handleDetail (row) {
+      this.itemId = row.dealerSn
+      this.openModal = true
+      this.isAudit = false
+    },
+    //  关闭弹框
+    closeModal () {
+      this.itemId = ''
+      this.openModal = false
+    },
+    //  导出
+    handleExport () {
+      const params = this.queryParam
+      this.exportLoading = true
+      dealerExport(params).then(res => {
+        this.exportLoading = false
+        this.download(res)
+      })
+    },
+    download (data) {
+      if (!data) { return }
+      const url = window.URL.createObjectURL(new Blob([data]))
+      const link = document.createElement('a')
+      link.style.display = 'none'
+      link.href = url
+      const a = moment().format('YYYYMMDDHHmmss')
+      const fname = '经销商资料' + a
+      link.setAttribute('download', fname + '.xlsx')
+      document.body.appendChild(link)
+      link.click()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+    })
+  }
+}
+</script>
+
+<style lang="less">
+  .merchantInfoManagementList-wrap{
+    .productPic{
+      cursor: pointer;
+    }
+  }
+</style>

+ 328 - 0
src/views/dealerManagement/merchantInfoManagement/permissionSetting.vue

@@ -0,0 +1,328 @@
+<template>
+  <div class="permissionSetting-wrap">
+    <a-page-header :ghost="false" :backIcon="false" @back="handleBack" class="permissionSetting-cont">
+      <!-- 自定义的二级文字标题 -->
+      <template slot="subTitle">
+        <a id="permissionSetting-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+      </template>
+    </a-page-header>
+    <a-card size="small" :bordered="false" class="permissionSetting-main">
+      <!-- 搜索条件 -->
+      <div class="table-page-search-wrapper">
+        <a-form-model
+          id="permissionSetting-form"
+          ref="ruleForm"
+          :model="queryParam"
+          :rules="rules"
+          layout="inline"
+          @keyup.enter.native="handleSearch">
+          <a-row :gutter="15">
+            <a-col :md="6" :sm="24">
+              <a-form-model-item label="类型" prop="goodsType">
+                <v-select code="DEALER_GOODS_TYPE" id="permissionSetting-goodsType" v-model="queryParam.goodsType" allowClear placeholder="请选择类型"></v-select>
+              </a-form-model-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-model-item label="类型名称" prop="goodsName">
+                <a-input id="permissionSetting-goodsName" v-model.trim="queryParam.goodsName" allowClear placeholder="请输入类型名称"/>
+              </a-form-model-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-model-item label="产品编码" prop="goodsCode">
+                <a-input id="permissionSetting-goodsCode" v-model.trim="queryParam.goodsCode" allowClear placeholder="请输入产品编码"/>
+              </a-form-model-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-button style="margin-bottom: 18px;" type="primary" @click="handleSearch" :disabled="disabled" id="permissionSetting-refresh">查询</a-button>
+              <a-button style="margin: 0 0 18px 8px" @click="resetSearchForm" :disabled="disabled" id="permissionSetting-reset">重置</a-button>
+            </a-col>
+          </a-row>
+        </a-form-model>
+      </div>
+      <!-- 操作按钮 -->
+      <div class="table-operator">
+        <a-button id="permissionSetting-brand" type="primary" class="button-error" @click="choosePModal('BRAND')">选择产品品牌</a-button>
+        <a-button id="permissionSetting-type" type="primary" class="button-info" @click="choosePModal('CATEGORY')">选择产品分类</a-button>
+        <a-button id="permissionSetting-product" type="primary" class="button-success" @click="choosePModal('PRODUCT')">选择产品</a-button>
+      </div>
+      <!-- 列表 -->
+      <a-table
+        class="sTable"
+        ref="table"
+        size="small"
+        :rowKey="(record) => record.id"
+        :columns="columns"
+        :data-source="loadData"
+        :pagination="paginationProps"
+        :loading="loading"
+        :scroll="{ x: 1200, y: tableHeight }"
+        bordered>
+        <!-- 操作 -->
+        <template slot="action" slot-scope="text, record">
+          <a-button size="small" type="link" class="button-error" @click="handleDel(record)">删除</a-button>
+        </template>
+      </a-table>
+    </a-card>
+    <!-- 选择产品品牌 -->
+    <chooseBrandModal :openModal="openBrandModal" :chooseData="chooseBrand" @close="openBrandModal=false" @ok="handleBrandOk" />
+    <!-- 选择产品分类 -->
+    <chooseTypeModal :openModal="openTypeModal" :chooseData="chooseType" @close="openTypeModal=false" @ok="handleTypeOk" />
+    <!-- 选择产品 -->
+    <chooseProductsModal
+      type="dealership"
+      :dealerSn="$route.params.sn"
+      :openModal="openProductsModal"
+      :chooseData="chooseProducts"
+      @close="openProductsModal=false"
+      @ok="handleProductsOk" />
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import ChooseProductsModal from '@/views/common/chooseProductsModal.vue'
+import ChooseBrandModal from '@/views/common/chooseBrandModal.vue'
+import ChooseTypeModal from '@/views/common/chooseTypeModal.vue'
+import { dealerScopeList, dealerScopeSave, dealerScopeDel, dealerScopeQueryList } from '@/api/dealerScope'
+export default {
+  components: { STable, VSelect, ChooseProductsModal, ChooseBrandModal, ChooseTypeModal },
+  data () {
+    return {
+      advanced: false, // 高级搜索 展开/关闭
+      tableHeight: 0,
+      queryParam: { //  查询条件
+        goodsType: undefined,
+        goodsName: '',
+        goodsCode: ''
+      },
+      rules: {
+        goodsType: [ { required: true, message: '请选择类型', trigger: 'change' } ]
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      loading: false, //  表格加载中
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '添加时间', dataIndex: 'createDate', width: 160, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '类型', dataIndex: 'type', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '类型名称', dataIndex: 'goodsName', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '产品名称', dataIndex: 'product.name', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '产品编码', dataIndex: 'product.code', width: 220, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 100, align: 'center', fixed: 'right' }
+      ],
+      loadData: [],
+      pageNo: 1, //  分页页码
+      pageSize: 10, //  分页 每页多少条
+      paginationProps: {
+        showSizeChanger: true, //  是否可以改变 pageSize
+        total: 0, //  分页总条数
+        current: 1,
+        onShowSizeChange: (current, pageSize) => this.changePageSize(current, pageSize),
+        onChange: (current) => this.changePage(current)
+      },
+      openBrandModal: false, //  选择产品品牌
+      openTypeModal: false, //  选择产品分类
+      openProductsModal: false, //  选择产品
+      chooseBrand: [], //  所选品牌
+      chooseProducts: [], //  所选产品
+      chooseType: [] //  所选分类
+    }
+  },
+  methods: {
+    // 查询
+    handleSearch () {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          _this.getProductList(1)
+        } else {
+          return false
+        }
+      })
+    },
+    // 经销权 列表
+    getProductList (pageNo) {
+      this.pageNo = pageNo || this.pageNo
+      this.disabled = true
+      if (this.tableHeight == 0) {
+        this.tableHeight = window.innerHeight - 380
+      }
+      const params = {
+        pageNo: this.pageNo,
+        pageSize: this.pageSize
+      }
+      this.loading = true
+      dealerScopeList(Object.assign(params, this.queryParam, { dealerSn: this.$route.params.sn })).then(res => {
+        this.loading = false
+        if (res.status == 200) {
+          const data = res.data
+          this.paginationProps.total = Number(res.data.count) || 0
+          this.paginationProps.current = data.pageNo
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+            const goodsType = data.list[i].goodsType
+            data.list[i].type = goodsType == 'PRODUCT' ? '产品' : goodsType == 'BRAND' ? '品牌' : goodsType == 'CATEGORY' ? '分类' : '--'
+          }
+          this.loadData = data.list
+          this.disabled = false
+        } else {
+          this.paginationProps.total = 0
+          this.paginationProps.current = 1
+          this.loadData = []
+        }
+      })
+    },
+    //  分页  一页多少条change
+    changePageSize (current, pageSize) {
+      this.pageNo = current
+      this.pageSize = pageSize
+      this.getProductList()
+    },
+    //  分页 页码change
+    changePage (current) {
+      this.pageNo = current
+      this.getProductList()
+    },
+    // 选择产品
+    choosePModal (type) {
+      const productList = []
+      const brandList = []
+      const typeList = []
+      dealerScopeQueryList({ dealerSn: this.$route.params.sn, goodsType: type }).then(res => {
+        if (res.status == 200) {
+          const data = res.data
+          data.map(item => {
+            if (item.goodsType == 'PRODUCT') {
+              productList.push(item)
+            } else if (item.goodsType == 'BRAND') {
+              brandList.push(item)
+            } else if (item.goodsType == 'CATEGORY') {
+              typeList.push(item)
+            }
+          })
+          if (type == 'PRODUCT') { //  选择产品
+            // this.chooseProducts = productList  //  包含先前所选产品
+            this.chooseProducts = [] //  不包含先前所选产品
+            this.openProductsModal = true
+          } else if (type == 'BRAND') { //  选择品牌
+            this.chooseBrand = brandList
+            this.openBrandModal = true
+          } else if (type == 'CATEGORY') { //  选择分类
+            this.chooseType = typeList
+            this.openTypeModal = true
+          }
+        }
+      })
+    },
+    // 品牌
+    handleBrandOk (obj) {
+      this.chooseBrand = obj
+      this.changeData('BRAND')
+    },
+    // 产品
+    handleProductsOk (obj) {
+      this.chooseProducts = obj
+      this.changeData('PRODUCT')
+    },
+    // 分类
+    handleTypeOk (obj) {
+      this.chooseType = obj
+      this.changeData('CATEGORY')
+    },
+    changeData (type) {
+      const _this = this
+      if (type == 'PRODUCT') { //  选择产品
+        if (_this.chooseProducts.length > 0) {
+          const snList = []
+          _this.chooseProducts.map(item => {
+            const productSn = item.productSn ? item.productSn : item.product.productSn ? item.product.productSn : ''
+            snList.push(productSn)
+          })
+          this.setData(snList, type)
+        }
+      } else if (type == 'BRAND') { //  选择品牌
+        if (_this.chooseBrand.length > 0) {
+          const snList = []
+          _this.chooseBrand.map(item => {
+            snList.push(item.brandSn)
+          })
+          this.setData(snList, type)
+        }
+      } else if (type == 'CATEGORY') { //  选择分类
+        if (_this.chooseType.length > 0) {
+          const snList = []
+          _this.chooseType.map(item => {
+            snList.push(item.productTypeSn)
+          })
+          this.setData(snList, type)
+        }
+      }
+    },
+    // 添加经销权
+    setData (snList, type) {
+      const _this = this
+      const params = {
+        dealerSn: _this.$route.params.sn,
+        goodsType: type,
+        goodsSnList: snList
+      }
+      dealerScopeSave(params).then(res => {
+        if (res.status == 200) {
+          _this.$message.success(res.message)
+          _this.getProductList(1)
+        }
+      })
+    },
+    // 删除
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认要删除吗?',
+        centered: true,
+        onOk () {
+          dealerScopeDel({ sn: row.dealerScopeSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.getProductList()
+            }
+          })
+        }
+      })
+    },
+    // 重置表单
+    resetSearchForm () {
+      this.queryParam.goodsType = undefined
+      this.queryParam.goodsName = ''
+      this.queryParam.goodsCode = ''
+      this.pageNo = 1
+      this.pageSize = 10
+      this.paginationProps.total = 0
+      this.paginationProps.current = 1
+      this.getProductList(1)
+    },
+    // 返回
+    handleBack () {
+      this.$router.push({ name: 'merchantInfoManagementList' })
+    },
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.getProductList(1)
+    })
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .permissionSetting-wrap{
+    .permissionSetting-cont{
+      margin-bottom: 10px;
+    }
+  }
+</style>

部分文件因为文件数量过多而无法显示