فهرست منبع

Merge branch 'deploy' of jianguan-web/qpls-it-html into master

陈瑞 4 سال پیش
والد
کامیت
a6232b5ee6
49فایلهای تغییر یافته به همراه4826 افزوده شده و 1083 حذف شده
  1. 2 2
      .env
  2. 1 1
      .env.development
  3. 2 2
      .env.preview
  4. 47 0
      public/adapter.js
  5. 50 0
      public/index.html
  6. 12 0
      src/api/dealer.js
  7. 0 28
      src/api/dealerProductType.js
  8. 47 0
      src/api/linkageGroup.js
  9. 86 0
      src/api/menu.js
  10. 30 0
      src/api/mould.js
  11. 224 2
      src/components/global.less
  12. 3 3
      src/components/tools/UserMenu.vue
  13. 1 1
      src/config/defaultSettings.js
  14. 225 169
      src/config/router.config.js
  15. 1 2
      src/layouts/BasicLayout.vue
  16. 8 10
      src/permission.js
  17. 1 0
      src/store/getters.js
  18. 8 0
      src/store/modules/user.js
  19. 3 1
      src/utils/mixin.js
  20. 2 3
      src/utils/request.js
  21. 32 3
      src/views/Home.vue
  22. 461 0
      src/views/bnSetting/menu/adminMenus.vue
  23. 346 0
      src/views/bnSetting/menu/childModal.vue
  24. 498 0
      src/views/bnSetting/menu/storeMenus.vue
  25. 162 0
      src/views/bnSetting/menusAuth.vue
  26. 41 0
      src/views/bnSetting/menusAuthTab.vue
  27. 151 0
      src/views/chainGroupManagement/chainGroupSetting/associateModal.vue
  28. 172 0
      src/views/chainGroupManagement/chainGroupSetting/editModal.vue
  29. 248 0
      src/views/chainGroupManagement/chainGroupSetting/list.vue
  30. 116 0
      src/views/chainGroupManagement/chainGroupSetting/storeModal.vue
  31. 69 0
      src/views/common/custList.vue
  32. 0 54
      src/views/common/editInput.js
  33. 423 0
      src/views/power/job/jobs.vue
  34. 306 0
      src/views/power/menu/childModal.vue
  35. 462 0
      src/views/power/menu/menu.vue
  36. 71 0
      src/views/power/menuMould/list.vue
  37. 174 0
      src/views/power/menuMould/setModal.vue
  38. 10 17
      src/views/power/role/menuModal.vue
  39. 1 1
      src/views/power/role/roleList.vue
  40. 10 21
      src/views/power/role/roleModal.vue
  41. 54 106
      src/views/power/user/userList.vue
  42. 114 191
      src/views/power/user/userModal.vue
  43. 0 146
      src/views/productManagement/productCategory/editModal.vue
  44. 0 170
      src/views/productManagement/productCategory/list.vue
  45. 10 143
      src/views/user/ChangePwd.vue
  46. 1 1
      src/views/user/Login.vue
  47. 4 4
      src/views/user/Register.vue
  48. 135 0
      src/views/user/ResetPwd.vue
  49. 2 2
      vue.config.js

+ 2 - 2
.env

@@ -1,9 +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://qpls-it.360arrow.com/qpls-it
 VUE_APP_VERSION=V1.0.1
 VUE_APP_PRO_NAME=箭冠汽配IT系统
 VUE_APP_LOGO=@/assets/logo.png
-VUE_APP_THEME_COLOR=#ff0000
+VUE_APP_THEME_COLOR=#ed1c24
 VUE_APP_COM_NAME=广州市箭冠网络科技有限公司
 VUE_APP_ICP=粤ICP备10216726号

+ 1 - 1
.env.development

@@ -4,6 +4,6 @@ VUE_APP_API_BASE_URL=/api
 VUE_APP_VERSION=V1.0.1
 VUE_APP_PRO_NAME=箭冠汽配IT系统-dev
 VUE_APP_LOGO=@/assets/logo.png
-VUE_APP_THEME_COLOR=#ff0000
+VUE_APP_THEME_COLOR=#ed1c24
 VUE_APP_COM_NAME=广州市箭冠网络科技有限公司
 VUE_APP_ICP=粤ICP备10216726号

+ 2 - 2
.env.preview

@@ -1,9 +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://qpls-it.360arrow.com.cn/qpls-it
 VUE_APP_VERSION=V1.0.1
 VUE_APP_PRO_NAME=箭冠汽配IT系统-pre
 VUE_APP_LOGO=@/assets/logo.png
-VUE_APP_THEME_COLOR=#ff0000
+VUE_APP_THEME_COLOR=#ed1c24
 VUE_APP_COM_NAME=广州市箭冠网络科技有限公司
 VUE_APP_ICP=粤ICP备10216726号

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

+ 12 - 0
src/api/dealer.js

@@ -0,0 +1,12 @@
+import { axios } from '@/utils/request'
+//  经销商 列表 有分页
+export const dealerList = (params) => {
+  const url = `/dealer/queryLike/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}

+ 0 - 28
src/api/dealerProductType.js

@@ -1,28 +0,0 @@
-import { axios } from '@/utils/request'
-
-//  产品类别列表  无分页
-export const dealerProductTypeQuery = (params) => {
-  const url = `/dealerProductType/query`
-  return axios({
-    url: url,
-    data: params,
-    method: 'post'
-  })
-}
-
-// 新增/编辑产品类别
-export const dealerProductTypeSave = params => {
-  return axios({
-    url: '/dealerProductType/save',
-    data: params,
-    method: 'post'
-  })
-}
-
-// 删除产品类别
-export const dealerProductTypeDel = params => {
-  return axios({
-    url: `/dealerProductType/delete/${params.id}`,
-    method: 'get'
-  })
-}

+ 47 - 0
src/api/linkageGroup.js

@@ -0,0 +1,47 @@
+import { axios } from '@/utils/request'
+
+//  连锁组 列表  分页
+export const linkageGroupList = (params) => {
+  const url = `/linkageGroup/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  连锁组 保存
+export const linkageGroupSave = (params) => {
+  return axios({
+    url: '/linkageGroup/save',
+    data: params,
+    method: 'post'
+  })
+}
+//  连锁组 详情
+export const linkageGroupDetail = (params) => {
+  const url = `/linkageGroup/queryDetail/${params.sn}`
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  连锁组 关联
+export const linkageGroupRelation = (params) => {
+  return axios({
+    url: '/linkageGroup/relation',
+    data: params,
+    method: 'post'
+  })
+}
+//  连锁组 取消关联
+export const linkageGroupUnRelation = (params) => {
+  const url = `/linkageGroup/unRelation/${params.sn}`
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}

+ 86 - 0
src/api/menu.js

@@ -0,0 +1,86 @@
+import { axios } from '@/utils/request'
+
+// 获取菜单树数据
+export const getMenuList = params => {
+  const url = `/menu/findAll`
+  return axios({
+    url: url,
+    data: params,
+    method: 'POST'
+  })
+}
+
+// 保存
+export const saveMenu = params => {
+  const url = `/menu/save`
+  return axios({
+    url: url,
+    data: params,
+    method: 'POST'
+  })
+}
+
+// 删除
+export const deleteMenu = params => {
+  const url = `/menu/delete/${params.id}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}
+
+// 获取门店菜单树数据
+export const getMdMenuList = params => {
+  const url = `/mdmenu/findAll`
+  return axios({
+    url: url,
+    data: params,
+    method: 'POST'
+  })
+}
+
+// 门店菜单保存
+export const saveMdMenu = params => {
+  const url = `/mdmenu/save`
+  return axios({
+    url: url,
+    data: params,
+    method: 'POST'
+  })
+}
+// 门店菜单删除
+export const deleteMdMenu = params => {
+  const url = `/mdmenu/delete/${params.id}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}
+
+// 获取运营菜单树数据
+export const getYyMenuList = params => {
+  const url = `/yymenu/findAll`
+  return axios({
+    url: url,
+    data: params,
+    method: 'POST'
+  })
+}
+
+// 运营菜单保存
+export const saveYyMenu = params => {
+  const url = `/yymenu/save`
+  return axios({
+    url: url,
+    data: params,
+    method: 'POST'
+  })
+}
+// 运营菜单删除
+export const deleteYyMenu = params => {
+  const url = `/yymenu/delete/${params.id}`
+  return axios({
+    url: url,
+    method: 'get'
+  })
+}

+ 30 - 0
src/api/mould.js

@@ -0,0 +1,30 @@
+import { axios } from '@/utils/request'
+
+//  菜单模板 列表  分页
+export const mouldList = (params) => {
+  const url = `/mould/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  菜单模板 保存
+export const findMouldMenuSave = (params) => {
+  return axios({
+    url: '/mould/saveMouldMenu',
+    data: params,
+    method: 'post'
+  })
+}
+//  菜单模板 详情
+export const findMouldMenuDetail = (params) => {
+  const url = `/mould/findMouldMenu/${params.id}/${params.appType}`
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}

+ 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;
+  }
+}

+ 3 - 3
src/components/tools/UserMenu.vue

@@ -7,11 +7,11 @@
         </span>
       </a> -->
       <!-- <notice-icon class="action"/> -->
+      <span style="margin: 0 5px;">{{ nickname }}</span>
       <a-dropdown>
         <span class="action ant-dropdown-link user-dropdown-menu">
           <!-- <a-avatar class="avatar" size="small" :src="avatar==''?defaultAvatar:avatar"/> -->
-          <a-icon type="user" />
-          <span style="margin: 0 5px;">{{ nickname }}</span>
+          <!-- <a-icon type="user" /> -->
           <a-icon type="down" />
         </span>
         <a-menu slot="overlay" class="user-dropdown-menu-wrapper">
@@ -66,7 +66,7 @@ export default {
     handleLogout () {
       this.$confirm({
         title: '提示',
-        content: '真的要注销登录吗 ?',
+        content: '真的要退出登录吗 ?',
         onOk: () => {
           return this.Logout({}).then(() => {
             setTimeout(() => {

+ 1 - 1
src/config/defaultSettings.js

@@ -14,7 +14,7 @@
  */
 
 export default {
-  primaryColor: '#ff0000', // primary color of ant design
+  primaryColor: '#ed1c24', // primary color of ant design
   navTheme: 'dark', // theme for nav menu
   layout: 'sidemenu', // nav menu position: sidemenu or topmenu
   contentWidth: 'Fluid', // layout of content: Fluid or Fixed, only works when layout is topmenu

+ 225 - 169
src/config/router.config.js

@@ -7,202 +7,258 @@ import {
   PageView
 } from '@/layouts'
 
-export const asyncRouterMap = [{
-  path: '/',
-  name: 'index',
-  component: BasicLayout,
-  meta: {
-    title: '首页'
-  },
-  redirect: '/home',
-  children: [{
-    path: '/home',
-    name: 'home',
-    redirect: '/home',
-    component: PageView,
-    meta: {
-      title: '首页',
-      icon: 'home'
-    },
-    hideChildrenInMenu: true,
-    children: [{
-      path: '/home',
-      name: 'home',
-      component: () => import(/* webpackChunkName: "home" */ '@/views/Home'),
-      meta: {
-        title: '首页',
-        icon: 'home',
-        hide: true
-      }
-    }
-    ]
-  },
+export const asyncRouterMap = [
   {
-    path: '/changePwd',
-    name: 'changePwd',
-    component: () => import(/* webpackChunkName: "home" */ '@/views/user/ChangePwd'),
+    path: '/',
+    name: 'index',
+    component: BasicLayout,
     meta: {
-      title: '修改密码',
-      icon: 'home'
-    },
-    hidden: true
-  },
-  // 产品管理
-  {
-    path: '/productManagement',
-    redirect: '/productManagement/productCategory',
-    component: PageView,
-    meta: {
-      title: '产品管理',
-      icon: 'shop'
-      // permission: 'M_shop'
+      title: '首页'
     },
+    redirect: '/home',
     children: [
       {
-        path: '/productManagement/productCategory',
-        redirect: '/productManagement/productCategory/list',
-        name: 'productCategory',
-        component: RouteView,
+        path: '/home',
+        name: 'home',
+        redirect: '/home',
+        component: PageView,
         meta: {
-          title: '产品类别管理',
-          icon: 'shopping'
-          // permission: 'M_goodsManage_list'
+          title: '首页',
+          icon: 'home'
         },
         hideChildrenInMenu: true,
+        children: [{
+          path: '/home',
+          name: 'home',
+          component: () => import(/* webpackChunkName: "home" */ '@/views/Home'),
+          meta: {
+            title: '首页',
+            icon: 'home',
+            hide: true
+          }
+        }]
+      },
+      {
+        path: '/changePwd',
+        name: 'changePwd',
+        component: () => import(/* webpackChunkName: "home" */ '@/views/user/ChangePwd'),
+        meta: {
+          title: '修改密码',
+          icon: 'home'
+        },
+        hidden: true
+      },
+      // 连锁组管理
+      {
+        path: '/chainGroupManagement',
+        redirect: '/chainGroupManagement/chainGroupSetting',
+        component: PageView,
+        meta: {
+          title: '连锁组管理',
+          icon: 'radar-chart',
+          permission: 'M_chainGroupManagement'
+        },
+        children: [
+          {
+            path: '/chainGroupManagement/chainGroupSetting',
+            redirect: '/chainGroupManagement/chainGroupSetting/list',
+            name: 'chainGroupSetting',
+            component: RouteView,
+            meta: {
+              title: '连锁组设置',
+              icon: 'pull-request',
+              permission: 'M_chainGroupSetting'
+            },
+            hideChildrenInMenu: true,
+            children: [
+              {
+                path: 'list',
+                name: 'chainGroupSettingList',
+                component: () => import(/* webpackChunkName: "chainGroupManagement" */ '@/views/chainGroupManagement/chainGroupSetting/list.vue'),
+                meta: {
+                  title: '连锁组列表',
+                  icon: 'pull-request',
+                  hidden: true,
+                  permission: 'M_chainGroupSetting'
+                }
+              }
+            ]
+          }
+        ]
+      },
+      {
+        path: '/menusAuth',
+        redirect: '/bnSetting/menusAuth',
+        component: PageView,
+        meta: {
+          title: '菜单管理',
+          icon: 'bars',
+          permission: 'M_menusAuth_0'
+        },
         children: [
           {
-            path: '/productManagement/productCategory/list',
-            name: 'productCategoryList',
-            component: () => import(/* webpackChunkName: "shop" */ '@/views/productManagement/productCategory/list.vue'),
+            path: '/menusAuth/storeMenus',
+            name: 'storeMenus',
+            component: () => import(/* webpackChunkName: "bnSetting" */ '@/views/bnSetting/menu/storeMenus.vue'),
             meta: {
-              title: '产品类别列表',
-              icon: 'shopping',
-              hidden: true
-              // permission: 'M_goodsManage_list'
+              title: '连锁菜单管理',
+              icon: 'shop',
+              permission: 'M_menusAuth_lsMenus'
+            }
+          },
+          // {
+          //   path: '/menusAuth/adminMenus',
+          //   name: 'adminMenus',
+          //   component: () => import(/* webpackChunkName: "bnSetting" */ '@/views/bnSetting/menu/adminMenus.vue'),
+          //   meta: {
+          //     title: 'boss菜单管理',
+          //     icon: 'appstore',
+          //     // permission: 'M_menusAuth_adminMenus'
+          //   }
+          // },
+          {
+            path: '/menusAuth/menu',
+            name: 'powerMenu',
+            component: () => import(/* webpackChunkName: "auth" */ '@/views/power/menu/menu.vue'),
+            meta: {
+              title: 'IT菜单管理',
+              icon: 'profile',
+              permission: 'M_menusAuth_menu'
+            }
+          },
+          {
+            path: '/menusAuth/menuMould',
+            name: 'MenuMould',
+            component: () => import(/* webpackChunkName: "auth" */ '@/views/power/menuMould/list.vue'),
+            meta: {
+              title: '菜单模板',
+              icon: 'profile',
+              permission: 'M_menuMould'
+            }
+          }
+        ]
+      },
+      // auth
+      {
+        path: '/auth',
+        redirect: '/auth/userList',
+        component: PageView,
+        meta: {
+          title: '权限管理',
+          icon: 'lock',
+          permission: 'M_auth_0'
+        },
+        children: [
+          {
+            path: '/auth/userList',
+            name: 'powerUserList',
+            component: () => import(/* webpackChunkName: "auth" */ '@/views/power/user/userList.vue'),
+            meta: {
+              title: '用户管理',
+              icon: 'user',
+              permission: 'M_auth_userList'
+            }
+          },
+          {
+            path: '/auth/roleList',
+            name: 'powerRoleList',
+            component: () => import(/* webpackChunkName: "auth" */ '@/views/power/role/roleList.vue'),
+            meta: {
+              title: '角色管理',
+              icon: 'solution',
+              permission: 'M_auth_roleList'
+            }
+          }
+        ]
+      },
+      {
+        path: '/setting',
+        redirect: '/setting/userList',
+        component: PageView,
+        meta: {
+          title: '系统设置',
+          icon: 'setting',
+          permission: 'M_setting_0'
+        },
+        children: [
+          {
+            path: '/setting/dataDictionary',
+            name: 'powerDD',
+            component: () => import(/* webpackChunkName: "setting" */
+              '@/views/power/dataDictionary/dataDictionary.vue'),
+            meta: {
+              title: '数据字典管理',
+              icon: 'database',
+              permission: 'M_sys_dataDictionary'
+            }
+          },
+          // {
+          //   path: '/setting/register',
+          //   name: 'powerRegister',
+          //   component: () => import(/* webpackChunkName: "setting" */ '@/views/power/register/register.vue'),
+          //   meta: {
+          //     title: '参数管理',
+          //     icon: 'key',
+          //     permission: 'M_sys_register'
+          //   }
+          // },
+          {
+            path: '/setting/OperateJournal',
+            name: 'powerOperateJournal',
+            component: () => import(/* webpackChunkName: "setting" */
+              '@/views/power/OperateJournal/OperateJournal.vue'),
+            meta: {
+              title: '操作日志',
+              icon: 'read',
+              permission: 'M_operateJournal'
             }
           }
         ]
       }
     ]
   },
-  // auth
-  {
-    path: '/auth',
-    redirect: '/auth/userList',
-    component: PageView,
-    meta: {
-      title: '权限管理',
-      icon: 'lock',
-      permission: 'M_auth_0'
-    },
-    children: [{
-      path: '/auth/userList',
-      name: 'powerUserList',
-      component: () => import(/* webpackChunkName: "auth" */ '@/views/power/user/userList.vue'),
-      meta: {
-        title: '用户管理',
-        icon: 'user',
-        permission: 'M_auth_userList'
-      }
-    },
-    {
-      path: '/auth/roleList',
-      name: 'powerRoleList',
-      component: () => import(/* webpackChunkName: "auth" */ '@/views/power/role/roleList.vue'),
-      meta: {
-        title: '角色管理',
-        icon: 'solution',
-        permission: 'M_auth_roleList'
-      }
-    }
-    ]
-  },
   {
-    path: '/setting',
-    redirect: '/setting/userList',
-    component: PageView,
-    meta: {
-      title: '系统设置',
-      icon: 'setting',
-      permission: 'M_setting_0'
-    },
-    children: [{
-      path: '/setting/dataDictionary',
-      name: 'powerDD',
-      component: () => import(/* webpackChunkName: "setting" */
-        '@/views/power/dataDictionary/dataDictionary.vue'),
-      meta: {
-        title: '数据字典管理',
-        icon: 'database',
-        permission: 'M_sys_dataDictionary'
-      }
-    },
-    // {
-    //   path: '/setting/register',
-    //   name: 'powerRegister',
-    //   component: () => import(/* webpackChunkName: "setting" */ '@/views/power/register/register.vue'),
-    //   meta: {
-    //     title: '参数管理',
-    //     icon: 'key',
-    //     permission: 'M_sys_register'
-    //   }
-    // },
-    {
-      path: '/setting/OperateJournal',
-      name: 'powerOperateJournal',
-      component: () => import(/* webpackChunkName: "setting" */
-        '@/views/power/OperateJournal/OperateJournal.vue'),
-      meta: {
-        title: '操作日志',
-        icon: 'read',
-        permission: 'M_operateJournal'
-      }
-    }
-    ]
+    path: '*',
+    redirect: '/404',
+    hidden: true
   }
-  ]
-},
-{
-  path: '*',
-  redirect: '/404',
-  hidden: true
-}
 ]
 
 /**
  * 基础路由
  * @type { *[] }
  */
-export const constantRouterMap = [{
-  path: '/user',
-  component: UserLayout,
-  redirect: '/user/login',
-  hidden: true,
-  children: [{
-    path: 'login',
-    name: 'login',
-    component: () => import(/* webpackChunkName: "user" */ '@/views/user/Login')
-  },
+export const constantRouterMap = [
   {
-    path: 'register',
-    name: 'register',
-    component: () => import(/* webpackChunkName: "user" */ '@/views/user/Register')
-  },
-  {
-    path: 'register-result',
-    name: 'registerResult',
-    component: () => import(/* webpackChunkName: "user" */ '@/views/user/RegisterResult')
+    path: '/user',
+    component: UserLayout,
+    redirect: '/user/login',
+    hidden: true,
+    children: [
+      {
+        path: 'login',
+        name: 'login',
+        component: () => import(/* webpackChunkName: "user" */ '@/views/user/Login')
+      },
+      {
+        path: 'register',
+        name: 'register',
+        component: () => import(/* webpackChunkName: "user" */ '@/views/user/Register')
+      },
+      {
+        path: 'register-result',
+        name: 'registerResult',
+        component: () => import(/* webpackChunkName: "user" */ '@/views/user/RegisterResult')
+      },
+      {
+        path: 'recover',
+        name: 'recover',
+        component: undefined
+      }
+    ]
   },
   {
-    path: 'recover',
-    name: 'recover',
-    component: undefined
+    path: '/404',
+    component: () => import(/* webpackChunkName: "fail" */ '@/views/exception/404')
   }
-  ]
-},
-{
-  path: '/404',
-  component: () => import(/* webpackChunkName: "fail" */ '@/views/exception/404')
-}
-
 ]

+ 1 - 2
src/layouts/BasicLayout.vue

@@ -113,8 +113,7 @@ export default {
     } else {
       // 没有权限时只显示首页
       const noqx = asyncRouterMap.find((item) => item.path === '/').children
-      // this.menus = [noqx.find(item => item.path === '/home')]
-      this.menus = noqx
+      this.menus = [noqx.find(item => item.path === '/home')]
     }
     this.collapsed = !this.sidebarOpened
   },

+ 8 - 10
src/permission.js

@@ -78,16 +78,14 @@ router.beforeEach((to, from, next) => {
       }
     }
   } else {
-    console.log(111111)
-    next()
-    // // 未登录
-    // if (whiteList.includes(to.name)) {
-    //   // 在免登录白名单,直接进入
-    //   next()
-    // } else {
-    //   next({ path: '/user/login', query: { redirect: to.fullPath } })
-    //   NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
-    // }
+    // 未登录
+    if (whiteList.includes(to.name)) {
+      // 在免登录白名单,直接进入
+      next()
+    } else {
+      next({ path: '/user/login', query: { redirect: to.fullPath } })
+      NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
+    }
   }
 })
 

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

+ 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: [] })

+ 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')

+ 2 - 3
src/utils/request.js

@@ -38,9 +38,8 @@ const err = (error) => {
 // request interceptor
 service.interceptors.request.use(config => {
   const token = store.getters.token
-  config.headers['App-Type'] = 9 // 平台类型
   if (token) {
-    config.headers['authorization'] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
+    config.headers['access-token'] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
   }
   return config
 }, err)
@@ -49,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>

+ 461 - 0
src/views/bnSetting/menu/adminMenus.vue

@@ -0,0 +1,461 @@
+<template>
+  <a-card :bordered="false">
+    <a-row :gutter="24">
+      <a-button style="margin-right: 10px;" type="primary" icon="plus" @click="addChild">添加子菜单</a-button>
+      <a-button style="margin-right: 10px;background-color: #19be6b;color: #fff;" type="" icon="plus" @click="addTitle">添加顶部菜单</a-button>
+      <a-button style="margin-right: 10px;background-color: red;color: #fff;" type="" icon="delete" @click="delect()">删除</a-button>
+
+    </a-row>
+    <a-row :gutter="24">
+      <!-- 左侧菜单树列表 -->
+      <a-col :span="8">
+        <a-row :gutter="24" class="textCount">
+          <a-icon type="info-circle" style="color: #1890FF;margin-right: 10px;" />
+          <span>当前选择:<span style="color: #40a9ff;font-weight: 600;">{{ selectedMenu }}</span><span v-if="selectedKeys.length" class="imgSize" @click="cancelSel">取消选择</span></span>
+        </a-row>
+
+        <a-row :gutter="24" >
+          <a-input-search placeholder="输入搜索菜单名搜索" style="width: 100%" @change="onChange" />
+          <a-tree
+            @expand="onExpand"
+            :treeData="getMenus"
+            :expandedKeys="expandedKeys"
+            :autoExpandParent="autoExpandParent"
+            @select="onSelect"
+            :selectedKeys="selectedKeys"
+            showIcon
+          >
+            <template slot="title" slot-scope="{title}">
+              <span v-if="title.indexOf(searchValue) > -1">
+                {{ title.substr(0, title.indexOf(searchValue)) }}
+                <span style="color: #f50">{{ searchValue }}</span>
+                {{ title.substr(title.indexOf(searchValue) + searchValue.length) }}
+              </span>
+              <span v-else>{{ title }}</span>
+            </template>
+            <a-icon slot="file" type="file" />
+            <a-icon slot="pushpin" type="pushpin" />
+          </a-tree>
+        </a-row>
+      </a-col>
+      <!-- 右侧 -->
+      <a-col :span="16" >
+        <a-form :form="form" @submit="handleSubmit">
+          <!-- 类型 -->
+          <a-form-item label="类型" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <div v-if="!formData.type||formData.type=='0'">
+              <a-icon type="file" style="margin-right: 10px;" /><span >页面菜单</span>
+            </div>
+            <div v-if="formData.type=='1'">
+              <a-icon type="pushpin" style="margin-right: 10px;" /><span >操作按钮</span>
+            </div>
+          </a-form-item>
+
+          <!-- 名称 -->
+          <a-form-item label="名称" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入名称(最多30个字符)"
+              v-decorator="['formData.name', {
+                initialValue: formData.name,
+                getValueFromEvent: $filterEmpty,
+                rules: [{ required: true, message: '请输入名称!' }] }]"
+            />
+          </a-form-item>
+          <!-- 路由英文名 -->
+          <!-- <a-form-item v-if="!formData.type||formData.type=='0'" label="路由英文名" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入路由英文名"
+              v-decorator="['formData.routeName', {
+                initialValue: formData.routeName,
+                rules: [{ required: true, message: '请输入路由英文名!' }] }]"
+            />
+          </a-form-item> -->
+          <!-- 路径 -->
+          <!-- <a-form-item v-if="!formData.type||formData.type=='0'" label="路径" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入路径"
+              v-decorator="['formData.routePath', {
+                initialValue: formData.routePath,
+                rules: [{ required: true, message: '请输入路径!' }] }]"
+            />
+          </a-form-item> -->
+          <!-- 请求路径 -->
+          <!-- <a-form-item v-if="formData.type==1" label="请求路径" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入请求路径"
+              v-decorator="['formData.urlPath', {
+                initialValue: formData.urlPath,
+                rules: [{ required: true, message: '请输入请求路径!' }] }]"
+            />
+          </a-form-item> -->
+          <!-- 前端权限编码 -->
+          <a-form-item label="前端权限编码" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入前端权限编码"
+              v-decorator="[
+                'formData.code',
+                {
+                  initialValue: formData.code,
+                  rules: [{ required: true, message: '请输入前端权限编码!' }] },
+              ]"
+            />
+          </a-form-item>
+          <!-- 后台权限编码 -->
+          <a-form-item label="后台权限编码" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入后台权限编码"
+              v-decorator="[
+                'formData.permission',
+                {
+                  initialValue: formData.permission,
+                  rules: [{ required: formData.isLeaf, message: '请输入后台权限编码!' }] },
+              ]"
+            />
+          </a-form-item>
+          <!-- 图标 -->
+          <!-- <a-form-item v-if="!formData.type ||formData.type=='0' " label="图标" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入图标名称"
+              v-decorator="['formData.icon', {
+                initialValue: formData.icon,
+                rules: [] }]"
+            />
+          </a-form-item> -->
+          <!-- 前端组件 -->
+          <!-- <a-form-item v-if="!formData.type ||formData.type=='0'" label="前端组件" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入前端组件路径"
+              v-decorator="['formData.componentPath', {
+                initialValue: formData.componentPath,
+                rules: [{ required: true, message: '请输入前端组件路径!' }] }]"
+            />
+          </a-form-item> -->
+
+          <!-- 第三方链接 -->
+          <!-- <a-form-item v-if="!formData.type ||formData.type=='0'" label="第三方链接" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入第三方链接地址"
+              v-decorator="['formData.urlPath', {
+                initialValue: formData.urlPath,
+                rules: [] }]"
+            />
+          </a-form-item> -->
+
+          <!-- 排序值 -->
+          <a-form-item label="排序值" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input-number
+              style="width: 100%;"
+              type="number"
+              placeholder="请输入排序值(0~999999)"
+              v-decorator="['formData.sort', {
+                initialValue: formData.sort,
+                rules: [] }]"
+              :max="999999"
+              :min="0"
+            />
+          </a-form-item>
+          <!-- 状态 -->
+          <a-form-item label="启用" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-radio-group
+              name="radioGroup"
+              v-decorator="[
+                'formData.status',
+                {
+                  initialValue: formData.status,
+                  rules: [{ required: true, message: '请选择状态!' }] },
+              ]"
+            >
+              <a-radio :value="1">是</a-radio>
+              <a-radio :value="0">否</a-radio>
+            </a-radio-group>
+          </a-form-item>
+
+          <a-form-item :wrapper-col="{ span: 12, offset: 5 }">
+            <a-button type="primary" @click="handleSubmit()">
+              保存
+            </a-button>
+            <a-button :style="{ marginLeft: '8px' }" @click="clear">
+              重置
+            </a-button>
+          </a-form-item>
+        </a-form>
+
+      </a-col>
+    </a-row>
+    <childModal parentType="admin" :visible="showChildModal" @refresh="getYyMenuList" :data="parentData" @close="showChildModal = false"></childModal>
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import childModal from './childModal.vue'
+import { getYyMenuList, saveYyMenu, deleteYyMenu } from '@/api/menu.js'
+
+export default {
+  name: 'Menu',
+  components: {
+    STable, VSelect, childModal
+  },
+  props: {},
+  data () {
+    return {
+      treeData: [],
+      dataList: [],
+      searchValue: '',
+      expandedKeys: [],
+      autoExpandParent: true,
+      selectedKeys: [],
+      selectedMenu: '', // 选择的树节点名
+      formLayout: 'horizontal',
+      form: this.$form.createForm(this, { name: 'menu' }),
+      showChildModal: false,
+      parentData: {}, // 父级菜单
+      formData: {
+        id: '',
+        name: '',
+        routePath: '',
+        icon: '',
+        routeName: '',
+        componentPath: '',
+        urlPath: '',
+        code: '',
+        permission: '',
+        sort: '',
+        type: '0',
+        isLeaf: true,
+        status: '' // 活动状态
+      }
+    }
+  },
+  computed: {
+    getMenus () {
+      this.generateList(this.treeData)
+      return this.treeData
+    }
+  },
+  methods: {
+    onExpand (expandedKeys) {
+      // console.log('onExpand', expandedKeys)
+      this.expandedKeys = expandedKeys
+      this.autoExpandParent = false
+    },
+
+    onSelect (selectedKeys, info) {
+      console.log('onSelect', info)
+      this.selectedKeys = selectedKeys
+      if (info.selected) {
+        const data = info.selectedNodes[0].data.props
+        const isLeaf = data.dataRef.children
+        // this.formData = Object.assign({}, this.formData, info.selectedNodes[0].data.props)
+        this.formData = {
+          id: data.id,
+          name: data.name,
+          routePath: data.routePath,
+          icon: data.icon,
+          routeName: data.routeName,
+          componentPath: data.componentPath,
+          urlPath: data.urlPath,
+          code: data.code,
+          permission: data.permission,
+          sort: data.sort,
+          type: data.type,
+          status: data.status,
+          isLeaf: !(isLeaf && isLeaf.length)
+        }
+
+        this.selectedMenu = this.formData.name
+        this.formData.status = Number(this.formData.status)
+      } else {
+        this.selectedMenu = ''
+        this.clear()
+      }
+    },
+    generateList (data) {
+      for (let i = 0; i < data.length; i++) {
+        const node = data[i]
+        const key = node.title
+        this.dataList.push({ key, title: key })
+        node.scopedSlots = { title: 'title' }
+        node.slots = { icon: node.type == '0' ? 'file' : 'pushpin' }
+
+        if (node.children) {
+          this.generateList(node.children)
+        }
+      }
+    },
+    getParentKey (key, tree) {
+      let parentKey
+      for (let i = 0; i < tree.length; i++) {
+        const node = tree[i]
+        if (node.children) {
+          if (node.children.some(item => item.title == key)) {
+            parentKey = node.key
+          } else if (this.getParentKey(key, node.children)) {
+            parentKey = this.getParentKey(key, node.children)
+          }
+        }
+      }
+      return parentKey
+    },
+    onChange (e) {
+      const value = e.target.value
+      const expandedKeys = this.dataList
+        .map(item => {
+          if (item.title.indexOf(value) > -1) {
+            return this.getParentKey(item.title, this.treeData)
+          }
+          return null
+        })
+        .filter((item, i, self) => item && self.indexOf(item) === i)
+      Object.assign(this, {
+        expandedKeys,
+        searchValue: value,
+        autoExpandParent: true
+      })
+    },
+    // 获取菜单树列表
+    getYyMenuList () {
+      getYyMenuList().then(res => {
+        console.log(res, 'res1111111')
+        if (res.status == 200) {
+          this.treeData = res.data
+          console.log(this.treeData, 'this.treeData')
+        }
+      })
+    },
+    // 添加子节点
+    addChild () {
+      if (!this.selectedMenu) {
+        return this.$message.warning('请先选择一个父级菜单')
+      } else if (this.formData.type == '1') {
+        return this.$message.warning('请选择一个页面级菜单')
+      }
+      this.showChildModal = true
+      this.parentData = this.formData
+    },
+    // 添加顶部菜单
+    addTitle () {
+      this.showChildModal = true
+      this.parentData = {}
+    },
+
+    //  取消选择
+    cancelSel () {
+      this.selectedKeys = []
+      this.selectedMenu = ''
+      this.clear()
+    },
+    // 清空列表
+    clear () {
+      this.form.resetFields()
+      this.formData.id = ''
+      this.formData.name = ''
+      this.formData.routePath = ''
+      this.formData.icon = ''
+      this.formData.routeName = ''
+      this.formData.componentPath = ''
+      this.formData.urlPath = ''
+      this.formData.sort = ''
+      this.formData.type = ''
+      this.formData.status = ''
+      this.formData.code = ''
+      this.formData.permission = ''
+      this.formData.isLeaf = true
+    },
+
+    // 删除数据
+    delect () {
+      if (!this.selectedKeys.length) {
+        return this.$message.warning('您还未选择要删除的数据')
+      }
+      const _this = this
+      console.log(_this.formData.id, '_this.formData.id')
+      this.$confirm({
+        title: '警告',
+        content: `确定要删除您选择的 ${_this.formData.name} 的数据吗?`,
+        okText: '确定',
+        cancelText: '取消',
+        onOk () {
+          deleteYyMenu({
+            id: _this.formData.id
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success('删除成功')
+              _this.getYyMenuList()
+            }
+          }).catch(() => {
+            _this.$message.success('删除失败, 请稍后重试')
+          })
+        }
+      })
+    },
+
+    // 保存提交
+    handleSubmit () {
+      const _this = this
+      this.form.validateFields((err, values) => {
+        if (!err) {
+          console.log(values.formData, ' formData.type222222222')
+          saveYyMenu(Object.assign({ id: this.formData.id }, values.formData)).then(res => {
+            console.log(res, 'res--save')
+            if (res.status + '' === '200') {
+              this.$message.success(res.message ? res.message : '保存成功')
+              _this.getYyMenuList()
+              _this.clear()
+            } else {
+              // this.$message.warning(res.message)
+            }
+          })
+        }
+      })
+    },
+    handleCancel () {
+      this.clear()
+    }
+
+  },
+  mounted () {
+  },
+  beforeCreate () {
+    this.form = this.$form.createForm(this, { name: 'menu' })
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.getYyMenuList()
+    })
+  },
+  watch: {
+
+  }
+}
+</script>
+
+<style>
+  .menu-box::-webkit-scrollbar{
+    width: 6px;
+    height: 6px ;
+  }
+
+  .menu-box::-webkit-scrollbar-thumb{
+    width: 6px;
+    height: 6px ;
+    border-radius: 4px;
+    -webkit-box-shadow: inset 0 0 2px #d1d1d1;
+    background: #e4e4e4;
+  }
+
+  .textCount{
+    border: 1px solid #91d5ff;
+    background-color: #e6f7ff;
+    border-radius: 5px;
+    padding: 5px 10px 5px 20px;
+    margin: 10px 0;
+    color: rgba(0, 0, 0, 0.85);
+  }
+  .imgSize{
+    color: #2d8cf0;
+    margin-left: 10px;
+    font-size: 14px;
+  }
+
+</style>

+ 346 - 0
src/views/bnSetting/menu/childModal.vue

@@ -0,0 +1,346 @@
+<template>
+  <div>
+    <a-modal class="modalBox" :title="titleText" v-model="isshow" @cancle="cancel">
+      <a-form :form="form" @submit="handleSubmit">
+        <!-- 上级菜单 -->
+        <a-form-item label="上级菜单" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <div >
+            <span >{{ parentTitle }}</span>
+          </div>
+
+        </a-form-item>
+        <!-- 类型 -->
+        <a-form-item label="类型" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-select
+            @change="selectChange"
+            :disabled="disabled"
+            v-decorator="[
+              'formData.type',
+              {
+                initialValue: formData.type,
+                rules: [{ required: true, message: '请选择状态!' }] },
+            ]"
+            style="width: 100%"
+            placeholder="请选择菜单类型"
+          >
+            <a-select-option :value="0">页面类型</a-select-option>
+            <a-select-option :value="1">按钮类型</a-select-option>
+          </a-select>
+        </a-form-item>
+
+        <!-- 名称 -->
+        <a-form-item label="名称" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入名称(最多30个字符)"
+            :maxLength="30"
+            v-decorator="['formData.name', {
+              initialValue: formData.name,
+              getValueFromEvent: $filterEmpty,
+              rules: [{ required: true, message: '请输入名称!' }] }]"
+          />
+        </a-form-item>
+        <!-- 路由英文名 -->
+        <!-- <a-form-item v-if="!formData.type" label="路由英文名" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入路由英文名"
+            v-decorator="['formData.routeName', {
+              initialValue: formData.routeName,
+              rules: [{ required: true, message: '请输入路由英文名!' }] }]"
+          />
+        </a-form-item> -->
+        <!-- 路径 -->
+        <!-- <a-form-item v-if="!formData.type" label="路径" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+             <a-input placeholder="请输入路径"
+                      v-decorator="['formData.routePath', {
+                        initialValue: formData.routePath,
+                        rules: [{ required: true, message: '请输入路径!' }] }]"
+             />
+           </a-form-item> -->
+        <!-- 请求路径 -->
+        <!-- <a-form-item v-if="formData.type==1" label="请求路径" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+             <a-input placeholder="请输入请求路径"
+                      v-decorator="['formData.urlPath', {
+                        initialValue: formData.urlPath,
+                        rules: [{ required: true, message: '请输入请求路径!' }] }]"
+             />
+           </a-form-item> -->
+        <!-- 前端权限编码 -->
+        <a-form-item label="前端权限编码" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入前端权限编码"
+            v-decorator="[
+              'formData.code',
+              {
+                initialValue: formData.code,
+                rules: [{ required: true, message: '请输入前端权限编码!' }] },
+            ]"
+          />
+
+        </a-form-item>
+        <!-- 后台权限编码 -->
+        <a-form-item label="后台权限编码" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入后台权限编码"
+            v-decorator="[
+              'formData.permission',
+              {initialValue: formData.permission},
+            ]"
+          />
+
+        </a-form-item>
+
+        <!-- 图标 -->
+        <!-- <a-form-item v-if="!formData.type" label="图标" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入图标名称"
+            v-decorator="['formData.icon', {
+              initialValue: formData.icon,
+              rules: [] }]"
+          />
+        </a-form-item> -->
+        <!-- 前端组件 -->
+        <!-- <a-form-item v-if="!formData.type" label="前端组件" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入前端组件路径"
+            v-decorator="['formData.componentPath', {
+              initialValue: formData.componentPath,
+              rules: [{ required: true, message: '请输入前端组件路径!' }] }]"
+          />
+        </a-form-item> -->
+
+        <!-- 第三方链接 -->
+        <!-- <a-form-item v-if="!formData.type" label="第三方链接" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入第三方链接地址"
+            v-decorator="['formData.urlPath', {
+              initialValue: formData.urlPath,
+              rules: [] }]"
+          />
+        </a-form-item> -->
+
+        <!-- 排序值 -->
+        <a-form-item label="排序值" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input-number
+            style="width: 100%;"
+            type="number"
+            placeholder="请输入排序值(0~999999)"
+            v-decorator="['formData.sort', {
+              initialValue: formData.sort,
+              rules: [] }]"
+            :max="999999"
+            :min="0"
+          />
+        </a-form-item>
+        <!-- 连锁可用 -->
+        <!-- <a-form-item v-if="parentType=='store'" label="连锁可用" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-radio-group
+            name="radioGroup"
+            v-decorator="[
+              'formData.chainOrgUse',
+              {
+                initialValue: formData.chainOrgUse,
+                rules: [{ required: true, message: '请选择!' }] },
+            ]"
+          >
+            <a-radio :value="1">是</a-radio>
+            <a-radio :value="0">否</a-radio>
+          </a-radio-group>
+        </a-form-item> -->
+        <!-- 单店可用 -->
+        <!-- <a-form-item v-if="parentType=='store'" label="单店可用" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-radio-group
+            name="radioGroup"
+            v-decorator="[
+              'formData.singleOrgUse',
+              {
+                initialValue: formData.singleOrgUse,
+                rules: [{ required: true, message: '请选择!' }] },
+            ]"
+          >
+            <a-radio :value="1">是</a-radio>
+            <a-radio :value="0">否</a-radio>
+          </a-radio-group>
+        </a-form-item> -->
+        <!-- 状态 -->
+        <a-form-item label="启用" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-radio-group
+            name="radioGroup"
+            v-decorator="[
+              'formData.status',
+              {
+                initialValue: formData.status,
+                rules: [{ required: true, message: '请选择状态!' }] },
+            ]"
+          >
+            <a-radio :value="1">是</a-radio>
+            <a-radio :value="0">否</a-radio>
+          </a-radio-group>
+        </a-form-item>
+
+        <a-form-item :wrapper-col="{ span: 12, offset: 5 }">
+          <a-button type="primary" @click="handleSubmit()">
+            保存
+          </a-button>
+          <a-button :style="{ marginLeft: '8px' }" @click="handleCancel()">
+            取消
+          </a-button>
+        </a-form-item>
+      </a-form>
+
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import { saveYyMenu, saveMdMenu } from '@/api/menu.js'
+export default {
+  name: 'ChildModal',
+  components: {
+    STable, VSelect
+  },
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    parentType: {
+      type: String,
+      default: ''
+    },
+    data: {
+      type: Object,
+      default: function () {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      isshow: this.visible,
+      titleText: '',
+      disabled: false,
+      parentTitle: '',
+      formLayout: 'horizontal',
+      form: this.$form.createForm(this, { name: 'childModal' }),
+      formData: {
+        parentId: '',
+        name: '',
+        routePath: '',
+        icon: '',
+        routeName: '',
+        code: '',
+        permission: '',
+        componentPath: '',
+        urlPath: '',
+        sort: '',
+        type: undefined,
+        chainOrgUse: 1,
+        singleOrgUse: 1,
+        status: 1 // 活动状态
+      }
+    }
+  },
+  methods: {
+    cancel (e) {
+      this.clear()
+      this.$emit('close')
+    },
+
+    selectChange (val) {
+      this.formData.type = val
+      console.log(val)
+    },
+    // 保存提交
+    handleSubmit () {
+      const _this = this
+      this.form.validateFields((err, values) => {
+        if (!err) {
+          console.log(values.formData, ' formData.type222222222')
+          const saveRequest = this.parentType == 'store' ? saveMdMenu : saveYyMenu
+          saveRequest(Object.assign(this.formData, values.formData)).then(res => {
+            console.log(res, 'res--save')
+            if (res.status + '' === '200') {
+              this.$message.success(res.message ? res.message : '保存成功')
+              this.$emit('refresh')
+              setTimeout(function () {
+                _this.cancel()
+              }, 300)
+            } else {
+              // this.$message.warning(res.message)
+            }
+          })
+        }
+      })
+    },
+    // 取消
+    handleCancel () {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确定取消吗?',
+        okText: '确定',
+        cancelText: '取消',
+        onOk () {
+          _this.clear()
+          _this.cancel()
+        }
+      })
+    },
+    clear () {
+      this.form.resetFields()
+      this.parentTitle = ''
+      this.formData.parentId = ''
+      this.formData.name = ''
+      this.formData.routePath = ''
+      this.formData.icon = ''
+      this.formData.routeName = ''
+      this.formData.componentPath = ''
+      this.formData.urlPath = ''
+      this.formData.sort = ''
+      this.formData.type = ''
+      this.formData.status = 1
+      this.formData.chainOrgUse = 1
+      this.formData.singleOrgUse = 1
+      this.formData.code = ''
+      this.formData.permission = ''
+    }
+
+  },
+  mounted () {
+  },
+  beforeCreate () {
+    this.form = this.$form.createForm(this, { name: 'childModal' })
+  },
+  watch: {
+    visible (newValue, oldValue) {
+      this.isshow = newValue
+    },
+    isshow (newValue, oldValue) {
+      if (newValue) {
+        if (this.data.id) { // 添加子菜单
+          this.titleText = '添加子菜单'
+          this.disabled = false
+          console.log(this.data, 'this.data')
+          this.formData.parentId = this.data.id
+          this.parentTitle = this.data.name
+        } else { // 添加顶菜单
+          this.titleText = '添加顶菜单'
+          this.formData.type = 0
+          this.disabled = true
+        }
+      } else {
+        this.cancel()
+      }
+    }
+  }
+}
+</script>
+
+<style >
+  .modalBox{
+  }
+  .ant-modal-footer {
+    display: none;
+  }
+</style>

+ 498 - 0
src/views/bnSetting/menu/storeMenus.vue

@@ -0,0 +1,498 @@
+<template>
+  <a-card :bordered="false">
+    <a-row :gutter="24">
+      <a-button style="margin-right: 10px;" type="primary" icon="plus" @click="addChild">添加子菜单</a-button>
+      <a-button style="margin-right: 10px;background-color: #19be6b;color: #fff;" type="" icon="plus" @click="addTitle">添加顶部菜单</a-button>
+      <a-button style="margin-right: 10px;background-color: red;color: #fff;" type="" icon="delete" @click="delect()">删除</a-button>
+
+    </a-row>
+    <a-row :gutter="24">
+      <!-- 左侧菜单树列表 -->
+      <a-col :span="8">
+        <a-row :gutter="24" class="textCount">
+          <a-icon type="info-circle" style="color: #1890FF;margin-right: 10px;" />
+          <span>当前选择:<span style="color: #40a9ff;font-weight: 600;">{{ selectedMenu }}</span><span v-if="selectedKeys.length" class="imgSize" @click="cancelSel">取消选择</span></span>
+        </a-row>
+
+        <a-row :gutter="24" >
+          <a-input-search placeholder="输入搜索菜单名搜索" style="width: 100%" @change="onChange" />
+          <a-tree
+            @expand="onExpand"
+            :treeData="getMenus"
+            :expandedKeys="expandedKeys"
+            :autoExpandParent="autoExpandParent"
+            @select="onSelect"
+            :selectedKeys="selectedKeys"
+            showIcon
+          >
+            <template slot="title" slot-scope="{title}">
+              <span v-if="title.indexOf(searchValue) > -1">
+                {{ title.substr(0, title.indexOf(searchValue)) }}
+                <span style="color: #f50">{{ searchValue }}</span>
+                {{ title.substr(title.indexOf(searchValue) + searchValue.length) }}
+              </span>
+              <span v-else>{{ title }}</span>
+            </template>
+            <a-icon slot="file" type="file" />
+            <a-icon slot="pushpin" type="pushpin" />
+          </a-tree>
+        </a-row>
+      </a-col>
+      <!-- 右侧 -->
+      <a-col :span="16" >
+        <a-form :form="form" @submit="handleSubmit">
+          <!-- 类型 -->
+          <a-form-item label="类型" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <div v-if="!formData.type||formData.type=='0'">
+              <a-icon type="file" style="margin-right: 10px;" /><span >页面菜单</span>
+            </div>
+            <div v-if="formData.type=='1'">
+              <a-icon type="pushpin" style="margin-right: 10px;" /><span >操作按钮</span>
+            </div>
+          </a-form-item>
+
+          <!-- 名称 -->
+          <a-form-item label="名称" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入名称(最多30个字符)"
+              :maxLength="30"
+              v-decorator="['formData.name', {
+                initialValue: formData.name,
+                getValueFromEvent: $filterEmpty,
+                rules: [{ required: true, message: '请输入名称!' }] }]"
+            />
+          </a-form-item>
+          <!-- 路由英文名 -->
+          <!-- <a-form-item v-if="!formData.type||formData.type=='0'" label="路由英文名" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入路由英文名"
+              v-decorator="['formData.routeName', {
+                initialValue: formData.routeName,
+                rules: [{ required: true, message: '请输入路由英文名!' }] }]"
+            />
+          </a-form-item> -->
+          <!-- 路径 -->
+          <!-- <a-form-item v-if="!formData.type||formData.type=='0'" label="路径" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入路径"
+              v-decorator="['formData.routePath', {
+                initialValue: formData.routePath,
+                rules: [{ required: true, message: '请输入路径!' }] }]"
+            />
+          </a-form-item> -->
+          <!-- 请求路径 -->
+          <!-- <a-form-item v-if="formData.type==1" label="请求路径" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入请求路径"
+              v-decorator="['formData.urlPath', {
+                initialValue: formData.urlPath,
+                rules: [{ required: true, message: '请输入请求路径!' }] }]"
+            />
+          </a-form-item> -->
+          <!-- 前端权限编码 -->
+          <a-form-item label="前端权限编码" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入前端权限编码"
+              v-decorator="[
+                'formData.code',
+                {
+                  initialValue: formData.code,
+                  rules: [{ required: true, message: '请输入前端权限编码!' }] },
+              ]"
+            />
+          </a-form-item>
+          <!-- 后台权限编码 -->
+          <a-form-item label="后台权限编码" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入后台权限编码"
+              v-decorator="[
+                'formData.permission',
+                {
+                  initialValue: formData.permission,
+                  rules: [{ required: formData.isLeaf, message: '请输入后台权限编码!' }] },
+              ]"
+            />
+          </a-form-item>
+          <!-- 图标 -->
+          <!-- <a-form-item v-if="!formData.type ||formData.type=='0' " label="图标" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入图标名称"
+              v-decorator="['formData.icon', {
+                initialValue: formData.icon,
+                rules: [] }]"
+            />
+          </a-form-item> -->
+          <!-- 前端组件 -->
+          <!-- <a-form-item v-if="!formData.type ||formData.type=='0'" label="前端组件" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入前端组件路径"
+              v-decorator="['formData.componentPath', {
+                initialValue: formData.componentPath,
+                rules: [{ required: true, message: '请输入前端组件路径!' }] }]"
+            />
+          </a-form-item> -->
+
+          <!-- 第三方链接 -->
+          <!-- <a-form-item v-if="!formData.type ||formData.type=='0'" label="第三方链接" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入第三方链接地址"
+              v-decorator="['formData.urlPath', {
+                initialValue: formData.urlPath,
+                rules: [] }]"
+            />
+          </a-form-item> -->
+
+          <!-- 排序值 -->
+          <a-form-item label="排序值" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input-number
+              style="width: 100%;"
+              placeholder="请输入排序值(0~999999)"
+              v-decorator="['formData.sort', {
+                initialValue: formData.sort,
+                rules: [] }]"
+              :max="999999"
+              :min="0"
+            />
+          </a-form-item>
+          <!-- 连锁可用 -->
+          <!-- <a-form-item label="连锁可用" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-radio-group
+              name="radioGroup"
+              v-decorator="[
+                'formData.chainOrgUse',
+                {
+                  initialValue: formData.chainOrgUse,
+                  rules: [{ required: true, message: '请选择!' }] },
+              ]"
+            >
+              <a-radio :value="1">是</a-radio>
+              <a-radio :value="0">否</a-radio>
+            </a-radio-group>
+          </a-form-item> -->
+          <!-- 单店可用 -->
+          <!-- <a-form-item label="单店可用" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-radio-group
+              name="radioGroup"
+              v-decorator="[
+                'formData.singleOrgUse',
+                {
+                  initialValue: formData.singleOrgUse,
+                  rules: [{ required: true, message: '请选择!' }] },
+              ]"
+            >
+              <a-radio :value="1">是</a-radio>
+              <a-radio :value="0">否</a-radio>
+            </a-radio-group>
+          </a-form-item> -->
+          <!-- 状态 -->
+          <a-form-item label="启用" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-radio-group
+              name="radioGroup"
+              v-decorator="[
+                'formData.status',
+                {
+                  initialValue: formData.status,
+                  rules: [{ required: true, message: '请选择状态!' }] },
+              ]"
+            >
+              <a-radio :value="1">是</a-radio>
+              <a-radio :value="0">否</a-radio>
+            </a-radio-group>
+          </a-form-item>
+
+          <a-form-item :wrapper-col="{ span: 12, offset: 5 }">
+            <a-button type="primary" @click="handleSubmit()">
+              保存
+            </a-button>
+            <a-button :style="{ marginLeft: '8px' }" @click="clear">
+              重置
+            </a-button>
+          </a-form-item>
+        </a-form>
+
+      </a-col>
+    </a-row>
+    <childModal parentType="store" :visible="showChildModal" @refresh="getMdMenuList" :data="parentData" @close="showChildModal = false"></childModal>
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import childModal from './childModal.vue'
+import { getMdMenuList, saveMdMenu, deleteMdMenu } from '@/api/menu.js'
+
+export default {
+  name: 'Menu',
+  components: {
+    STable, VSelect, childModal
+  },
+  props: {},
+  data () {
+    return {
+      treeData: [],
+      dataList: [],
+      searchValue: '',
+      expandedKeys: [],
+      autoExpandParent: true,
+      selectedKeys: [],
+      selectedMenu: '', // 选择的树节点名
+      formLayout: 'horizontal',
+      form: this.$form.createForm(this, { name: 'menu' }),
+      showChildModal: false,
+      parentData: {}, // 父级菜单
+      formData: {
+        id: '',
+        name: '',
+        routePath: '',
+        icon: '',
+        routeName: '',
+        componentPath: '',
+        urlPath: '',
+        code: '',
+        permission: '',
+        sort: '',
+        type: '0',
+        isLeaf: true,
+        chainOrgUse: '',
+        singleOrgUse: '',
+        status: '' // 活动状态
+      }
+    }
+  },
+  computed: {
+    getMenus () {
+      this.generateList(this.treeData)
+      return this.treeData
+    }
+  },
+  methods: {
+    onExpand (expandedKeys) {
+      // console.log('onExpand', expandedKeys)
+      this.expandedKeys = expandedKeys
+      this.autoExpandParent = false
+    },
+
+    onSelect (selectedKeys, info) {
+      console.log('onSelect', info)
+      this.selectedKeys = selectedKeys
+      if (info.selected) {
+        const data = info.selectedNodes[0].data.props
+        const isLeaf = data.dataRef.children
+        // this.formData = Object.assign({}, this.formData, info.selectedNodes[0].data.props)
+        this.formData = {
+          id: data.id,
+          name: data.name,
+          routePath: data.routePath,
+          icon: data.icon,
+          routeName: data.routeName,
+          componentPath: data.componentPath,
+          urlPath: data.urlPath,
+          code: data.code,
+          permission: data.permission,
+          sort: data.sort,
+          type: data.type,
+          chainOrgUse: data.chainOrgUse,
+          singleOrgUse: data.singleOrgUse,
+          status: data.status,
+          isLeaf: !(isLeaf && isLeaf.length)
+        }
+
+        this.selectedMenu = this.formData.name
+        this.formData.status = Number(this.formData.status)
+        this.formData.chainOrgUse = Number(this.formData.chainOrgUse)
+        this.formData.singleOrgUse = Number(this.formData.singleOrgUse)
+      } else {
+        this.selectedMenu = ''
+        this.clear()
+      }
+    },
+    generateList (data) {
+      for (let i = 0; i < data.length; i++) {
+        const node = data[i]
+        const key = node.title
+        this.dataList.push({ key, title: key })
+        node.scopedSlots = { title: 'title' }
+        node.slots = { icon: node.type == '0' ? 'file' : 'pushpin' }
+
+        if (node.children) {
+          this.generateList(node.children)
+        }
+      }
+    },
+    getParentKey (key, tree) {
+      let parentKey
+      for (let i = 0; i < tree.length; i++) {
+        const node = tree[i]
+        if (node.children) {
+          if (node.children.some(item => item.title == key)) {
+            parentKey = node.key
+          } else if (this.getParentKey(key, node.children)) {
+            parentKey = this.getParentKey(key, node.children)
+          }
+        }
+      }
+      return parentKey
+    },
+    onChange (e) {
+      const value = e.target.value
+      const expandedKeys = this.dataList
+        .map(item => {
+          if (item.title.indexOf(value) > -1) {
+            return this.getParentKey(item.title, this.treeData)
+          }
+          return null
+        })
+        .filter((item, i, self) => item && self.indexOf(item) === i)
+      Object.assign(this, {
+        expandedKeys,
+        searchValue: value,
+        autoExpandParent: true
+      })
+    },
+    // 获取菜单树列表
+    getMdMenuList () {
+      getMdMenuList().then(res => {
+        console.log(res, 'res1111111')
+        if (res.status == 200) {
+          this.treeData = res.data
+          console.log(this.treeData, 'this.treeData')
+        }
+      })
+    },
+    // 添加子节点
+    addChild () {
+      if (!this.selectedMenu) {
+        return this.$message.warning('请先选择一个父级菜单')
+      } else if (this.formData.type == '1') {
+        return this.$message.warning('请选择一个页面级菜单')
+      }
+      this.showChildModal = true
+      this.parentData = this.formData
+    },
+    // 添加顶部菜单
+    addTitle () {
+      this.showChildModal = true
+      this.parentData = {}
+    },
+    //  取消选择
+    cancelSel () {
+      this.selectedKeys = []
+      this.selectedMenu = ''
+      this.clear()
+    },
+    // 清空列表
+    clear () {
+      this.form.resetFields()
+      this.formData.id = ''
+      this.formData.name = ''
+      this.formData.routePath = ''
+      this.formData.icon = ''
+      this.formData.routeName = ''
+      this.formData.componentPath = ''
+      this.formData.urlPath = ''
+      this.formData.sort = ''
+      this.formData.type = ''
+	    this.formData.chainOrgUse = ''
+	    this.formData.singleOrgUse = ''
+      this.formData.status = ''
+      this.formData.code = ''
+      this.formData.permission = ''
+      this.formData.isLeaf = true
+    },
+
+    // 删除数据
+    delect () {
+      if (!this.selectedKeys.length) {
+        return this.$message.warning('您还未选择要删除的数据')
+      }
+      const _this = this
+      console.log(_this.formData.id, '_this.formData.id')
+      this.$confirm({
+        title: '警告',
+        content: `确定要删除您选择的 ${_this.formData.name} 的数据吗?`,
+        okText: '确定',
+        cancelText: '取消',
+        onOk () {
+          deleteMdMenu({
+            id: _this.formData.id
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success('删除成功')
+              _this.getMdMenuList()
+            }
+          }).catch(() => {
+            _this.$message.success('删除失败, 请稍后重试')
+          })
+        }
+      })
+    },
+
+    // 保存提交
+    handleSubmit () {
+      const _this = this
+      this.form.validateFields((err, values) => {
+        if (!err) {
+          console.log(values.formData, ' formData.type222222222')
+          saveMdMenu(Object.assign({ id: this.formData.id }, values.formData)).then(res => {
+            console.log(res, 'res--save')
+            if (res.status + '' === '200') {
+              this.$message.success(res.message ? res.message : '保存成功')
+              _this.getMdMenuList()
+              _this.clear()
+            } else {
+              // this.$message.warning(res.message)
+            }
+          })
+        }
+      })
+    },
+    handleCancel () {
+      this.clear()
+    }
+
+  },
+  mounted () {
+  },
+  beforeCreate () {
+    this.form = this.$form.createForm(this, { name: 'menu' })
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.getMdMenuList()
+    })
+  },
+  watch: {
+
+  }
+}
+</script>
+
+<style>
+  .menu-box::-webkit-scrollbar{
+    width: 6px;
+    height: 6px ;
+  }
+
+  .menu-box::-webkit-scrollbar-thumb{
+    width: 6px;
+    height: 6px ;
+    border-radius: 4px;
+    -webkit-box-shadow: inset 0 0 2px #d1d1d1;
+    background: #e4e4e4;
+  }
+
+  .textCount{
+    border: 1px solid #91d5ff;
+    background-color: #e6f7ff;
+    border-radius: 5px;
+    padding: 5px 10px 5px 20px;
+    margin: 10px 0;
+    color: rgba(0, 0, 0, 0.85);
+  }
+  .imgSize{
+    color: #2d8cf0;
+    margin-left: 10px;
+    font-size: 14px;
+  }
+
+</style>

+ 162 - 0
src/views/bnSetting/menusAuth.vue

@@ -0,0 +1,162 @@
+<template>
+  <div>
+    <a-form class="form-box" style="height: 500px;overflow: auto;margin-bottom: 15px;" :form="form" @submit="handleSubmit">
+      <a-tree
+        checkable
+        @check="onCheck"
+        @expand="onExpand"
+        :autoExpandParent="autoExpandParent"
+        v-model="checkedKeys"
+        :treeData="treeData"
+      />
+    </a-form>
+    <a-form-item :wrapper-col="{ offset: 3 }">
+      <a-button type="primary" @click="handleSubmit()">
+        保存
+      </a-button>
+    </a-form-item>
+  </div>
+</template>
+
+<script>
+import { findLsMenu, saveLsMouldMenu, findDdMenu, saveDdMouldMenu } from '@/api/menuSet'
+export default {
+  name: 'MenusAuth',
+  props: {
+    types: {
+      type: String,
+      default: 'dd'
+    }
+  },
+  data () {
+    return {
+      menuIds: '',
+      treeData: [],
+      expandedKeys: [],
+      autoExpandParent: false,
+      checkedKeys: [],
+      checkedData: [],
+      formLayout: 'horizontal',
+      form: this.$form.createForm(this, { name: 'menuModal' })
+    }
+  },
+  methods: {
+    tabChange (v) {
+      console.log(v)
+    },
+    // 初始化树
+    treeInit (dr) {
+      this.treeData = dr.menuList
+      this.menuIds = dr.mould.menuIds
+      if (this.menuIds) {
+        const arr = this.menuIds.split(',')
+        const temp = []
+        arr.map(item => {
+          temp.push(Number(item))
+        })
+        this.checkedData = temp
+        this.expandedKeys = temp
+        // 找出叶子节点
+        this.findLeaf(this.treeData, temp)
+      }
+    },
+    // 获取连锁树数据
+    getfindLsMenu () {
+      findLsMenu().then(res => {
+        console.log(res, '+++++++++连锁+++++++++')
+        if (res.status == 200) {
+          this.treeInit(res.data)
+        }
+      })
+    },
+    // 获取单店树数据
+    getfindDdMenu () {
+      findDdMenu().then(res => {
+        console.log(res, '+++++++++单店+++++++++')
+        if (res.status == 200) {
+          this.treeInit(res.data)
+        }
+      })
+    },
+    onExpand (expandedKeys) {
+      console.log('onExpand', expandedKeys)
+      this.expandedKeys = expandedKeys
+      this.autoExpandParent = false
+    },
+    onCheck (checkedKeys, info) {
+      this.checkedData = [...checkedKeys, ...info.halfCheckedKeys]
+      this.checkedKeys = checkedKeys
+    },
+    // 勾选已选的菜单
+    findLeaf (data, arr) {
+      for (let i = 0; i < data.length; i++) {
+        const node = data[i]
+        if (node.children) {
+          this.findLeaf(node.children, arr)
+        } else {
+          const hasNode = arr.find(item => {
+            return item == node.id
+          })
+          if (hasNode) {
+            this.checkedKeys.push(node.id)
+          }
+        }
+      }
+    },
+    // 保存提交
+    handleSubmit () {
+      const _this = this
+      this.form.validateFields((err, values) => {
+        if (!err) {
+          // console.log(this.checkedData)
+          if (this.checkedData.length == 0) {
+            return this.$message.warning('请先选择菜单')
+          }
+          const arr = this.checkedData.join(',')
+          if (this.types == 'dd') {
+            this.ddSave({ menuIds: arr })
+          } else {
+            this.lsSave({ menuIds: arr })
+          }
+        }
+      })
+    },
+    // 保存单店
+    ddSave (pars) {
+      saveDdMouldMenu(pars).then(res => {
+        console.log(res, 'res--save')
+        if (res.status + '' === '200') {
+          this.$message.success(res.message ? res.message : '保存成功')
+        } else {
+          // this.$message.warning(res.message)
+        }
+      })
+    },
+    // 保存连锁
+    lsSave (pars) {
+      saveLsMouldMenu(pars).then(res => {
+        console.log(res, 'res--save')
+        if (res.status + '' === '200') {
+          this.$message.success(res.message ? res.message : '保存成功')
+        } else {
+          // this.$message.warning(res.message)
+        }
+      })
+    }
+  },
+  mounted () {
+    // 单店
+    if (this.types == 'dd') {
+      this.getfindDdMenu()
+    } else {
+      this.getfindLsMenu()
+    }
+  },
+  beforeCreate () {
+    this.form = this.$form.createForm(this, { name: 'menu' })
+  }
+}
+</script>
+
+<style>
+</style>

+ 41 - 0
src/views/bnSetting/menusAuthTab.vue

@@ -0,0 +1,41 @@
+<template>
+  <div class="menusAuth-cons">
+    <a-tabs @change="tabChange" type="card">
+      <a-tab-pane tab="单店菜单设置" key="1">
+        <menusAuth types="dd"></menusAuth>
+      </a-tab-pane>
+      <a-tab-pane tab="连锁店菜单设置" key="2">
+        <menusAuth types="ls"></menusAuth>
+      </a-tab-pane>
+    </a-tabs>
+  </div>
+</template>
+
+<script>
+  import menusAuth from './menusAuth.vue'
+  export default {
+    name: 'menusAuthTab',
+    components: {
+      menusAuth
+    },
+    data() {
+      return {}
+    },
+    methods: {
+      tabChange(v) {
+        console.log(v)
+      },
+    },
+    beforeRouteEnter (to, from, next) {
+      next(vm => {
+      })
+    },
+  }
+</script>
+
+<style>
+  .menusAuth-cons{
+    background: #fff;
+    padding: 10px;
+  }
+</style>

+ 151 - 0
src/views/chainGroupManagement/chainGroupSetting/associateModal.vue

@@ -0,0 +1,151 @@
+<template>
+  <a-modal
+    centered
+    class="chainGroupAssociate-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="关联分店"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="800">
+    <!-- 操作按钮 -->
+    <div class="table-operator">
+      <a-button id="chainGroupAssociate-add" type="primary" class="button-error" @click="openStoreModal=true">新增分店</a-button>
+    </div>
+    <!-- 列表 -->
+    <a-table
+      class="sTable"
+      ref="table"
+      size="small"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :dataSource="loadData"
+      :scroll="{ y: 500 }"
+      :pagination="false"
+      :loading="loading"
+      bordered>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-button
+          type="link"
+          class="button-error"
+          size="small"
+          icon="close"
+          :id="'chainGroupAssociate-delSubItem'+record.id"
+          @click.stop="handleDisassociate(record)">取消关联</a-button>
+      </template>
+    </a-table>
+    <div class="btn-cont">
+      <a-button id="chainGroupAssociate-back" @click="isShow = false">取消</a-button>
+    </div>
+    <!-- 新增关联分店 -->
+    <chain-group-store-modal :openModal="openStoreModal" :itemSn="itemSn" @close="openStoreModal=false" @ok="handlerOk" />
+  </a-modal>
+</template>
+
+<script>
+import chainGroupStoreModal from './storeModal.vue'
+import { linkageGroupDetail, linkageGroupUnRelation } from '@/api/linkageGroup'
+export default {
+  name: 'ChainGroupAssociateModal',
+  components: { chainGroupStoreModal },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemSn: {
+      type: [Number, String],
+      default: ''
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      form: {},
+      rules: {},
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 16 }
+      },
+      subDealerSn: '',
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '连锁分店名称', dataIndex: 'dealer.name', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '负责人', dataIndex: 'dealer.contactName', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '联系电话', dataIndex: 'dealer.contactPhone', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 120, align: 'center', fixed: 'right' }
+      ],
+      loadData: [],
+      openStoreModal: false,
+      loading: false
+    }
+  },
+  methods: {
+    // 取消关联
+    handleDisassociate (row) {
+      const _this = this
+      _this.$confirm({
+        title: '提示',
+        content: '确认要解除关联关系吗?',
+        centered: true,
+        onOk () {
+          linkageGroupUnRelation({ sn: row.linkageGroupDetailSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$emit('ok')
+              _this.getDetail()
+            }
+          })
+        }
+      })
+    },
+    // 关联成功
+    handlerOk () {
+      this.getDetail()
+      this.$emit('ok')
+    },
+    // 详情
+    getDetail () {
+      this.loading = true
+      linkageGroupDetail({ sn: this.itemSn }).then(res => {
+        this.loading = false
+        if (res.status == 200) {
+          res.data.map((item, index) => {
+            item.no = index + 1
+          })
+          this.loadData = res.data
+        } else {
+          this.loadData = []
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+      } else {
+        this.getDetail()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .chainGroupAssociate-modal{
+    .table-operator{
+      margin-bottom: 15px;
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>

+ 172 - 0
src/views/chainGroupManagement/chainGroupSetting/editModal.vue

@@ -0,0 +1,172 @@
+<template>
+  <a-modal
+    centered
+    class="chainGroupEdit-modal"
+    :footer="null"
+    :maskClosable="false"
+    :title="(itemId?'编辑':'新增')+'连锁组'"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="800">
+    <!-- 表单 -->
+    <div>
+      <a-form-model
+        id="chainGroupEdit-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol"
+      >
+        <a-form-model-item label="连锁组名称" prop="linkageGroupName">
+          <a-input
+            id="chainGroupEdit-linkageGroupName"
+            :maxLength="30"
+            v-model="form.linkageGroupName"
+            placeholder="请输入连锁组名称(最多30个字符)"
+            allowClear />
+        </a-form-model-item>
+        <a-form-model-item label="负责人" prop="majorPersonName">
+          <a-input
+            id="chainGroupEdit-majorPersonName"
+            :maxLength="30"
+            v-model="form.majorPersonName"
+            placeholder="请输入负责人(最多30个字符)"
+            allowClear />
+        </a-form-model-item>
+        <a-form-model-item label="联系电话" prop="contactTel">
+          <a-input
+            id="chainGroupEdit-contactTel"
+            :maxLength="11"
+            v-model="form.contactTel"
+            placeholder="请输入联系电话(最多11个字符)"
+            allowClear />
+        </a-form-model-item>
+        <a-form-model-item label="邮箱" prop="email">
+          <a-input
+            id="chainGroupEdit-email"
+            :maxLength="60"
+            v-model="form.email"
+            placeholder="请输入邮箱(最多60个字符)"
+            allowClear />
+        </a-form-model-item>
+      </a-form-model>
+      <div class="btn-cont">
+        <a-button type="primary" id="chainGroupEdit-save" @click="handleSave">确定</a-button>
+        <a-button id="chainGroupEdit-back" @click="isShow = false" style="margin-left: 15px;">关闭</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { linkageGroupSave } from '@/api/linkageGroup'
+export default {
+  name: 'ChainGroupEditModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemId: {
+      type: [Number, String],
+      default: ''
+    },
+    nowData: {
+      type: Object,
+      default: null
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      form: {
+        linkageGroupName: '',
+        majorPersonName: '',
+        contactTel: '',
+        email: ''
+      },
+      rules: {
+        linkageGroupName: [
+          { required: true, message: '请输入连锁组名称', trigger: 'blur' }
+        ],
+        majorPersonName: [
+          { required: true, message: '请输入负责人', trigger: 'blur' }
+        ],
+        contactTel: [
+          { required: true, message: '请输入联系电话', trigger: 'blur' },
+          { pattern: /^[1][0-9]{10}$/, message: '请输入正确的手机号码!' }
+        ],
+        email: [
+          { required: true, message: '请输入邮箱', trigger: 'blur' },
+          { type: 'email', message: '请输入正确的邮箱' }
+        ]
+      },
+      formItemLayout: {
+        labelCol: { span: 5 },
+        wrapperCol: { span: 16 }
+      }
+    }
+  },
+  methods: {
+    //  保存
+    handleSave () {
+      const _this = this
+      _this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const form = JSON.parse(JSON.stringify(_this.form))
+          form.id = _this.itemId ? _this.itemId : null
+          linkageGroupSave(form).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$emit('ok')
+              _this.isShow = false
+            }
+          })
+        } else {
+          return false
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.form.linkageGroupName = ''
+        this.form.majorPersonName = ''
+        this.form.contactTel = ''
+        this.form.email = ''
+      }
+    },
+    nowData: {
+      handler (newValue, oldValue) {
+        if (this.isShow && newValue) {
+          this.form.linkageGroupName = this.nowData.linkageGroupName
+          this.form.majorPersonName = this.nowData.majorPersonName
+          this.form.contactTel = this.nowData.contactTel
+          this.form.email = this.nowData.email
+        }
+      },
+      deep: true
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .chainGroupEdit-modal{
+    .ant-modal-body {
+      padding: 40px 40px 24px;
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>

+ 248 - 0
src/views/chainGroupManagement/chainGroupSetting/list.vue

@@ -0,0 +1,248 @@
+<template>
+  <a-card size="small" :bordered="false" class="chainGroupSetList-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="chainGroupSetList-linkageGroupName" v-model.trim="queryParam.linkageGroupName" allowClear placeholder="请输入连锁组名称"/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="关联连锁店名称">
+              <a-input id="chainGroupSetList-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="chainGroupSetList-refresh">查询</a-button>
+            <a-button style="margin: 0 0 18px 8px" @click="resetSearchForm()" :disabled="disabled" id="chainGroupSetList-reset">重置</a-button>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 操作按钮 -->
+    <div class="table-operator">
+      <a-button id="chainGroupSetList-add" type="primary" class="button-error" @click="openEditModal=true">新增</a-button>
+    </div>
+    <!-- 列表 -->
+    <a-table
+      class="sTable"
+      ref="table"
+      size="default"
+      :rowKey="(record) => record.linkageGroupSn"
+      :columns="columns"
+      :pagination="pagination"
+      :data-source="list"
+      @expand="expand"
+      @change="change"
+      :expandedRowKeys="expandedRowKeys"
+      :expandRowByClick="true"
+      :scroll="{ y: tableHeight }">
+      <a-table
+        slot="expandedRowRender"
+        :rowKey="(record) => record.id"
+        :columns="innerColumns"
+        :data-source="innerData"
+        :pagination="false"
+      >
+        <!-- 操作 -->
+        <template slot="action" slot-scope="text, record">
+          <a-button
+            type="link"
+            class="button-error"
+            size="small"
+            icon="close"
+            :id="'chainGroupSetList-delSubItem'+record.id"
+            @click.stop="handleDisassociate(record)">取消关联</a-button>
+        </template>
+      </a-table>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-button
+          type="link"
+          class="button-success"
+          size="small"
+          icon="plus"
+          :id="'chainGroupSetList-addSubItem'+record.id"
+          @click.stop="handleAssociate(record)">关联分店</a-button>
+        <a-button
+          type="link"
+          class="button-info"
+          size="small"
+          icon="edit"
+          :id="'chainGroupSetList-addSubItem'+record.id"
+          @click.stop="handleEdit(record)">编辑</a-button>
+      </template>
+    </a-table>
+    <!-- 关联下级 -->
+    <associate-modal :openModal="openModal" :itemSn="itemSn" @ok="addItemOk" @close="closeModal" />
+    <!-- 新增/编辑 -->
+    <chain-group-edit-modal :openModal="openEditModal" :nowData="nowData" :itemId="itemId" @ok="getList" @close="closeEditModal" />
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import associateModal from './associateModal.vue'
+import chainGroupEditModal from './editModal.vue'
+import { linkageGroupList, linkageGroupDetail, linkageGroupUnRelation } from '@/api/linkageGroup'
+export default {
+  components: { STable, VSelect, associateModal, chainGroupEditModal },
+  data () {
+    return {
+      tableHeight: 0,
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 16 }
+      },
+      queryParam: {
+        linkageGroupName: '',
+        dealerName: ''
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      columns: [
+        { title: '连锁组名称', dataIndex: 'linkageGroupName', customRender: function (text) { return text || '--' }, ellipsis: true, 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
+      },
+      innerColumns: [
+        { title: '关联连锁店名称', dataIndex: 'dealer.name', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '负责人', dataIndex: 'dealer.contactName', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '联系电话', dataIndex: 'dealer.contactPhone', customRender: function (text) { return text || '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, align: 'center' }
+      ],
+      innerData: [],
+      openModal: false, //  新增编辑  弹框
+      nowData: null, //  当前记录数据
+      tabInd: '1', //  tabs选中项
+      dealerSn: [],
+      openEditModal: false,
+      itemId: '',
+      itemSn: ''
+    }
+  },
+  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) {
+      this.innerData = []
+      linkageGroupDetail({ sn: record.linkageGroupSn }).then(res => {
+        if (res.status == 200 && res.data && res.data.length) {
+          this.innerData = res.data
+        } else {
+          this.innerData = []
+        }
+        if (res.data.length == 0) {
+          this.$message.info('暂无分店,请关联分店')
+        } else {
+          this.expandedRowKeys = [record.linkageGroupSn]
+        }
+      })
+    },
+    // 添加子级成功
+    addItemOk () {
+      this.getSubItem(this.nowData)
+    },
+    // 获取列表数据
+    getList () {
+      this.disabled = true
+      linkageGroupList(Object.assign(this.parameter, this.queryParam)).then(res => {
+        const data = res.data
+        this.pagination.total = Number(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
+        }
+        this.disabled = false
+        this.list = data.list
+      })
+    },
+    // 关闭  新增编辑 弹框
+    closeEditModal () {
+      this.itemId = ''
+      this.nowData = null
+      this.openEditModal = false
+    },
+    // 编辑连锁组
+    handleEdit (row) {
+      this.itemId = row.id
+      this.nowData = JSON.parse(JSON.stringify(row)) //  为避免编辑数据未改变无法触发表单赋值
+      this.openEditModal = true
+    },
+    //  重置
+    resetSearchForm (flag) {
+      if (!flag) {
+        this.queryParam.linkageGroupName = ''
+        this.queryParam.dealerName = ''
+        this.parameter.pageNo = 1
+        this.parameter.pageSize = 10
+        this.expandedRowKeys = []
+      }
+      this.getList()
+    },
+    // 关联下级
+    handleAssociate (row) {
+      this.itemSn = row.linkageGroupSn
+      this.nowData = row
+      this.openModal = true
+    },
+    // 取消关联
+    handleDisassociate (row) {
+      const _this = this
+      _this.nowData = row
+      _this.$confirm({
+        title: '提示',
+        content: '确认要解除关联的关系吗?',
+        centered: true,
+        onOk () {
+          linkageGroupUnRelation({ sn: row.linkageGroupDetailSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.addItemOk()
+            }
+          })
+        }
+      })
+    },
+    //  关闭弹框
+    closeModal () {
+      this.openModal = false
+    }
+  }
+}
+</script>

+ 116 - 0
src/views/chainGroupManagement/chainGroupSetting/storeModal.vue

@@ -0,0 +1,116 @@
+<template>
+  <a-modal
+    centered
+    class="chainGroupStore-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="新增连锁分店"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="600">
+    <!-- 表单 -->
+    <div>
+      <a-form-model
+        id="chainGroupStore-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol"
+      >
+        <a-form-model-item label="商户名称" prop="dealerSn">
+          <custList ref="custList" id="chainGroupStore-dealerSn" @change="custChange"></custList>
+        </a-form-model-item>
+      </a-form-model>
+      <div class="btn-cont">
+        <a-button type="primary" id="chainGroupStore-save" @click="handleSave">确认关联</a-button>
+        <a-button id="chainGroupStore-back" @click="isShow = false" style="margin-left: 15px;">取消</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import custList from '@/views/common/custList.vue'
+import { linkageGroupRelation } from '@/api/linkageGroup'
+export default {
+  name: 'ChainGroupEditModal',
+  components: { custList },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemSn: {
+      type: [Number, String],
+      default: ''
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      form: {
+        dealerSn: ''
+      },
+      rules: {
+        dealerSn: [
+          { required: true, message: '请输入商户名称', trigger: 'blur' }
+        ]
+      },
+      formItemLayout: {
+        labelCol: { span: 5 },
+        wrapperCol: { span: 16 }
+      }
+    }
+  },
+  methods: {
+    custChange (val) {
+      this.form.dealerSn = val.key
+    },
+    //  保存
+    handleSave () {
+      const _this = this
+      _this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const form = JSON.parse(JSON.stringify(_this.form))
+          form.linkageGroupSn = _this.itemSn
+          linkageGroupRelation(form).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$emit('ok')
+              _this.isShow = false
+            }
+          })
+        } else {
+          return false
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.$refs.custList.resetForm()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .chainGroupStore-modal{
+    .ant-modal-body {
+      padding: 40px 40px 24px;
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>

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

@@ -0,0 +1,69 @@
+<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"
+  >
+    <a-spin v-if="fetching" slot="notFoundContent" size="small" />
+    <a-select-option v-for="item in data" :key="item.sn" :value="item.sn">
+      {{ item.name }}
+    </a-select-option>
+  </a-select>
+</template>
+<script>
+import debounce from 'lodash/debounce'
+import { dealerList } 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
+      dealerList({ 'name': 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)
+    },
+    resetForm () {
+      this.dealerName = []
+    },
+    // 查询详细
+    getDetail (sn) {
+      // dealerFindUpdateInfoBySn({ sn: sn }).then(res => {
+      //   this.$emit('dealerDetail', res.data || null)
+      // })
+    }
+  }
+}
+</script>

+ 0 - 54
src/views/common/editInput.js

@@ -1,54 +0,0 @@
-const EditableCell = {
-  template: `
-      <div style="display:flex;align-items: center;">
-        <div class="editable-cell-input-wrapper">
-          <a-input-number 
-          size="small" 
-          :min="0.1" 
-          :max="100000" 
-          :value="value" 
-          :precision="precision"
-          :step="step"
-          @change="handleChange" 
-          @pressEnter="check"/>
-        </div>
-        <a-icon
-          type="check"
-          slot="suffix"
-          :style="{color: editable?'#08c':'#666', marginLeft: '10px' }"
-          @click="check"
-        />
-      </div>
-    `,
-  props: {
-    text: Number,
-    precision: {
-      type: [Number],
-      default: 2
-    },
-    step: {
-      type: [Number],
-      default: 1
-    }
-  },
-  data() {
-    return {
-      value: this.text,
-      editable: false,
-    };
-  },
-  methods: {
-    handleChange(value) {
-      this.value = value;
-      this.editable = true
-    },
-    check() {
-      if(this.editable){
-        this.editable = false;
-        this.$emit('change', this.value);
-      }
-    },
-  },
-};
-
-export default EditableCell

+ 423 - 0
src/views/power/job/jobs.vue

@@ -0,0 +1,423 @@
+<template>
+  <a-card class="settlement" :bordered="false">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="20">
+          <a-col :md="6" :sm="24">
+            <a-form-item style="margin-bottom: 0;">
+              <a-input v-model.trim="queryParam.name" placeholder="定时器名称" allowClear/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="4" :sm="24">
+            <a-button type="primary" @click="$refs.table.refresh(true)">查询</a-button>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <a-divider />
+    <div class="btns">
+      <a-button @click="addJob()" type="primary" icon="plus-circle">添加JOB</a-button>
+      <a-button @click="startJob()" type="default" icon="play-circle">启动</a-button>
+      <a-button @click="stopJob()" type="default" icon="stop">停止</a-button>
+    </div>
+
+    <s-table
+      ref="table"
+      size="default"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :data="loadData"
+      :bordered="true"
+      :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+    >
+      <span slot="action" slot-scope="text, record">
+        <template>
+          <a @click="editJob(record)">编辑</a>
+          <a-divider type="vertical" />
+          <a @click="deleteRow(record)">删除</a>
+          <a-divider type="vertical" />
+          <a @click="syncJob(record)">立即运行一次</a>
+        </template>
+      </span>
+      <span slot="isEnable" slot-scope="text, record">
+        {{ record.isEnable ? '启用' : '禁用' }}
+      </span>
+      <div slot="status" slot-scope="text, record">
+        <span v-if="record.status === 'STAT'" style="color:green">运行中</span>
+        <span v-if="record.status !== 'STAT'" style="color:red">已停止</span>
+      </div>
+    </s-table>
+
+    <a-modal
+      title="添加JOB"
+      v-model="visible"
+      :footer="null"
+      :maskClosable="false"
+      @cancel="handleCancel"
+    >
+      <a-form
+        @submit="handleSubmit"
+        :form="form"
+      >
+        <a-form-item
+          label="JOB名称"
+          :label-col="{ span: 6 }"
+          :wrapper-col="{ span: 17 }"
+        >
+          <a-input v-decorator="['formData.name',{initialValue: formData.name,rules:[{ required: true, message: '请输入JOB名称' }]}]"/>
+        </a-form-item>
+        <a-form-item
+          label="JOB分组"
+          :label-col="{ span: 6 }"
+          :wrapper-col="{ span: 17 }"
+        >
+          <a-input v-decorator="['formData.group',{initialValue: formData.group,rules:[{ required: true, message: '请输入JOB分组称' }]}]"/>
+        </a-form-item>
+        <a-form-item
+          label="JOB业务类名"
+          :label-col="{ span: 6 }"
+          :wrapper-col="{ span: 17 }"
+        >
+          <a-input v-decorator="['formData.className',{initialValue: formData.className,rules:[{ required: true, message: '请输入JOB业务类名' }]}]"/>
+        </a-form-item>
+        <a-form-item
+          label="CRON表达式"
+          :label-col="{ span: 6 }"
+          :wrapper-col="{ span: 17 }"
+        >
+          <a-input @click="openCronModal" v-model="formData.cron" @change="setCorn">
+            <a-icon slot="prefix" type="schedule" title="corn控件"/>
+            <a-icon v-if="formData.cron" slot="suffix" type="close-circle" @click="formData.cron=''" title="清空"/>
+          </a-input>
+          <JCronModal ref="innerVueCron" :data="formData.cron" @ok="setCorn"></JCronModal>
+        </a-form-item>
+        <a-form-item
+          label="是否启用"
+          :label-col="{ span: 6 }"
+          :wrapper-col="{ span: 17 }"
+        >
+          <a-switch checkedChildren="启用" unCheckedChildren="禁用" v-decorator="['formData.isEnable', { initialValue: formData.isEnable, valuePropName: 'checked' }]" />
+          <!-- <a-switch checkedChildren="启用" unCheckedChildren="禁用" :checked="formData.isEnable" @change="changeStatus"/> -->
+        </a-form-item>
+
+        <div class="jobBtns">
+          <a-button key="back" @click="handleCancel">取消</a-button>
+          <a-button htmlType="submit" :loading="loading" type="primary">
+            确定
+          </a-button>
+        </div>
+
+      </a-form>
+    </a-modal>
+
+  </a-card>
+</template>
+
+<script>
+import { STable } from '@/components'
+import { listJob, pauseJob, resumeJob, delJob, callJob, addJob } from '@/api/job.js'
+import JCronModal from '@/components/Cron/JCronModal'
+
+export default {
+  name: 'Jobs',
+  components: {
+    STable,
+    JCronModal
+  },
+  data () {
+    return {
+      showCron: false,
+      // 查询参数
+      queryParam: {
+        name: ''
+      },
+      selectedRowKeys: [],
+      visible: false,
+      loading: false,
+      formLayout: 'horizontal',
+      formData: {},
+      formBackData: {
+        name: '',
+        group: '',
+        className: '',
+        cron: '',
+        isEnable: false
+      },
+      form: this.$form.createForm(this),
+      // 表头
+      columns: [
+        {
+          title: '序号',
+          dataIndex: 'no',
+          width: '70px',
+          align: 'center'
+        },
+        {
+          title: 'JOB名称',
+          dataIndex: 'name',
+          width: '150px',
+          align: 'center'
+        },
+        {
+          title: 'JOB状态',
+          dataIndex: 'status',
+          width: '100px',
+          align: 'center',
+          scopedSlots: { customRender: 'status' }
+        },
+        {
+          title: 'JOB分组',
+          dataIndex: 'group',
+          width: '150px',
+          align: 'center'
+        },
+        {
+          title: 'JOB业务类名',
+          dataIndex: 'className',
+          width: '200px',
+          align: 'center'
+        },
+        {
+          title: 'CRON表达式',
+          dataIndex: 'cron',
+          width: '150px',
+          align: 'center'
+        },
+        {
+          title: '是否启用',
+          dataIndex: 'isEnable',
+          align: 'center',
+          width: '100px',
+          scopedSlots: { customRender: 'isEnable' }
+        },
+        {
+          title: '操作',
+          dataIndex: 'action',
+          width: '250px',
+          align: 'center',
+          scopedSlots: { customRender: 'action' }
+        }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        return listJob(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].isEnable = data.list[i].isEnable + '' === '1'
+          }
+          return data
+        })
+      }
+    }
+  },
+  created () {
+
+  },
+  methods: {
+    // 打开cron 表达式弹框
+    openCronModal () {
+      this.$refs.innerVueCron.show()
+    },
+    setCorn (data) {
+      console.log('cron data', data)
+      // this.formData.cron = data
+      this.$set(this.formData, 'cron', data)
+    },
+    handleSubmit (e) {
+      e.preventDefault()
+      this.form.validateFields((err, values) => {
+        if (!err) {
+          // 保存数据
+          let params = Object.assign(this.formData, values.formData)
+          params = Object.assign({}, params)
+          params.isEnable = params.isEnable ? 1 : 0
+          params.id = this.formData.id
+
+          if (params.cron == '' || params.cron.length == 0) {
+            this.$message.warning('请输入CRON表达式')
+            return
+          }
+
+          this.loading = true
+          addJob(params).then(res => {
+            console.log(res)
+            if (res.status + '' === '200') {
+              this.$message.success(params.id ? '修改成功' : '保存成功')
+              this.visible = false
+              this.$refs.table.refresh(true)
+            } else {
+              // this.$message.warning(res.message)
+            }
+            this.loading = false
+          })
+        }
+      })
+    },
+    // 编辑
+    editJob (record) {
+      this.visible = true
+      this.formData = Object.assign({}, {
+        id: record.id,
+        name: record.name,
+        group: record.group,
+        className: record.className,
+        cron: record.cron,
+        isEnable: record.isEnable
+      })
+    },
+    /**
+     * 删除选中的job
+     * @param params
+     */
+    deleteRow (record) {
+      const that = this
+      const h = this.$createElement
+      this.$confirm({
+        title: '提示',
+        content: h('div', {
+          style: {
+            textAlign: 'center'
+          }
+        }, [
+          h('div', '删除后,数据将无法恢复。'),
+          h('div', '确认删除吗?')
+        ]),
+        onOk () {
+          delJob({ id: record.id }).then(res => {
+            if (res.status === '200') {
+              that.$message.success('删除成功')
+              that.$refs.table.refresh()
+            }
+          })
+        }
+      })
+    },
+    /**
+     * 立即执行一次
+     * @param params
+     */
+    syncJob (record) {
+      const that = this
+      const h = this.$createElement
+      this.$confirm({
+        title: '提示',
+        content: h('div', {
+          style: {
+            textAlign: 'center'
+          }
+        }, [
+          h('div', '是否立即执行一次定时器。')
+        ]),
+        onOk () {
+          callJob({ id: record.id }).then(res => {
+            if (res.status === '200') {
+              that.$message.success('执行成功')
+              that.$refs.table.refresh()
+            }
+          })
+        }
+      })
+    },
+    handleCancel (e) {
+      this.visible = false
+      this.loading = false
+      this.formData = Object.assign({}, this.formBackData)
+      this.form.resetFields()
+    },
+    addJob () {
+      this.formData = Object.assign({}, this.formBackData)
+      this.form.resetFields()
+      this.visible = true
+    },
+    /**
+     * 批量启动
+     */
+    startJob () {
+      const _this = this
+      const checkIds = this.selectedRowKeys
+      if (checkIds.length) {
+        // 调用后台启动方法
+        resumeJob({
+          ids: checkIds
+        }).then(res => {
+          if (res.status === '200') {
+            _this.$message.success('操作成功')
+          } else {
+            _this.$message.info(res.message)
+          }
+          _this.$refs.table.refresh()
+        })
+      } else {
+        this.$message.info('请选择需要启动的服务')
+      }
+    },
+    /**
+     * 批量停止
+     */
+    stopJob () {
+      const _this = this
+      const h = this.$createElement
+      const checkIds = this.selectedRowKeys
+      if (checkIds.length) {
+        this.$confirm({
+          title: '提示',
+          content: h('div', {
+            style: {
+              textAlign: 'center'
+            }
+          }, [
+            h('div', '您确定停止所选的服务吗?')
+          ]),
+          onOk () {
+            pauseJob({
+              'ids': checkIds
+            }).then(res => {
+              if (res.status === '200') {
+                _this.$message.success('操作成功')
+              } else {
+                _this.$message.info(res.message)
+              }
+              _this.$refs.table.refresh()
+            })
+          }
+        })
+      } else {
+        this.$message.info('请选择需要停止的服务')
+      }
+    },
+    /**
+     * 获取选中的列表
+     * @returns {Array}
+     */
+    onSelectChange (selectedRowKeys) {
+      this.selectedRowKeys = selectedRowKeys
+    }
+  }
+}
+</script>
+<style>
+  .jobBtns{
+    text-align: center;
+    padding-top: 20px;
+  }
+  .jobBtns button{
+    margin: 0 10px;
+  }
+  .ant-modal-footer{
+    text-align: center;
+  }
+  .ant-modal-body .ant-form-item{
+    margin-bottom: 10px;
+  }
+  .btns{
+    padding-bottom: 15px;
+  }
+  .btns button{
+    margin-right: 15px;
+  }
+  .ant-table-thead > tr > th, .ant-table-tbody > tr > td{
+    word-break: break-all;
+  }
+</style>

+ 306 - 0
src/views/power/menu/childModal.vue

@@ -0,0 +1,306 @@
+<template>
+  <div>
+    <a-modal class="modalBox" :title="titleText" v-model="isshow" @cancle="cancel">
+      <a-form :form="form" @submit="handleSubmit">
+        <!-- 上级菜单 -->
+        <a-form-item label="上级菜单" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <div >
+            <span >{{ parentTitle }}</span>
+          </div>
+
+        </a-form-item>
+        <!-- 类型 -->
+        <a-form-item label="类型" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-select
+            @change="selectChange"
+            :disabled="disabled"
+            v-decorator="[
+              'formData.type',
+              {
+                initialValue: formData.type,
+                rules: [{ required: true, message: '请选择状态!' }] },
+            ]"
+            style="width: 100%"
+            placeholder="请选择菜单类型"
+          >
+            <a-select-option :value="0">页面类型</a-select-option>
+            <a-select-option :value="1">按钮类型</a-select-option>
+          </a-select>
+        </a-form-item>
+
+        <!-- 名称 -->
+        <a-form-item label="名称" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入名称(最多30个字符)"
+            v-decorator="['formData.name', {
+              initialValue: formData.name,
+              getValueFromEvent: $filterEmpty,
+              rules: [{ required: true, message: '请输入名称!' }] }]"
+          />
+        </a-form-item>
+        <!-- 路由英文名 -->
+        <!-- <a-form-item v-if="!formData.type" label="路由英文名" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入路由英文名"
+            v-decorator="['formData.routeName', {
+              initialValue: formData.routeName,
+              rules: [{ required: true, message: '请输入路由英文名!' }] }]"
+          />
+        </a-form-item> -->
+        <!-- 路径 -->
+        <!-- <a-form-item v-if="!formData.type" label="路径" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+             <a-input placeholder="请输入路径"
+                      v-decorator="['formData.routePath', {
+                        initialValue: formData.routePath,
+                        rules: [{ required: true, message: '请输入路径!' }] }]"
+             />
+           </a-form-item> -->
+        <!-- 请求路径 -->
+        <!-- <a-form-item v-if="formData.type==1" label="请求路径" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+             <a-input placeholder="请输入请求路径"
+                      v-decorator="['formData.urlPath', {
+                        initialValue: formData.urlPath,
+                        rules: [{ required: true, message: '请输入请求路径!' }] }]"
+             />
+           </a-form-item> -->
+        <!-- 前端权限编码 -->
+        <a-form-item label="前端权限编码" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入前端权限编码"
+            v-decorator="[
+              'formData.code',
+              {
+                initialValue: formData.code,
+                rules: [{ required: true, message: '请输入前端权限编码!' }] },
+            ]"
+          />
+
+        </a-form-item>
+        <!-- 后台权限编码 -->
+        <a-form-item label="后台权限编码" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入后台权限编码"
+            v-decorator="[
+              'formData.permission',
+              {initialValue: formData.permission},
+            ]"
+          />
+
+        </a-form-item>
+
+        <!-- 图标 -->
+        <!-- <a-form-item v-if="!formData.type" label="图标" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入图标名称"
+            v-decorator="['formData.icon', {
+              initialValue: formData.icon,
+              rules: [] }]"
+          />
+        </a-form-item> -->
+        <!-- 前端组件 -->
+        <!-- <a-form-item v-if="!formData.type" label="前端组件" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入前端组件路径"
+            v-decorator="['formData.componentPath', {
+              initialValue: formData.componentPath,
+              rules: [{ required: true, message: '请输入前端组件路径!' }] }]"
+          />
+        </a-form-item> -->
+
+        <!-- 第三方链接 -->
+        <!-- <a-form-item v-if="!formData.type" label="第三方链接" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input
+            placeholder="请输入第三方链接地址"
+            v-decorator="['formData.urlPath', {
+              initialValue: formData.urlPath,
+              rules: [] }]"
+          />
+        </a-form-item> -->
+
+        <!-- 排序值 -->
+        <a-form-item label="排序值" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-input-number
+            style="width: 100%;"
+            type="number"
+            placeholder="请输入排序值(0~999999)"
+            v-decorator="['formData.sort', {
+              initialValue: formData.sort,
+              rules: [] }]"
+            :max="999999"
+            :min="0"
+          />
+        </a-form-item>
+        <!-- 状态 -->
+        <a-form-item label="启用" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-radio-group
+            name="radioGroup"
+            v-decorator="[
+              'formData.status',
+              {
+                initialValue: formData.status,
+                rules: [{ required: true, message: '请选择状态!' }] },
+            ]"
+          >
+            <a-radio :value="1">是</a-radio>
+            <a-radio :value="0">否</a-radio>
+          </a-radio-group>
+        </a-form-item>
+
+        <a-form-item :wrapper-col="{ span: 12, offset: 5 }">
+          <a-button type="primary" @click="handleSubmit()">
+            保存
+          </a-button>
+          <a-button :style="{ marginLeft: '8px' }" @click="handleCancel()">
+            取消
+          </a-button>
+        </a-form-item>
+      </a-form>
+
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import { saveMenu } from '@/api/menu.js'
+export default {
+  name: 'ChildModal',
+  components: {
+    STable, VSelect
+  },
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    data: {
+      type: Object,
+      default: function () {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      isshow: this.visible,
+      titleText: '',
+      disabled: false,
+      parentTitle: '',
+      formLayout: 'horizontal',
+      form: this.$form.createForm(this, { name: 'childModal' }),
+      formData: {
+        parentId: '',
+        name: '',
+        routePath: '',
+        icon: '',
+        routeName: '',
+        code: '',
+        permission: '',
+        componentPath: '',
+        urlPath: '',
+        sort: '',
+        type: undefined,
+        status: 1 // 活动状态
+      }
+    }
+  },
+  methods: {
+    cancel (e) {
+      this.clear()
+      this.$emit('close')
+    },
+
+    selectChange (val) {
+      this.formData.type = val
+      console.log(val)
+    },
+    // 保存提交
+    handleSubmit () {
+      const _this = this
+      this.form.validateFields((err, values) => {
+        if (!err) {
+          console.log(values.formData, ' formData.type222222222')
+          saveMenu(Object.assign(this.formData, values.formData)).then(res => {
+            console.log(res, 'res--save')
+            if (res.status + '' === '200') {
+              this.$message.success(res.message ? res.message : '保存成功')
+              this.$emit('refresh')
+              setTimeout(function () {
+                _this.cancel()
+              }, 300)
+            } else {
+              // this.$message.warning(res.message)
+            }
+          })
+        }
+      })
+    },
+    // 取消
+    handleCancel () {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确定取消吗?',
+        okText: '确定',
+        cancelText: '取消',
+        onOk () {
+          _this.clear()
+          _this.cancel()
+        }
+      })
+    },
+    clear () {
+      this.form.resetFields()
+      this.parentTitle = ''
+      this.formData.parentId = ''
+      this.formData.name = ''
+      this.formData.routePath = ''
+      this.formData.icon = ''
+      this.formData.routeName = ''
+      this.formData.componentPath = ''
+      this.formData.urlPath = ''
+      this.formData.sort = ''
+      this.formData.type = ''
+      this.formData.status = 1
+      this.formData.code = ''
+      this.formData.permission = ''
+    }
+
+  },
+  mounted () {
+  },
+  beforeCreate () {
+    this.form = this.$form.createForm(this, { name: 'childModal' })
+  },
+  watch: {
+    visible (newValue, oldValue) {
+      this.isshow = newValue
+    },
+    isshow (newValue, oldValue) {
+      if (newValue) {
+        if (this.data.id) { // 添加子菜单
+          this.titleText = '添加子菜单'
+          this.disabled = false
+          console.log(this.data, 'this.data')
+          this.formData.parentId = this.data.id
+          this.parentTitle = this.data.name
+        } else { // 添加顶菜单
+          this.titleText = '添加顶菜单'
+          this.formData.type = 0
+          this.disabled = true
+        }
+      } else {
+        this.cancel()
+      }
+    }
+  }
+}
+</script>
+
+<style >
+  .modalBox{
+  }
+  .ant-modal-footer {
+    display: none;
+  }
+</style>

+ 462 - 0
src/views/power/menu/menu.vue

@@ -0,0 +1,462 @@
+<template>
+  <a-card :bordered="false">
+    <a-row :gutter="24">
+      <a-button style="margin-right: 10px;" type="primary" icon="plus" @click="addChild">添加子菜单</a-button>
+      <a-button style="margin-right: 10px;background-color: #19be6b;color: #fff;" type="" icon="plus" @click="addTitle">添加顶部菜单</a-button>
+      <a-button style="margin-right: 10px;background-color: red;color: #fff;" type="" icon="delete" @click="delect()">删除</a-button>
+
+    </a-row>
+    <a-row :gutter="24">
+      <!-- 左侧菜单树列表 -->
+      <a-col :span="8">
+        <a-row :gutter="24" class="textCount">
+          <a-icon type="info-circle" style="color: #1890FF;margin-right: 10px;" />
+          <span>当前选择:<span style="color: #40a9ff;font-weight: 600;">{{ selectedMenu }}</span><span v-if="selectedKeys.length" class="imgSize" @click="cancelSel">取消选择</span></span>
+        </a-row>
+
+        <a-row :gutter="24" >
+          <a-input-search placeholder="输入搜索菜单名搜索" style="width: 100%" @change="onChange" />
+          <a-tree
+            @expand="onExpand"
+            :treeData="getMenus"
+            :expandedKeys="expandedKeys"
+            :autoExpandParent="autoExpandParent"
+            @select="onSelect"
+            :selectedKeys="selectedKeys"
+            showIcon
+          >
+            <template slot="title" slot-scope="{title}">
+              <span v-if="title.indexOf(searchValue) > -1">
+                {{ title.substr(0, title.indexOf(searchValue)) }}
+                <span style="color: #f50">{{ searchValue }}</span>
+                {{ title.substr(title.indexOf(searchValue) + searchValue.length) }}
+              </span>
+              <span v-else>{{ title }}</span>
+            </template>
+            <a-icon slot="file" type="file" />
+            <a-icon slot="pushpin" type="pushpin" />
+          </a-tree>
+        </a-row>
+      </a-col>
+      <!-- 右侧 -->
+      <a-col :span="16" >
+        <a-form :form="form" @submit="handleSubmit">
+          <!-- 类型 -->
+          <a-form-item label="类型" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <div v-if="!formData.type||formData.type=='0'">
+              <a-icon type="file" style="margin-right: 10px;" /><span >页面菜单</span>
+            </div>
+            <div v-if="formData.type=='1'">
+              <a-icon type="pushpin" style="margin-right: 10px;" /><span >操作按钮</span>
+            </div>
+          </a-form-item>
+
+          <!-- 名称 -->
+          <a-form-item label="名称" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入名称(最多30个字符)"
+              :maxLength="30"
+              v-decorator="['formData.name', {
+                initialValue: formData.name,
+                getValueFromEvent: $filterEmpty,
+                rules: [{ required: true, message: '请输入名称!' }] }]"
+            />
+          </a-form-item>
+          <!-- 路由英文名 -->
+          <!-- <a-form-item v-if="!formData.type||formData.type=='0'" label="路由英文名" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入路由英文名"
+              v-decorator="['formData.routeName', {
+                initialValue: formData.routeName,
+                rules: [{ required: true, message: '请输入路由英文名!' }] }]"
+            />
+          </a-form-item> -->
+          <!-- 路径 -->
+          <!-- <a-form-item v-if="!formData.type||formData.type=='0'" label="路径" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入路径"
+              v-decorator="['formData.routePath', {
+                initialValue: formData.routePath,
+                rules: [{ required: true, message: '请输入路径!' }] }]"
+            />
+          </a-form-item> -->
+          <!-- 请求路径 -->
+          <!-- <a-form-item v-if="formData.type==1" label="请求路径" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入请求路径"
+              v-decorator="['formData.urlPath', {
+                initialValue: formData.urlPath,
+                rules: [{ required: true, message: '请输入请求路径!' }] }]"
+            />
+          </a-form-item> -->
+          <!-- 前端权限编码 -->
+          <a-form-item label="前端权限编码" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入前端权限编码"
+              v-decorator="[
+                'formData.code',
+                {
+                  initialValue: formData.code,
+                  rules: [{ required: true, message: '请输入前端权限编码!' }] },
+              ]"
+            />
+          </a-form-item>
+          <!-- 后台权限编码 -->
+          <a-form-item label="后台权限编码" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入后台权限编码"
+              v-decorator="[
+                'formData.permission',
+                {
+                  initialValue: formData.permission,
+                  rules: [{ required: formData.isLeaf, message: '请输入后台权限编码!' }] },
+              ]"
+            />
+          </a-form-item>
+          <!-- 图标 -->
+          <!-- <a-form-item v-if="!formData.type ||formData.type=='0' " label="图标" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入图标名称"
+              v-decorator="['formData.icon', {
+                initialValue: formData.icon,
+                rules: [] }]"
+            />
+          </a-form-item> -->
+          <!-- 前端组件 -->
+          <!-- <a-form-item v-if="!formData.type ||formData.type=='0'" label="前端组件" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入前端组件路径"
+              v-decorator="['formData.componentPath', {
+                initialValue: formData.componentPath,
+                rules: [{ required: true, message: '请输入前端组件路径!' }] }]"
+            />
+          </a-form-item> -->
+
+          <!-- 第三方链接 -->
+          <!-- <a-form-item v-if="!formData.type ||formData.type=='0'" label="第三方链接" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input
+              placeholder="请输入第三方链接地址"
+              v-decorator="['formData.urlPath', {
+                initialValue: formData.urlPath,
+                rules: [] }]"
+            />
+          </a-form-item> -->
+
+          <!-- 排序值 -->
+          <a-form-item label="排序值" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-input-number
+              style="width: 100%;"
+              type="number"
+              placeholder="请输入排序值(0~999999)"
+              v-decorator="['formData.sort', {
+                initialValue: formData.sort,
+                rules: [] }]"
+              :max="999999"
+              :min="0"
+            />
+          </a-form-item>
+          <!-- 状态 -->
+          <a-form-item label="启用" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+            <a-radio-group
+              name="radioGroup"
+              v-decorator="[
+                'formData.status',
+                {
+                  initialValue: formData.status,
+                  rules: [{ required: true, message: '请选择状态!' }] },
+              ]"
+            >
+              <a-radio :value="1">是</a-radio>
+              <a-radio :value="0">否</a-radio>
+            </a-radio-group>
+          </a-form-item>
+
+          <a-form-item :wrapper-col="{ span: 12, offset: 5 }">
+            <a-button type="primary" @click="handleSubmit()">
+              保存
+            </a-button>
+            <a-button :style="{ marginLeft: '8px' }" @click="clear">
+              重置
+            </a-button>
+          </a-form-item>
+        </a-form>
+
+      </a-col>
+    </a-row>
+    <childModal :visible="showChildModal" @refresh="getMenuList" :data="parentData" @close="showChildModal = false"></childModal>
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import childModal from './childModal.vue'
+import { getMenuList, saveMenu, deleteMenu } from '@/api/menu.js'
+
+export default {
+  name: 'Menu',
+  components: {
+    STable, VSelect, childModal
+  },
+  props: {},
+  data () {
+    return {
+      treeData: [],
+      dataList: [],
+      searchValue: '',
+      expandedKeys: [],
+      autoExpandParent: true,
+      selectedKeys: [],
+      selectedMenu: '', // 选择的树节点名
+      formLayout: 'horizontal',
+      form: this.$form.createForm(this, { name: 'menu' }),
+      showChildModal: false,
+      parentData: {}, // 父级菜单
+      formData: {
+        id: '',
+        name: '',
+        routePath: '',
+        icon: '',
+        routeName: '',
+        componentPath: '',
+        urlPath: '',
+        code: '',
+        permission: '',
+        sort: '',
+        type: '0',
+        isLeaf: true,
+        status: '' // 活动状态
+      }
+    }
+  },
+  computed: {
+    getMenus () {
+      this.generateList(this.treeData)
+      return this.treeData
+    }
+  },
+  methods: {
+    onExpand (expandedKeys) {
+      // console.log('onExpand', expandedKeys)
+      this.expandedKeys = expandedKeys
+      this.autoExpandParent = false
+    },
+
+    onSelect (selectedKeys, info) {
+      console.log('onSelect', info)
+      this.selectedKeys = selectedKeys
+      if (info.selected) {
+        const data = info.selectedNodes[0].data.props
+        const isLeaf = data.dataRef.children
+        // this.formData = Object.assign({}, this.formData, info.selectedNodes[0].data.props)
+        this.formData = {
+          id: data.id,
+          name: data.name,
+          routePath: data.routePath,
+          icon: data.icon,
+          routeName: data.routeName,
+          componentPath: data.componentPath,
+          urlPath: data.urlPath,
+          code: data.code,
+          permission: data.permission,
+          sort: data.sort,
+          type: data.type,
+          status: data.status,
+          isLeaf: !(isLeaf && isLeaf.length)
+        }
+
+        this.selectedMenu = this.formData.name
+        this.formData.status = Number(this.formData.status)
+      } else {
+        this.selectedMenu = ''
+        this.clear()
+      }
+    },
+    generateList (data) {
+      for (let i = 0; i < data.length; i++) {
+        const node = data[i]
+        const key = node.title
+        this.dataList.push({ key, title: key })
+        node.scopedSlots = { title: 'title' }
+        node.slots = { icon: node.type == '0' ? 'file' : 'pushpin' }
+
+        if (node.children) {
+          this.generateList(node.children)
+        }
+      }
+    },
+    getParentKey (key, tree) {
+      let parentKey
+      for (let i = 0; i < tree.length; i++) {
+        const node = tree[i]
+        if (node.children) {
+          if (node.children.some(item => item.title == key)) {
+            parentKey = node.key
+          } else if (this.getParentKey(key, node.children)) {
+            parentKey = this.getParentKey(key, node.children)
+          }
+        }
+      }
+      return parentKey
+    },
+    onChange (e) {
+      const value = e.target.value
+      const expandedKeys = this.dataList
+        .map(item => {
+          if (item.title.indexOf(value) > -1) {
+            return this.getParentKey(item.title, this.treeData)
+          }
+          return null
+        })
+        .filter((item, i, self) => item && self.indexOf(item) === i)
+      Object.assign(this, {
+        expandedKeys,
+        searchValue: value,
+        autoExpandParent: true
+      })
+    },
+    // 获取菜单树列表
+    getMenuList () {
+      getMenuList().then(res => {
+        console.log(res, 'res1111111')
+        if (res.status == 200) {
+          this.treeData = res.data
+          console.log(this.treeData, 'this.treeData')
+        }
+      })
+    },
+    // 添加子节点
+    addChild () {
+      if (!this.selectedMenu) {
+        return this.$message.warning('请先选择一个父级菜单')
+      } else if (this.formData.type == '1') {
+        return this.$message.warning('请选择一个页面级菜单')
+      }
+      this.showChildModal = true
+      this.parentData = this.formData
+    },
+    // 添加顶部菜单
+    addTitle () {
+      this.showChildModal = true
+      this.parentData = {}
+    },
+
+    //  取消选择
+    cancelSel () {
+      this.selectedKeys = []
+      this.selectedMenu = ''
+      this.clear()
+    },
+    // 清空列表
+    clear () {
+      this.form.resetFields()
+      this.formData.id = ''
+      this.formData.name = ''
+      this.formData.routePath = ''
+      this.formData.icon = ''
+      this.formData.routeName = ''
+      this.formData.componentPath = ''
+      this.formData.urlPath = ''
+      this.formData.sort = ''
+      this.formData.type = ''
+      this.formData.status = ''
+      this.formData.code = ''
+      this.formData.permission = ''
+      this.formData.isLeaf = true
+    },
+
+    // 删除数据
+    delect () {
+      if (!this.selectedKeys.length) {
+        return this.$message.warning('您还未选择要删除的数据')
+      }
+      const _this = this
+      console.log(_this.formData.id, '_this.formData.id')
+      this.$confirm({
+        title: '警告',
+        content: `确定要删除您选择的 ${_this.formData.name} 的数据吗?`,
+        okText: '确定',
+        cancelText: '取消',
+        onOk () {
+          deleteMenu({
+            id: _this.formData.id
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success('删除成功')
+              _this.getMenuList()
+            }
+          }).catch(() => {
+            _this.$message.success('删除失败, 请稍后重试')
+          })
+        }
+      })
+    },
+
+    // 保存提交
+    handleSubmit () {
+      const _this = this
+      this.form.validateFields((err, values) => {
+        if (!err) {
+          console.log(values.formData, ' formData.type222222222')
+          saveMenu(Object.assign({ id: this.formData.id }, values.formData)).then(res => {
+            console.log(res, 'res--save')
+            if (res.status + '' === '200') {
+              this.$message.success(res.message ? res.message : '保存成功')
+              _this.getMenuList()
+              _this.clear()
+            } else {
+              // this.$message.warning(res.message)
+            }
+          })
+        }
+      })
+    },
+    handleCancel () {
+      this.clear()
+    }
+
+  },
+  mounted () {
+  },
+  beforeCreate () {
+    this.form = this.$form.createForm(this, { name: 'menu' })
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.getMenuList()
+    })
+  },
+  watch: {
+
+  }
+}
+</script>
+
+<style>
+  .menu-box::-webkit-scrollbar{
+    width: 6px;
+    height: 6px ;
+  }
+
+  .menu-box::-webkit-scrollbar-thumb{
+    width: 6px;
+    height: 6px ;
+    border-radius: 4px;
+    -webkit-box-shadow: inset 0 0 2px #d1d1d1;
+    background: #e4e4e4;
+  }
+
+  .textCount{
+    border: 1px solid #91d5ff;
+    background-color: #e6f7ff;
+    border-radius: 5px;
+    padding: 5px 10px 5px 20px;
+    margin: 10px 0;
+    color: rgba(0, 0, 0, 0.85);
+  }
+  .imgSize{
+    color: #2d8cf0;
+    margin-left: 10px;
+    font-size: 14px;
+  }
+
+</style>

+ 71 - 0
src/views/power/menuMould/list.vue

@@ -0,0 +1,71 @@
+<template>
+  <a-card size="small" :bordered="false" class="customerTypeList-wrap">
+    <!-- 列表 -->
+    <s-table
+      class="sTable"
+      ref="table"
+      size="default"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :data="loadData"
+      :scroll="{ y: 300 }"
+      bordered>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-icon type="setting" v-if="record.scopeType=='dz'" title="菜单权限" :style="{ fontSize: '20px', color: '#e29e14', padding: '0 10px' }" @click="handleSet(record)" />
+        <span v-else>--</span>
+      </template>
+    </s-table>
+    <!-- 新增/编辑 -->
+    <menu-mould-set-modal :openModal="openModal" :nowData="nowData" :itemId="itemId" @close="closeModal" />
+  </a-card>
+</template>
+
+<script>
+import { mouldList } from '@/api/mould'
+import { STable, VSelect } from '@/components'
+import menuMouldSetModal from './setModal.vue'
+export default {
+  components: { STable, VSelect, menuMouldSetModal },
+  data () {
+    return {
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '模板名称', dataIndex: 'name', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '模板权限类型', dataIndex: 'ruletype', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '备注', dataIndex: 'remarks', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 200, align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        return mouldList(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
+            data.list[i].ruletype = data.list[i].scopeType == 'all' ? '全部权限' : '定制权限'
+          }
+          return data
+        })
+      },
+      openModal: false, //  新增编辑客户类型  弹框
+      itemId: '', //  当前id
+      nowData: null //  当前记录数据
+    }
+  },
+  methods: {
+    // 菜单权限设置
+    handleSet (row) {
+      this.itemId = row ? row.id : null
+      this.nowData = row || null
+      this.openModal = true
+    },
+    //  关闭弹框
+    closeModal () {
+      this.itemId = ''
+      this.nowData = null
+      this.openModal = false
+    }
+  }
+}
+</script>

+ 174 - 0
src/views/power/menuMould/setModal.vue

@@ -0,0 +1,174 @@
+<template>
+  <a-modal
+    centered
+    class="customerTypeEdit-modal"
+    :footer="null"
+    :maskClosable="false"
+    :title="modalTit"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="800">
+    <!-- 表单 -->
+    <div>
+      <a-form-model
+        id="customerTypeEdit-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol"
+      >
+        <a-tree
+          checkable
+          @check="onCheck"
+          @expand="onExpand"
+          :expandedKeys="expandedKeys"
+          :autoExpandParent="autoExpandParent"
+          v-model="checkedKeys"
+          :treeData="treeData"
+        />
+      </a-form-model>
+      <div class="btn-cont">
+        <a-button type="primary" id="customer-type-edit-modal-save" @click="handleSave">保存</a-button>
+        <a-button id="customer-type-edit-modal-back" @click="isShow = false" style="margin-left: 15px;">返回列表</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { findMouldMenuDetail, findMouldMenuSave } from '@/api/mould'
+export default {
+  name: 'MenuMouldSetModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemId: {
+      type: [Number, String],
+      default: ''
+    },
+    nowData: {
+      type: Object,
+      default: null
+    }
+  },
+  computed: {
+    modalTit () {
+      return '分配权限(' + (this.nowData && this.nowData.name ? this.nowData.name : '--') + ')'
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      detailData: null, //  数据
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 16 }
+      },
+      form: {},
+      rules: {},
+      treeData: [],
+      expandedKeys: [],
+      autoExpandParent: true,
+      checkedKeys: [],
+      checkedData: []
+    }
+  },
+  methods: {
+    onExpand (expandedKeys) {
+      this.expandedKeys = expandedKeys
+      this.autoExpandParent = false
+    },
+    onCheck (checkedKeys, info) {
+      this.checkedData = [...checkedKeys, ...info.halfCheckedKeys]
+      this.checkedKeys = checkedKeys
+    },
+    //  保存
+    handleSave () {
+      const _this = this
+      if (this.checkedData.length == 0) {
+        return this.$message.warning('请先选择菜单')
+      }
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const arr = _this.checkedData.join(',')
+          findMouldMenuSave({ id: _this.itemId, menuIds: arr }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.isShow = false
+            }
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    // 详情
+    getDetail () {
+      findMouldMenuDetail({ id: this.itemId, appType: 2 }).then(res => {
+        if (res.status == 200) {
+          this.treeData = res.data.menuList
+          if (res.data.mould.menuIds) {
+            const arr = res.data.mould.menuIds.split(',')
+            this.checkedData = arr
+            // 找出叶子节点
+            this.findLeaf(this.treeData, arr)
+          }
+        }
+      })
+    },
+    // 查找叶子节点
+    findLeaf (data, arr) {
+      for (let i = 0; i < data.length; i++) {
+        const node = data[i]
+        if (node.children) {
+          this.findLeaf(node.children, arr)
+        } else {
+          const hasNode = arr.find(item => {
+            return item == node.id
+          })
+          if (hasNode) {
+            this.expandedKeys.push(node.id)
+            this.checkedKeys.push(node.id)
+          }
+        }
+      }
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.$refs.ruleForm.resetFields()
+        this.checkedKeys = []
+        this.expandedKeys = []
+      }
+    },
+    itemId (newValue, oldValue) {
+      if (this.isShow && newValue) {
+        this.getDetail()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .customerTypeEdit-modal{
+    .ant-modal-body {
+      padding: 40px 40px 24px;
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>

+ 10 - 17
src/views/power/role/menuModal.vue

@@ -1,6 +1,12 @@
 <template>
   <div>
-    <a-modal class="modalBox" :title="roleName" v-model="isshow" @cancle="cancel" :centered="true">
+    <a-modal
+      centered
+      class="modalBox"
+      :title="roleName"
+      v-model="isshow"
+      @cancle="cancel"
+      :maskClosable="false">
       <a-form class="form-box" style="max-height: 600px;" :form="form" @submit="handleSubmit">
         <a-tree
           checkable
@@ -16,7 +22,7 @@
         <a-button type="primary" @click="handleSubmit()" id="menuModal-handleSubmit">
           保存
         </a-button>
-        <a-button :style="{ marginLeft: '8px' }" @click="handleCancel()" id="menuModal-handleCancel">
+        <a-button :style="{ marginLeft: '8px' }" @click="cancel" id="menuModal-handleCancel">
           取消
         </a-button>
       </a-form-item>
@@ -98,20 +104,6 @@ export default {
         }
       })
     },
-    // 取消
-    handleCancel () {
-      const _this = this
-      this.$confirm({
-        title: '提示',
-        content: '确定取消吗?',
-        okText: '确定',
-        cancelText: '取消',
-        onOk () {
-          _this.clear()
-          _this.cancel()
-        }
-      })
-    },
     clear () {
       this.form.resetFields()
       this.roleName = ''
@@ -166,7 +158,8 @@ export default {
 </script>
 
 <style >
-  .modalBox{
+  .ant-modal-title{
+    padding-right: 30px;
   }
   .ant-modal-footer {
     display: none;

+ 1 - 1
src/views/power/role/roleList.vue

@@ -17,7 +17,7 @@
 
           <a-col :md="6" :sm="24">
             <a-form-item label="状态">
-              <v-select code="CHECK_ENABLE_STATE" v-model="queryParam.isEnable" allowClear placeholder="请选择状态" id="roleList-isEnable"></v-select>
+              <v-select code="ENABLE_FLAG" v-model="queryParam.isEnable" allowClear placeholder="请选择状态" id="roleList-isEnable"></v-select>
             </a-form-item>
           </a-col>
           <a-col :md="6" :sm="24">

+ 10 - 21
src/views/power/role/roleModal.vue

@@ -1,6 +1,13 @@
 <template>
   <div>
-    <a-modal class="modalBox" :title="titleText" v-model="isshow" @cancle="cancel" width="45%">
+    <a-modal
+      centered
+      class="modalBox"
+      :title="titleText"
+      :maskClosable="false"
+      v-model="isshow"
+      @cancle="cancel"
+      width="45%">
       <a-form :form="form" @submit="handleSubmit">
         <!-- 用户名称 -->
         <a-form-item label="角色名称" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
@@ -41,12 +48,11 @@
             placeholder="请输入描述(最多500个字符)"
             autosize />
         </a-form-item>
-
         <a-form-item :wrapper-col="{ span: 12, offset: 5 }">
           <a-button type="primary" @click="handleSubmit()">
             保存
           </a-button>
-          <a-button :style="{ marginLeft: '8px' }" @click="handleCancel()">
+          <a-button :style="{ marginLeft: '8px' }" @click="cancel">
             取消
           </a-button>
         </a-form-item>
@@ -95,7 +101,6 @@ export default {
       this.clear()
       this.$emit('close')
     },
-
     // 保存提交
     handleSubmit () {
       const _this = this
@@ -117,20 +122,6 @@ export default {
         }
       })
     },
-    // 取消
-    handleCancel () {
-      const _this = this
-      this.$confirm({
-        title: '提示',
-        content: '确定取消吗?',
-        okText: '确定',
-        cancelText: '取消',
-        onOk () {
-          _this.clear()
-          _this.cancel()
-        }
-      })
-    },
     clear () {
       this.form.resetFields()
       delete this.formData.id
@@ -138,10 +129,8 @@ export default {
       this.formData.isEnable = ''
       this.formData.remarks = ''
     }
-
-  },
-  mounted () {
   },
+  mounted () {},
   beforeCreate () {
     this.form = this.$form.createForm(this, { name: 'roleModal' })
   },

+ 54 - 106
src/views/power/user/userList.vue

@@ -1,34 +1,32 @@
 <template>
-  <a-card :bordered="false">
+  <a-card size="small" :bordered="false">
     <div class="table-page-search-wrapper">
-      <a-form layout="inline">
-        <a-row :gutter="48">
+      <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 allowClear v-model="queryParam.name" placeholder="请输入用户名称"/>
+              <a-input id="userList-name" allowClear v-model.trim="queryParam.name" placeholder="请输入用户名称"/>
             </a-form-item>
           </a-col>
-
           <a-col :md="6" :sm="24">
             <a-form-item label="手机号码">
-              <a-input allowClear v-model="queryParam.phone" placeholder="请输入手机号码"/>
+              <a-input id="userList-phone" allowClear v-model.trim="queryParam.phone" placeholder="请输入手机号码"/>
             </a-form-item>
           </a-col>
-
           <a-col :md="6" :sm="24">
             <a-form-item label="状态">
-              <v-select code="CHECK_ENABLE_STATE" v-model="queryParam.loginFlag" allowClear placeholder="请选择状态"></v-select>
+              <v-select id="userList-loginFlag" code="ENABLE_FLAG" v-model="queryParam.loginFlag" allowClear placeholder="请选择状态"></v-select>
             </a-form-item>
           </a-col>
           <a-col :md="4" :sm="24">
-            <a-button type="primary" @click="$refs.table.refresh(true)">查询</a-button>
+            <a-button type="primary" @click="$refs.table.refresh(true)" id="userList-search">查询</a-button>
+            <a-button type="" @click="reset" id="userList-reset" style="margin-left: 10px;">重置</a-button>
           </a-col>
         </a-row>
       </a-form>
     </div>
-    <a-divider/>
     <div class="table-operator">
-      <a-button type="primary" icon="plus" @click="openModal">新增</a-button>
+      <a-button type="primary" class="button-error" @click="openModal">新增</a-button>
     </div>
     <s-table
       ref="table"
@@ -36,11 +34,13 @@
       rowKey="id"
       :columns="columns"
       :data="loadData"
+      :scroll="{ x: 1010 }"
       style="word-break: break-all;"
       bordered
     >
       <span slot="status" slot-scope="text, record">
         <a-switch checkedChildren="启用" unCheckedChildren="禁用" v-model="record.loginFlag" @change="changeFlagHandle(text, record)"/>
+        <!-- <span v-else>{{ record.loginFlag==1?'已启用':'已禁用' }}</span> -->
       </span>
       <span slot="action" slot-scope="text, record">
         <a-icon
@@ -63,7 +63,7 @@
           @click="delect(record)"/>
       </span>
     </s-table>
-    <userModal :visible="showModal" @refresh="$refs.table.refresh(true)" :data="itemData" @close="showModal = false"></userModal>
+    <userModal :visible="showModal" @refresh="$refs.table.refresh(true)" :nowData="itemData" @close="handleUserCancel"></userModal>
   </a-card>
 </template>
 
@@ -82,54 +82,19 @@ export default {
       queryParam: {
         name: '',
         phone: '',
-        loginFlag: ''
+        loginFlag: undefined
       },
       showModal: false,
-      itemData: {}, // 编辑行数据
+      itemData: null, // 编辑行数据
       // 表头
       columns: [
-        {
-          title: '序号',
-          dataIndex: 'no',
-          width: 60,
-          align: 'center'
-        },
-        {
-		  title: '创建时间',
-          dataIndex: 'createDate',
-          width: 150,
-          align: 'center'
-        },
-        {
-          title: '用户名称',
-          dataIndex: 'name',
-          width: 150,
-          align: 'center'
-        },
-        {
-          title: '手机号码',
-          dataIndex: 'phone',
-          width: 150,
-          align: 'center'
-        },
-        {
-          title: '角色',
-          width: 200,
-          align: 'center',
-          dataIndex: 'roleNames'
-        },
-        {
-          title: '状态',
-          width: 150,
-          align: 'center',
-          scopedSlots: { customRender: 'status' }
-        },
-        {
-          title: '操作',
-          width: 150,
-          align: 'center',
-          scopedSlots: { customRender: 'action' }
-        }
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '创建时间', dataIndex: 'createDate', width: 160, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '用户名称', dataIndex: 'name', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '手机号码', dataIndex: 'phone', width: 150, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '角色', width: 200, align: 'center', dataIndex: 'roleNames', customRender: function (text) { return text || '--' } },
+        { title: '状态', width: 100, align: 'center', scopedSlots: { customRender: 'status' }, fixed: 'right' },
+        { title: '操作', width: 120, align: 'center', scopedSlots: { customRender: 'action' }, fixed: 'right' }
       ],
       // 加载数据方法 必须为 Promise 对象
       loadData: parameter => {
@@ -147,27 +112,40 @@ export default {
     }
   },
   methods: {
-    // 刷新列表
-    refreshTable () {
-      this.$refs.table.refresh(true)
-    },
-    // 新建
+    // 新增
     openModal () {
+      this.itemData = null
       this.showModal = true
-      this.itemData = {}
+    },
+    // 关闭弹框
+    handleUserCancel () {
+      this.showModal = false
+      this.itemData = null
+    },
+    // 重置
+    reset () {
+      this.queryParam.name = ''
+      this.queryParam.phone = ''
+      this.queryParam.loginFlag = undefined
+      this.$refs.table.refresh(true)
     },
     // 重置密码
     resetPassword (row) {
-      resetPSD({
-        id: row.id
-      }).then(res => {
-        if (res.status == 200) {
-          this.$message.success(res.message)
-        } else {
-          this.$message.error(res.message)
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认重置密码吗?',
+        centered: true,
+        onOk () {
+          resetPSD({
+            id: row.id
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+            }
+          })
         }
-      }).catch(() => {
-        this.$message.success(res.message)
       })
     },
     // 删除
@@ -176,8 +154,7 @@ export default {
       this.$confirm({
         title: '警告',
         content: '删除后无法恢复,确认删除?',
-        okText: '确定',
-        cancelText: '取消',
+        centered: true,
         onOk () {
           delectUserPower({
             id: row.id
@@ -188,23 +165,13 @@ export default {
             } else {
               _this.$message.error(res.message)
             }
-          }).catch(() => {
-            _this.$message.success(res.message)
           })
         }
       })
     },
-    getBizStr (storeBizList) {
-      const str = []
-      storeBizList.forEach(item => {
-        str.push(item.bizTypeName)
-      })
-      return str.join(',')
-    },
     handleEdit (row) {
-      console.log(row, 'row')
-      this.showModal = true
       this.itemData = row
+      this.showModal = true
     },
     // 修改状态
     changeFlagHandle (text, record) {
@@ -213,33 +180,14 @@ export default {
         flag: record.loginFlag ? '1' : '0'
       }
       updateEnableStatus(_data).then(res => {
-        if (res.status + '' === '200') {
+        if (res.status == 200) {
           this.$message.success(res.message)
+          this.$refs.table.refresh()
         } else {
-          record.loginFlag = !record.loginFlag
+          this.$refs.table.refresh()
         }
       })
     }
   }
 }
 </script>
-<style scoped>
-  .table-page-search-wrapper .ant-form-inline .ant-form-item{
-    margin-bottom: 0;
-  }
-  .action-button{
-   line-height: 40px;
-   white-space: nowrap;
-    padding: 5px 10px;
-    background-color: #1890ff;
-    border-radius: 4px;
-    color: #fff;
-    margin-right: 5px;
-  }
-  .red-text{
-    background-color: red;
-  }
-  .reset-text {
-    background-color: #31b50b;
-  }
-</style>

+ 114 - 191
src/views/power/user/userModal.vue

@@ -1,128 +1,89 @@
 <template>
   <div>
     <a-modal
-      class="modalBox"
+      centered
+      class="userEdit-modal"
+      :footer="null"
+      :maskClosable="false"
       :title="titleText"
       v-model="isshow"
-      @cancle="cancel"
-      width="45%"
-      :centered="true">
-      <a-form :form="form" @submit="handleSubmit">
+      @cancle="isshow=false"
+      :width="800">
+      <a-form-model
+        id="userEdit-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol"
+      >
         <a-row :gutter="24">
           <a-col :span="12">
-            <!-- 用户名称 -->
-            <a-form-item label="用户名称" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }">
+            <a-form-model-item label="用户名称" prop="name">
               <a-input
-                placeholder="请输入用户名称(最多30个字符)"
+                id="userEdit-name"
+                v-model.trim="form.name"
+                @change="filterEmpty"
                 :maxLength="30"
-                v-decorator="['formData.name', {
-                  initialValue: formData.name,
-                  rules: [{ required: true, message: '请输入用户名称(30个字以内)!' },{pattern:'^[^<|>]{1,30}$',message:'请输入不含<或>的字符,最多30个字符'}] }]"
-              />
-            </a-form-item>
+                allowClear
+                placeholder="请输入用户名称(最多30个字符)"/>
+            </a-form-model-item>
           </a-col>
           <a-col :span="12">
-            <!-- 手机号码 -->
-            <a-form-item label="手机号码" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }">
-              <a-input
-                placeholder="请输入手机号码"
-                :maxLength="11"
-                v-decorator="['formData.phone', {
-                  initialValue: formData.phone,
-                  rules: [{ required: true, message: '请输入手机号码!' },{pattern:/^[1][0-9]{10}$/, message: '请输入正确的手机号码!'}] }]"
-              />
-            </a-form-item>
+            <a-form-model-item label="手机号码" prop="phone">
+              <a-input id="userEdit-phone" v-model.trim="form.phone":maxLength="11" allowClear placeholder="请输入手机号码"/>
+            </a-form-model-item>
           </a-col>
         </a-row>
-
         <a-row :gutter="24">
           <!-- 性别 -->
           <a-col :span="12">
-            <a-form-item label="性别" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }">
+            <a-form-model-item label="性别" prop="sex">
               <v-select
+                ref="sex"
+                id="userEdit-sex"
                 code="SEX"
-                v-decorator="[
-                  'formData.sex',
-                  {
-                    initialValue: formData.sex,
-                    rules: [{ required: true, message: '请选择性别!' }] },
-                ]"
+                v-model="form.sex"
+                placeholder="请选择性别"
                 allowClear ></v-select>
-
-            </a-form-item>
+            </a-form-model-item>
           </a-col>
           <!-- 状态 -->
           <a-col :span="12">
-            <a-form-item label="状态" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }">
-              <a-radio-group
-                name="radioGroup"
-                v-decorator="[
-                  'formData.loginFlag',
-                  {
-                    initialValue: formData.loginFlag,
-                    rules: [{ required: true, message: '请选择状态!' }] },
-                ]"
-              >
+            <a-form-model-item label="状态" prop="loginFlag">
+              <a-radio-group name="radioGroup" v-model="form.loginFlag" placeholder="请选择状态">
                 <a-radio :value="1">是</a-radio>
                 <a-radio :value="0">否</a-radio>
               </a-radio-group>
-
-            </a-form-item>
+            </a-form-model-item>
           </a-col>
         </a-row>
         <a-row :gutter="24">
           <a-col :span="24">
-            <a-form-item label="角色" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
+            <a-form-model-item label="角色" prop="roleNames" :label-col="{span: 3}" :wrapper-col="{span: 20}">
               <a-select
-                v-decorator="[
-                  'formData.roleNames',
-                  {
-                    initialValue: formData.roleNames,
-                    rules: [{ required: true, message: '请选择状态!' }] },
-                ]"
-                mode="multiple"
-                style="width: 100%"
                 placeholder="请选择角色"
-              >
-                <a-select-option
-                  v-for="item in roleList"
-                  :key="item.id"
-                  :disabled="item.isEnable == '0' ? true : false"
-                >{{ item.name }}</a-select-option
-                >
+                id="userSyncEdit-roleNames"
+                allowClear
+                v-model="form.roleNames"
+                mode="multiple">
+                <a-select-option v-for="item in roleList" :key="item.id" :value="item.id" :disabled="item.isEnable == '0' ? true : false">{{ item.name }}</a-select-option>
               </a-select>
-            </a-form-item>
+            </a-form-model-item>
           </a-col>
-
         </a-row>
         <a-row :gutter="24">
           <a-col :span="24">
-            <a-form-item label="备注" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
-              <a-textarea
-                v-decorator="[
-                  'formData.remarks',
-                  {
-                    initialValue: formData.remarks,
-                    rules: [] },
-                ]"
-                style="min-height: 50px;"
-                :maxLength="500"
-                placeholder="请输入备注(最多500个字符)"
-                autosize />
-            </a-form-item>
+            <a-form-model-item label="备注" prop="remarks" :label-col="{span: 3}" :wrapper-col="{span: 20}">
+              <a-textarea id="userEdit-remarks" v-model.trim="form.remarks":maxLength="500" allowClear placeholder="请输入备注(最多500个字符)"/>
+            </a-form-model-item>
           </a-col>
         </a-row>
-
-        <a-form-item :wrapper-col="{ span: 24, offset: 12 }">
-          <a-button type="primary" @click="handleSubmit()" :style="{ marginRight: '8px' }">
-            保存
-          </a-button>
-          <a-button :style="{ marginLeft: '8px' }" @click="handleCancel()">
-            取消
-          </a-button>
-        </a-form-item>
-      </a-form>
-
+        <a-form-model-item :label-col="{span: 0}" :wrapper-col="{span: 24}" style="text-align: center;">
+          <a-button type="primary" @click="handleSubmit()" :style="{ marginRight: '8px' }">保存</a-button>
+          <a-button :style="{ marginLeft: '8px' }" @click="isshow=false">取消</a-button>
+        </a-form-model-item>
+      </a-form-model>
     </a-modal>
   </div>
 </template>
@@ -140,7 +101,7 @@ export default {
       type: Boolean,
       default: false
     },
-    data: {
+    nowData: {
       type: Object,
       default: function () {
         return {}
@@ -149,147 +110,109 @@ export default {
   },
   data () {
     return {
-      titleText: '添加用户',
+      titleText: '新增用户',
       isshow: this.visible,
-      formLayout: 'horizontal',
-      form: this.$form.createForm(this, { name: 'miniForm' }),
       roleList: [],
-      formData: {
-        roleNames: undefined, // 角色
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 16 }
+      },
+      form: {
         name: '',
-        loginFlag: '', // 活动状态
         phone: '',
-        sex: '',
+        sex: undefined,
+        loginFlag: '', // 状态
+        roleNames: undefined, // 角色
         remarks: ''
+      },
+      rules: {
+        name: [ { required: true, message: '请输入用户名称', trigger: 'blur' }, { pattern: '^[^<|>]{1,30}$', message: '请输入不含<或>的字符,最多30个字符' } ],
+        phone: [ { required: true, message: '请输入手机号码', trigger: 'blur' }, { pattern: /^[1][0-9]{10}$/, message: '请输入正确的手机号码!' } ],
+        sex: [ { required: true, message: '请选择性别', trigger: 'change' } ],
+        loginFlag: [ { required: true, message: '请选择状态', trigger: 'change' } ],
+        roleNames: [ { required: true, message: '请选择角色', trigger: 'change' } ]
       }
-
     }
   },
   methods: {
-    cancel (e) {
-      this.clear()
-      this.$emit('close')
+    // 过滤空格
+    filterEmpty () {
+      let str = this.form.name
+      str = str.replace(/\ +/g, '')
+      str = str.replace(/[ ]/g, '')
+      str = str.replace(/[\r\n]/g, '')
+      this.form.name = str
     },
-
     // 保存提交
     handleSubmit () {
       const _this = this
-      this.form.validateFields((err, values) => {
-        console.log(values, 'values222')
-        if (!err) {
-          values.formData.roleNames = values.formData.roleNames.join(',')
-
-          console.log(values.formData, ' formData.type222222222')
-          console.log(Object.assign({ id: this.data.id ? this.data.id : '' }, values.formData))
-          saveUserPower(Object.assign({ id: this.data.id ? this.data.id : '' }, values.formData)).then(res => {
-            console.log(res, 'res--save')
-            if (res.status + '' === '200') {
-              this.$message.success(res.message ? res.message : '保存成功')
-              this.$emit('refresh')
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const params = JSON.parse(JSON.stringify(_this.form))
+          params.roleNames = _this.form.roleNames.join(',')
+          params.id = _this.nowData && _this.nowData.id ? _this.nowData.id : null
+          saveUserPower(params).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$emit('refresh')
               setTimeout(function () {
-                _this.cancel()
+                _this.isshow = false
               }, 300)
+            } else {
+
             }
           })
+        } else {
+          console.log('error submit!!')
+          return false
         }
       })
     },
-    // 取消
-    handleCancel () {
-      const _this = this
-      this.$confirm({
-        title: '提示',
-        content: '确定取消吗?',
-        centered: true,
-        okText: '确定',
-        cancelText: '取消',
-        onOk () {
-          _this.clear()
-          _this.cancel()
-        }
-      })
-    },
-    clear () {
-      this.form.resetFields()
-      delete this.formData.id
-      this.formData.roleNames = []
-      this.formData.name = ''
-      this.formData.loginFlag = ''
-      this.formData.phone = ''
-      this.formData.sex = ''
-      this.formData.remarks = ''
-    },
-
     // 获取角色列表接口
     getRoleList () {
       getRoleList().then(res => {
-        console.log(res, 'res--role')
-        if (res.status + '' === '200') {
+        if (res.status == 200) {
           this.roleList = res.data
         } else {
           this.$message.warning(res.message)
         }
       })
     }
-
-  },
-  mounted () {
-    this.getRoleList()
-  },
-  beforeCreate () {
-    this.form = this.$form.createForm(this, { name: 'miniForm' })
   },
   watch: {
     visible (newValue, oldValue) {
       this.isshow = newValue
     },
     isshow (newValue, oldValue) {
-      if (newValue) {
-        if (this.data.id) { // 编辑
-          this.titleText = '编辑用户'
-          this.formData = Object.assign({}, this.data)
-          delete this.formData.no
-          let roleNames = this.formData.roleNames
-          console.log(roleNames, 'roleNames')
-          if (roleNames) {
-            roleNames = roleNames.split(',')
-            console.log(roleNames, 'roleNames22')
-            const arr = []
-            console.log(this.roleList, 'this.roleList')
-
-            roleNames.map(item => {
-              const row = this.roleList.find(a => {
-                return a.name == item
-              })
-              if (row) {
-                arr.push(row.id)
-              }
-            })
-
-            console.log(arr, 'arrs')
-            this.formData.roleNames = arr
-          } else {
-            this.formData.roleNames = []
-          }
-
-          this.formData.loginFlag = Number(this.formData.loginFlag)
-          // this.formData.sex = Number(this.formData.sex)
-          console.log(this.formData, 'this.formData')
-        } else {
-          this.titleText = '添加用户'
-        }
+      if (!newValue) {
+        this.$emit('close')
+        this.$refs.ruleForm.resetFields()
+        this.form.name = ''
+        this.form.phone = ''
+        this.form.sex = undefined
+        this.form.loginFlag = ''
+        this.form.roleNames = undefined
+        this.form.remarks = ''
+        this.titleText = '新增用户'
       } else {
-        this.cancel()
+        this.getRoleList()
       }
+    },
+    nowData: {
+      handler (newValue, oldValue) {
+        if (this.isshow && newValue) {
+          if (this.nowData.id) { //  编辑
+            this.titleText = '编辑用户'
+            this.form = Object.assign({}, this.nowData)
+            if (this.nowData.roleIds) {
+              this.form.roleNames = this.nowData.roleIds.split(',')
+            }
+            this.form.loginFlag = Number(this.nowData.loginFlag)
+          }
+        }
+      },
+      deep: true
     }
   }
 }
 </script>
-
-<style >
-  .modalBox{
-  }
-  .ant-modal-footer {
-    display: none;
-  }
-</style>

+ 0 - 146
src/views/productManagement/productCategory/editModal.vue

@@ -1,146 +0,0 @@
-<template>
-  <a-modal
-    centered
-    class="productCategoryEdit-modal"
-    :footer="null"
-    :maskClosable="false"
-    :title="modalTit"
-    v-model="isShow"
-    @cancle="isShow=false"
-    :width="800">
-    <!-- 表单 -->
-    <div>
-      <a-form-model
-        id="productCategoryEdit-form"
-        ref="ruleForm"
-        :model="form"
-        :rules="rules"
-        :label-col="formItemLayout.labelCol"
-        :wrapper-col="formItemLayout.wrapperCol"
-      >
-        <a-form-model-item label="所属类别" v-if="parentType">
-          {{ parentType }}
-        </a-form-model-item>
-        <a-form-model-item label="产品类别名称" prop="productTypeName">
-          <a-input v-model.trim="form.productTypeName" id="productCategory-name" :maxLength="30" allowClear placeholder="请输入产品类别名称(最多30个字符)" />
-        </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>
-    </div>
-  </a-modal>
-</template>
-
-<script>
-import { STable } from '@/components'
-import { dealerProductTypeSave } from '@/api/dealerProductType'
-export default {
-  name: 'productCategoryEditModal',
-  components: { STable },
-  props: {
-    openModal: { //  弹框显示状态
-      type: Boolean,
-      default: false
-    },
-    itemId: {
-      type: [Number, String],
-      default: ''
-    },
-    nowData: {
-      type: Object,
-      default: null
-    }
-  },
-  computed: {
-    modalTit () {
-      return (this.itemId ? '编辑' : '新增') + '产品类别'
-    }
-  },
-  data () {
-    return {
-      isShow: this.openModal, //  是否打开弹框
-      formItemLayout: {
-        labelCol: { span: 6 },
-        wrapperCol: { span: 16 }
-      },
-      form: {
-        productTypeName: '', // 产品类别名称
-      },
-      rules: {
-        productTypeName: [
-          { required: true, message: '请输入产品类别名称', trigger: 'blur' }
-        ],
-      },
-      parentType: '',  //  父级分类
-    }
-  },
-  methods: {
-    //  保存
-    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 : null
-          formData.psn = _this.nowData && _this.nowData.psn ? _this.nowData.psn : null
-          dealerProductTypeSave(formData).then(res => {
-            if (res.status == 200) {
-              _this.$message.success(res.message)
-              _this.$emit('ok')
-              _this.isShow = false
-            }
-          })
-        } else {
-          return false
-        }
-      })
-    },
-  },
-  watch: {
-    //  父页面传过来的弹框状态
-    openModal (newValue, oldValue) {
-      this.isShow = newValue
-    },
-    //  重定义的弹框状态
-    isShow (newValue, oldValue) {
-      if (!newValue) {
-        this.$emit('close')
-      }else{
-        //  获取父级分类 名称
-        if(this.nowData && this.nowData.namePaths){
-          let namePathsArr = []
-          namePathsArr = this.nowData.namePaths.split(',')
-          this.parentType = ''
-          namePathsArr.map((item, index) => {
-            this.parentType += item + ' > '
-          })
-          this.parentType = this.parentType ? this.parentType.substr(0, this.parentType.length - 3) : ''
-        }else{
-          this.parentType = ''
-        }
-      }
-    },
-    itemId (newValue, oldValue) {
-      if (this.isShow && newValue) {
-        this.form.productTypeName = this.nowData && this.nowData.productTypeName ? this.nowData.productTypeName : ''
-      }else{
-        this.form.productTypeName = ''
-      }
-    }
-  }
-}
-</script>
-
-<style lang="less">
-  .productCategoryEdit-modal{
-    .ant-modal-body {
-    	padding: 40px 40px 24px;
-    }
-    .btn-cont {
-    	text-align: center;
-    	margin: 35px 0 10px;
-    }
-  }
-</style>

+ 0 - 170
src/views/productManagement/productCategory/list.vue

@@ -1,170 +0,0 @@
-<template>
-  <a-card :bordered="false" class="productCategoryList-wrap">
-    <!-- 操作按钮 -->
-    <div class="table-operator">
-      <a-button id="productCategoryList-add" type="primary" @click="handleAdd()" style="margin-top: 18px;">新增一级分类</a-button>
-    </div>
-    <!-- 列表 -->
-    <s-table
-      class="sTable"
-      ref="table"
-      size="default"
-      :rowKey="(record) => record.id"
-      :columns="columns"
-      :data="loadData"
-      :showPagination="false"
-      :defaultExpandedRowKeys="defaultExpandedRowKeys"
-      bordered>
-      <!-- 操作 -->
-      <template slot="action" slot-scope="text, record">
-        <a-button
-          v-if="record.productTypeLevel<3"
-          type="link"
-          size="small"
-          icon="plus"
-          class="btn-add-s"
-          id="productCategory-addSubItem"
-          @click="handleAdd(record)">新增子级</a-button>
-        <a-button
-          v-if="record.pid != 0"
-          type="link"
-          size="small"
-          icon="edit"
-          class="btn-edit-s"
-          id="productCategory-edit"
-          @click="handleEdit(record)">编辑</a-button>
-        <a-button
-          v-if="record.pid != 0"
-          type="link"
-          size="small"
-          icon="delete"
-          class="btn-del-s"
-          id="productCategory-del"
-          @click="handleDel(record)">删除</a-button>
-      </template>
-    </s-table>
-    <!-- 新增/编辑产品类别 -->
-    <product-category-edit-modal :openModal="openModal" :nowData="nowData" :itemId="itemId" @ok="handleOk" @close="closeModal" />
-  </a-card>
-</template>
-
-<script>
-import { dealerProductTypeQuery, dealerProductTypeDel } from '@/api/dealerProductType'
-import { STable } from '@/components'
-import productCategoryEditModal from './editModal.vue'
-export default {
-  components: { STable, productCategoryEditModal },
-  data () {
-    return {
-      formItemLayout: {
-        labelCol: { span: 6 },
-        wrapperCol: { span: 16 }
-      },
-      columns: [
-        { title: '产品类别名称', dataIndex: 'productTypeName', width: 200, align: 'left' },
-        { title: '首字母', dataIndex: 'sss', width: 150, align: 'center' },
-        { title: '创建时间', dataIndex: 'createDate', width: 150, align: 'center' },
-        { title: '操作', scopedSlots: { customRender: 'action' }, width: 150, align: 'center' }
-      ],
-      // 加载数据方法 必须为 Promise 对象
-      loadData: parameter => {
-        this.disabled = true
-        return dealerProductTypeQuery({}).then(res => {
-          //  递归去除空children
-          this.recursionFun(res.data)
-          this.defaultExpandedRowKeys[0] = res.data[0].id
-          return res.data
-        })
-      },
-      defaultExpandedRowKeys: [], //  树形数据默认展开项
-      openModal: false,  //  新增编辑  弹框
-      itemId: '',  //  当前id
-      nowData: null  //  当前记录数据
-    }
-  },
-  methods: {
-    //  新增子级
-    handleAdd (row) {
-      this.itemId = null
-      if(row){  //  新增子级
-        let nowData = row
-        nowData.psn = nowData && nowData.productTypeSn ? nowData.productTypeSn : null
-        this.nowData = nowData
-      }else{  //  最高级
-        this.nowData = null
-      }
-      this.openModal = true
-    },
-    //  编辑
-    handleEdit (row) {
-      this.itemId = row && row.id ? row.id : null
-      let nowData = row
-      nowData.psn = nowData && nowData.productTypeSn ? nowData.productTypeSn : null
-      this.nowData = nowData
-      this.openModal = true
-    },
-    //  关闭弹框
-    closeModal(){
-      this.itemId = ''
-      this.openModal = false
-    },
-    //  新增/编辑  成功
-    handleOk(){
-      this.$refs.table.refresh(true)
-    },
-    //  删除
-    handleDel (item) {
-      const _this = this
-      _this.nowId = item.id
-      _this.$confirm({
-        title: '提示',
-        centered: true,
-        content: '删除后原数据不可恢复,是否删除?',
-        onOk () {
-          dealerProductTypeDel({ id: _this.nowId }).then(res => {
-            if (res.status == 200) {
-              _this.$message.success(res.message)
-              _this.$refs.table.refresh()
-            }
-          })
-        }
-      })
-    },
-    //  递归函数
-    recursionFun (data) {
-      if (data) {
-        data.map((item, index) => {
-          if (item.children && item.children.length == 0) {
-            delete item.children
-          } else {
-            this.recursionFun(item.children)
-          }
-        })
-      }
-    }
-  }
-}
-</script>
-
-<style lang="less">
-  .productCategoryList-wrap{
-    // 表格
-    .s-table{
-      .btn-edit-s{
-        color: #1891ff;
-        margin: 0 5px;
-      }
-      .btn-del-s{
-        color: #ff4d4f;
-      }
-      .btn-edit-s.ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger), .btn-edit-s.ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger){
-        color: #1891ff;
-        border-color: #1891ff;
-      }
-      .btn-del-s.ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger), .btn-del-s.ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger){
-        color: #ff4d4f;
-        border-color: #ff4d4f;
-      }
-    }
-  }
-</style>

+ 10 - 143
src/views/user/ChangePwd.vue

@@ -1,158 +1,25 @@
 <template>
-
   <a-card :bordered="false" class="change-pwd-card">
-    <a-row :gutter="24" class="change-pwd">
-      <a-col span="8" offset="8">
-        <a-form @submit="handleSubmit" :form="form">
-          <!-- 原始密码 -->
-          <a-form-item
-            label="原始密码"
-            prop="oldPwd"
-            :label-col="formLayout.labelCol"
-            :wrapper-col="formLayout.wrapperCol">
-            <a-input
-              type="password"
-              v-decorator="[
-                'formCustom.oldPwd',
-                { initialValue: formCustom.oldPwd,
-                  rules: [
-                    { required: true, message: '请输入原始密码' },
-                  ]
-                },
-              ]">
-            </a-input>
-          </a-form-item>
-          <!-- 新密码 -->
-          <a-form-item
-            label="新密码"
-            prop="passwd"
-            :label-col="formLayout.labelCol"
-            :wrapper-col="formLayout.wrapperCol">
-            <a-input
-              type="password"
-              v-decorator="[
-                'formCustom.passwd',
-                { initialValue: formCustom.passwd,
-                  rules: [
-                    { required: true, message: '请输入新密码' }
-                  ]
-                },
-              ]">
-            </a-input>
-          </a-form-item>
-          <!-- 再次确认 -->
-          <a-form-item
-            label="再次确认"
-            prop="passwdCheck"
-            :label-col="formLayout.labelCol"
-            :wrapper-col="formLayout.wrapperCol">
-            <a-input
-              type="password"
-              v-decorator="[
-                'formCustom.passwdCheck',
-                { initialValue: formCustom.passwdCheck,
-                  rules: [
-                    { required: true, message: '请再次输入密码' },
-                    { validator: compareToFirstPassword }
-                  ]
-                },
-              ]">
-            </a-input>
-          </a-form-item>
-          <a-col span="16" offset="8">
-            <a-form-item>
-              <a-button type="primary" htmlType="submit" :loading="loading">保存</a-button>
-              <a-button @click="handleReset('formCustom')" style="margin-left: 8px">重置</a-button>
-            </a-form-item>
-          </a-col>
-        </a-form>
+    <a-row :gutter="24">
+      <a-col span="12" offset="6">
+        <ResetPwd />
       </a-col>
     </a-row>
   </a-card>
-
 </template>
 
 <script>
-import { changePwd } from '@/api/login.js'
-import { mapActions, mapGetters } from 'vuex'
-
+import ResetPwd from '@/views/user/ResetPwd.vue'
 export default {
   name: 'ChangePwd',
-  data () {
-    return {
-      formLayout: {
-        labelCol: {
-          xs: { span: 24 },
-          sm: { span: 6 }
-        },
-        wrapperCol: {
-          xs: { span: 24 },
-          sm: { span: 18 }
-        }
-      },
-      form: this.$form.createForm(this),
-      loading: false,
-      formCustom: {
-        passwd: '',
-        passwdCheck: '',
-        oldPwd: ''
-      }
-    }
-  },
-  methods: {
-    ...mapActions(['Logout']),
-    // 密码校验
-    compareToFirstPassword (rule, value, callback) {
-      const form = this.form
-      if (value && value !== form.getFieldValue('formCustom.passwd')) {
-        callback('两次输入的密码不一致, 请重新输入!')
-      } else {
-        callback()
-      }
-    },
-    handleSubmit (e) {
-      e.preventDefault()
-      const _this = this
-      this.form.validateFields((err, values) => {
-        console.log(values, 'values')
-        if (!err) {
-          changePwd({
-            oldPassword: values.formCustom.oldPwd,
-            password: values.formCustom.passwd
-          }).then(res => {
-            console.log(res, 'res111111')
-            if (res.status === '200') {
-              _this.$message.success('修改成功, 请重新登录')
-              _this.logout()
-            } else {
-              // _this.$message.error(res.message)
-            }
-          })
-        }
-      })
-    },
-    logout () {
-      this.Logout({}).then(() => {
-        setTimeout(() => {
-          this.$router.push({ path: '/user/login' })
-        }, 16)
-      })
-    },
-    handleReset () {
-      this.form.resetFields()
-    }
+  components: {
+    ResetPwd
   }
-
 }
 </script>
 
-<style scoped>
-  .change-pwd {
-    margin-top: 15vh;
-  }
-
-  .change-pwd-card {
-    height: 70vh;
-    /* border-top: 2px solid #FFB01B; */
-  }
+<style lang="less" scoped>
+.change-pwd-card {
+  padding-top: 50px;
+}
 </style>

+ 1 - 1
src/views/user/Login.vue

@@ -275,7 +275,7 @@ export default {
       console.log(err, 'error')
       this.isLoginError = true
       this.$notification['error']({
-        message: '错误提示',
+        message: '提示',
         description: ((err.response || {}).data || {}).message || err.message || '请求出现错误,请稍后再试',
         duration: 4
       })

+ 4 - 4
src/views/user/Register.vue

@@ -115,8 +115,8 @@ const levelClass = {
   3: 'success'
 }
 const levelColor = {
-  0: '#ff0000',
-  1: '#ff0000',
+  0: '#ed1c24',
+  1: '#ed1c24',
   2: '#ff7e05',
   3: '#52c41a'
 }
@@ -135,7 +135,7 @@ export default {
         passwordLevel: 0,
         passwordLevelChecked: false,
         percent: 10,
-        progressColor: '#FF0000'
+        progressColor: '#ed1c24'
       },
       registerBtn: false
     }
@@ -277,7 +277,7 @@ export default {
   .user-register {
 
     &.error {
-      color: #ff0000;
+      color: #ed1c24;
     }
 
     &.warning {

+ 135 - 0
src/views/user/ResetPwd.vue

@@ -0,0 +1,135 @@
+<template>
+  <div class="change-pwd">
+    <a-form-model
+      id="change-pwd-form"
+      ref="ruleForm"
+      :model="form"
+      :rules="rules"
+      :label-col="formLayout.labelCol"
+      :wrapper-col="formLayout.wrapperCol">
+      <a-form-model-item label="原始密码" prop="oldPwd">
+        <a-input
+          type="password"
+          v-model.trim="form.oldPwd"
+          id="change-pwd-oldPwd"
+          :maxLength="50"
+          allowClear
+          placeholder="请输入原始密码(6~50位)" />
+      </a-form-model-item>
+      <a-form-model-item label="新密码" prop="passwd">
+        <a-input
+          type="password"
+          v-model.trim="form.passwd"
+          @change="filterEmpty"
+          id="change-pwd-passwd"
+          :maxLength="50"
+          allowClear
+          placeholder="请输入新密码(6~50位)" />
+      </a-form-model-item>
+      <a-form-model-item label="再次确认" prop="passwdCheck">
+        <a-input
+          type="password"
+          v-model.trim="form.passwdCheck"
+          id="change-pwd-passwdCheck"
+          :maxLength="50"
+          allowClear
+          placeholder="请再次输入新密码(6~50位)" />
+      </a-form-model-item>
+      <a-form-model-item :wrapper-col="{ span: 12, offset: 6 }">
+        <div style="text-align: center;">
+          <a-button type="primary" @click="handleSubmit">保存</a-button>
+          <a-button @click="handleReset" style="margin-left: 8px">重置</a-button>
+        </div>
+      </a-form-model-item>
+    </a-form-model>
+  </div>
+</template>
+
+<script>
+import { changePwd } from '@/api/login'
+import { mapActions } from 'vuex'
+export default {
+  name: 'ResetPwd',
+  data () {
+    return {
+      formLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 20 }
+      },
+      form: {
+        oldPwd: '',
+        passwd: '',
+        passwdCheck: ''
+      },
+      rules: {
+        oldPwd: [{ required: true, message: '请输入原始密码', trigger: 'blur' }],
+        passwd: [
+          { required: true, message: '请输入新密码', trigger: 'blur' },
+          { validator: this.passwordValid }
+        ],
+        passwdCheck: [
+          { required: true, message: '请再次输入密码', trigger: 'blur' },
+          { validator: this.compareToFirstPassword }
+        ]
+      }
+    }
+  },
+  methods: {
+    ...mapActions(['Logout']),
+    //  密码位数校验
+    passwordValid (rule, value, callback) {
+      if (value.length < 6 || value.length > 50) {
+        callback('请输入6~50位密码!')
+      } else {
+        callback()
+      }
+    },
+    // 密码校验
+    compareToFirstPassword (rule, value, callback) {
+      if (value && (value !== this.form.passwd)) {
+        callback('两次输入的密码不一致, 请重新输入!')
+      } else {
+        callback()
+      }
+    },
+    // 过滤空格
+    filterEmpty () {
+      let str = this.form.passwd
+      str = str.replace(/\ +/g, '')
+      str = str.replace(/[ ]/g, '')
+      str = str.replace(/[\r\n]/g, '')
+      this.form.passwd = str
+    },
+    handleSubmit () {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const form = {
+            oldPassword: _this.form.oldPwd,
+            password: _this.form.passwd
+          }
+          changePwd(form).then(res => {
+            if (res.status == 200) {
+              _this.$message.success('修改成功, 请重新登录')
+              _this.logout()
+            }
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    logout () {
+      this.Logout({}).then(() => {
+        setTimeout(() => {
+          this.$router.push({ path: '/user/login' })
+        }, 16)
+      })
+    },
+    handleReset () {
+      this.$refs.ruleForm.resetFields()
+    }
+  }
+}
+</script>

+ 2 - 2
vue.config.js

@@ -108,8 +108,8 @@ const vueConfig = {
     // If you want to turn on the proxy, please remove the mockjs /src/main.jsL11
     proxy: {
       '/api': {
-        target: 'http://192.168.0.119:8503/qpls-md',
-        // target: 'http://it.test.zyucgj.com/zyit',
+        // target: 'http://192.168.16.103:8501/qpls-it',
+        target: 'http://qpls-it.360arrow.com.cn/qpls-it',
         // target: 'https://it.test.qiubcar.com/zyit',
         ws: false,
         changeOrigin: true,