Browse Source

菜单权限 update

chenrui 4 years ago
parent
commit
790bdbf2a4

+ 96 - 34
src/config/router.config.js

@@ -1,9 +1,6 @@
-// eslint-disable-next-line
 import {
 import {
   UserLayout,
   UserLayout,
   BasicLayout,
   BasicLayout,
-  RouteView,
-  BlankLayout,
   PageView
   PageView
 } from '@/layouts'
 } from '@/layouts'
 
 
@@ -109,47 +106,112 @@ export const asyncRouterMap = [{
   //     }
   //     }
   //   }
   //   }
   //   ]
   //   ]
-  // },
+  // },
+  {
+    path: '/menusAuth',
+    redirect: '/bnSetting/menusAuth',
+    component: PageView,
+    meta: {
+      title: '菜单管理',
+      icon: 'bars'
+      // permission: 'M_menusAuth_0'
+    },
+    children: [
+      {
+        path: '/menusAuth/adminMenus',
+        name: 'adminMenus',
+        component: () => import(/* webpackChunkName: "bnSetting" */ '@/views/bnSetting/menu/adminMenus.vue'),
+        meta: {
+          title: '运营菜单管理',
+          icon: 'appstore',
+          permission: 'M_auth_menu'
+        }
+      },
+      {
+        path: '/menusAuth/menu',
+        name: 'powerMenu',
+        component: () => import(/* webpackChunkName: "auth" */ '@/views/power/menu/menu.vue'),
+        meta: {
+          title: '卡券菜单管理',
+          icon: 'profile'
+          // permission: 'M_menusAuth_menu'
+        }
+      },
+      {
+        path: '/menusAuth/storeMenus',
+        name: 'storeMenus',
+        component: () => import(/* webpackChunkName: "bnSetting" */ '@/views/bnSetting/menu/storeMenus.vue'),
+        meta: {
+          title: '发券菜单管理',
+          icon: 'shop'
+          // permission: 'M_menusAuth_storeMenus'
+        }
+      }
+    ]
+  },
   {
   {
     path: '/auth',
     path: '/auth',
     redirect: '/auth/userList',
     redirect: '/auth/userList',
     component: PageView,
     component: PageView,
     meta: {
     meta: {
-      title: '权限管理',
+      title: '运营权限管理',
       icon: 'lock',
       icon: 'lock',
       permission: 'M_auth_0'
       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: '/menusAuth/adminMenus',
-      name: 'adminMenus',
-      component: () => import(/* webpackChunkName: "bnSetting" */ '@/views/bnSetting/menu/adminMenus.vue'),
-      meta: {
-        title: '菜单管理',
-        icon: 'appstore',
-        permission: 'M_auth_menu'
+    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: '/CardVoucherAuth',
+    redirect: '/CardVoucherAuth/userList',
+    component: PageView,
+    meta: {
+      title: '卡券权限管理',
+      icon: 'lock'
+      // permission: 'M_CardVoucherAuth_0'
+    },
+    children: [
+      {
+        path: '/CardVoucherAuth/userList',
+        name: 'CardUserList',
+        component: () => import(/* webpackChunkName: "CardVoucherAuth" */ '@/views/CardVoucherAuth/user/userList.vue'),
+        meta: {
+          title: '用户管理',
+          icon: 'user'
+          // permission: 'M_CardVoucherAuth_userList'
+        }
+      },
+      {
+        path: '/CardVoucherAuth/roleList',
+        name: 'CardRoleList',
+        component: () => import(/* webpackChunkName: "CardVoucherAuth" */ '@/views/CardVoucherAuth/role/roleList.vue'),
+        meta: {
+          title: '角色管理',
+          icon: 'solution'
+          // permission: 'M_CardVoucherAuth_roleList'
+        }
+      }
+    ]
   },
   },
   {
   {
     path: '/setting',
     path: '/setting',

+ 194 - 0
src/views/CardVoucherAuth/role/menuModal.vue

@@ -0,0 +1,194 @@
+<template>
+  <div>
+    <a-modal class="modalBox" :title="roleName" v-model="isshow" @cancle="cancel">
+      <a-form class="form-box" style="max-height: 600px;" :form="form" @submit="handleSubmit">
+
+        <a-tree
+          checkable
+          @check="onCheck"
+          @expand="onExpand"
+          :expandedKeys="expandedKeys"
+          :autoExpandParent="autoExpandParent"
+          v-model="checkedKeys"
+          :treeData="treeData"
+        />
+
+      </a-form>
+      <a-form-item :wrapper-col="{ offset: 15 }">
+        <a-button type="primary" @click="handleSubmit()">
+          保存
+        </a-button>
+        <a-button :style="{ marginLeft: '8px' }" @click="handleCancel()">
+          取消
+        </a-button>
+      </a-form-item>
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import { addMenuPower } from '@/api/power-role.js'
+export default {
+  name: 'RoleModal',
+  components: {
+    STable, VSelect
+  },
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    data: {
+      type: Object,
+      default: function () {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      treeData: [],
+      roleName: '',
+      expandedKeys: [],
+      autoExpandParent: true,
+      checkedKeys: [],
+      checkedData: [],
+      isshow: this.visible,
+      formLayout: 'horizontal',
+      form: this.$form.createForm(this, { name: 'menuModal' }),
+      id: '' // 角色id
+    }
+  },
+  methods: {
+    onExpand (expandedKeys) {
+      // if not set autoExpandParent to false, if children expanded, parent can not collapse.
+      // or, you can remove all expanded children keys.
+      this.expandedKeys = expandedKeys
+      this.autoExpandParent = false
+    },
+    onCheck (checkedKeys, info) {
+      this.checkedData = [...checkedKeys, ...info.halfCheckedKeys]
+      this.checkedKeys = checkedKeys
+    },
+    cancel (e) {
+      this.clear()
+      this.$emit('close')
+    },
+    // 保存提交
+    handleSubmit () {
+      const _this = this
+      this.form.validateFields((err, values) => {
+        if (!err) {
+          if (this.checkedData.length == 0) {
+            return this.$message.warning('请先选择菜单')
+          }
+          const arr = this.checkedData.join(',')
+          addMenuPower({ id: this.id, menuIds: arr }).then(res => {
+            if (res.status + '' === '200') {
+              this.$message.success(res.message ? res.message : '保存成功')
+              this.$emit('refresh')
+              setTimeout(function () {
+                _this.cancel()
+              }, 300)
+            } else {
+              // this.$message.error(res.message)
+            }
+          })
+        }
+      })
+    },
+    // 取消
+    handleCancel () {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确定取消吗?',
+        okText: '确定',
+        cancelText: '取消',
+        onOk () {
+          _this.clear()
+          _this.cancel()
+        }
+      })
+    },
+    clear () {
+      this.form.resetFields()
+      this.roleName = ''
+      this.id = ''
+      this.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)
+          }
+        }
+      }
+    }
+  },
+  mounted () {
+  },
+  beforeCreate () {
+    this.form = this.$form.createForm(this, { name: 'menuModal' })
+  },
+  watch: {
+    visible (newValue, oldValue) {
+      this.isshow = newValue
+    },
+    isshow (newValue, oldValue) {
+      if (newValue) {
+        if (this.data) { // 编辑
+          this.treeData = this.data.allMenuList
+          this.id = this.data.role.id
+          this.roleName = '分配权限' + '(' + this.data.role.name + ')'
+          if (this.data.role.menuIds) {
+            const arr = this.data.role.menuIds.split(',')
+            const temp = []
+            arr.map(item => {
+              temp.push(Number(item))
+            })
+            this.checkedData = temp
+            this.expandedKeys = temp
+            // 找出叶子节点
+            this.findLeaf(this.treeData, temp)
+          }
+        }
+      } else {
+        this.cancel()
+      }
+    }
+  }
+}
+</script>
+
+<style >
+  .modalBox{
+  }
+  .ant-modal-footer {
+    display: none;
+  }
+  .form-box {
+    max-height: 600px !important;
+    overflow: auto;
+  }
+  .form-box::-webkit-scrollbar{
+    width: 6px;
+    height: 6px ;
+  }
+
+  .form-box::-webkit-scrollbar-thumb{
+    width: 6px;
+    height: 6px ;
+    border-radius: 4px;
+    -webkit-box-shadow: inset 0 0 2px #d1d1d1;
+    background: #e4e4e4;
+  }
+</style>

+ 222 - 0
src/views/CardVoucherAuth/role/roleList.vue

@@ -0,0 +1,222 @@
+<template>
+  <a-card :bordered="false">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+          <a-col :md="6" :sm="24">
+            <a-form-item label="角色名称">
+              <a-input allowClear v-model.trim="queryParam.name" 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.isEnable" 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-col>
+        </a-row>
+      </a-form>
+    </div>
+    <a-divider/>
+    <div class="table-operator">
+      <a-button type="primary" icon="plus" @click="openModal">新建</a-button>
+    </div>
+
+    <s-table
+      ref="table"
+      size="default"
+      rowKey="id"
+      :columns="columns"
+      :data="loadData"
+      bordered
+    >
+      <span slot="status" slot-scope="text, record">
+        <a-switch checkedChildren="" unCheckedChildren="" v-model="record.isEnable" @change="changeFlagHandle(text, record)"/>
+      </span>
+
+      <span slot="action" slot-scope="text, record">
+        <template>
+          <a class="action-button menu-text" @click="openMenuModal(record)">菜单权限</a>
+          <a class="action-button" @click="handleEdit(record)">修改</a>
+          <a v-if="!record.isEnable" class="action-button red-text" @click="delect(record)">删除</a>
+        </template>
+      </span>
+    </s-table>
+    <roleModal :visible="showModal" :data="itemData" @refresh="refreshTable" @close="showModal = false"></roleModal>
+    <menuModal :visible="showMenuModal" :data="menuData" @close="showMenuModal = false"></menuModal>
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import roleModal from './roleModal.vue'
+import menuModal from './menuModal.vue'
+import { getPowerRoleList, updateEnableStatus, delectRolePower, getMenuList } from '@/api/power-role.js'
+export default {
+  name: 'RoleList',
+  components: {
+    STable, VSelect, roleModal, menuModal
+  },
+  data () {
+    return {
+      // 查询参数
+      queryParam: {
+        name: '',
+        isEnable: ''
+      },
+      showModal: false,
+      showMenuModal: false,
+      itemData: {}, // 编辑行数据
+      menuData: {},
+      // 表头
+      columns: [
+        {
+          title: '序号',
+          dataIndex: 'no',
+          width: '40',
+          align: 'center'
+        },
+        {
+          title: '角色名称',
+          dataIndex: 'name',
+          width: '100',
+          align: 'center'
+        },
+        {
+          title: '角色描述',
+          dataIndex: 'remarks',
+          width: '100',
+          align: 'center'
+        },
+        {
+          title: '状态',
+          width: '100',
+          align: 'center',
+          scopedSlots: { customRender: 'status' }
+        },
+        {
+          title: '创建时间',
+          dataIndex: 'createDate',
+          width: '120',
+          align: 'center'
+        },
+        {
+          title: '操作',
+          width: '100',
+          align: 'center',
+          scopedSlots: { customRender: 'action' }
+        }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        return getPowerRoleList(Object.assign(parameter, this.queryParam)).then(res => {
+          const no = (res.data.pageNo - 1) * res.data.pageSize
+          for (let i = 0; i < res.data.list.length; i++) {
+            const _item = res.data.list[i]
+            _item.no = no + i + 1
+            _item.isEnable = _item.isEnable + '' === '1'
+          }
+          return res.data
+        })
+      },
+      optionAlertShow: false
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      // vm.$refs.table.refresh()
+    })
+  },
+  methods: {
+    // 刷新列表
+    refreshTable () {
+      this.$refs.table.refresh(true)
+    },
+    // 新建
+    openModal () {
+      this.showModal = true
+      this.itemData = {}
+    },
+    // 打开分配权限弹窗
+    openMenuModal (row) {
+      this.getMenuList(row.id)
+    },
+    // 获取菜单树列表
+    getMenuList (id) {
+      const _this = this
+      getMenuList({ id: id }).then(res => {
+        if (res.status == 200) {
+          _this.menuData = res.data
+          this.showMenuModal = true
+        }
+      })
+    },
+
+    // 删除
+    delect (row) {
+      const _this = this
+      this.$confirm({
+        title: '警告',
+        content: '删除后无法恢复,确认删除?',
+        okText: '确定',
+        cancelText: '取消',
+        onOk () {
+          delectRolePower({
+            id: row.id
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success('删除成功')
+              _this.$refs.table.refresh()
+            } else {
+              this.$message.error(res.message)
+            }
+          }).catch(() => {
+            _this.$message.success('删除失败, 请稍后重试')
+          })
+        }
+      })
+    },
+    handleEdit (row) {
+      this.showModal = true
+      this.itemData = row
+    },
+    // 修改状态
+    changeFlagHandle (text, record) {
+      const _data = {
+        id: record.id,
+        flag: record.isEnable ? '1' : '0'
+      }
+      updateEnableStatus(_data).then(res => {
+        if (res.status + '' === '200') {
+          this.$message.success('修改成功')
+        } else {
+          record.isEnable = !record.isEnable
+        }
+      })
+    }
+  }
+}
+</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;
+  }
+  .menu-text {
+    background-color: #f90;
+  }
+</style>

+ 172 - 0
src/views/CardVoucherAuth/role/roleModal.vue

@@ -0,0 +1,172 @@
+<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 }">
+          <a-input
+            placeholder="请输入角色名称"
+            v-decorator="['formData.name', {
+              initialValue: formData.name,
+              rules: [{ required: true, message: '请输入角色名称!' },{pattern:'^[^<|>]{1,20}$',message:'请输入不含<或>的字符,最多20个字符'}] }]"
+          />
+        </a-form-item>
+
+        <!-- 状态 -->
+        <a-form-item label="状态" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
+          <a-radio-group
+            name="radioGroup"
+            v-decorator="[
+              'formData.isEnable',
+              {
+                initialValue: formData.isEnable,
+                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-textarea
+            v-decorator="[
+              'formData.remarks',
+              { initialValue: formData.remarks,
+                rules: [] },
+            ]"
+            style="min-height: 60px;"
+            placeholder=""
+            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>
+        </a-form-item>
+      </a-form>
+
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import { saveRolePower } from '@/api/power-role.js'
+export default {
+  name: 'RoleModal',
+  components: {
+    STable, VSelect
+  },
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    data: {
+      type: Object,
+      default: function () {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      titleText: '添加角色',
+      isshow: this.visible,
+      formLayout: 'horizontal',
+      form: this.$form.createForm(this, { name: 'roleModal' }),
+      formData: {
+        name: '',
+        isEnable: '', // 活动状态
+        remarks: ''
+      }
+
+    }
+  },
+  methods: {
+    cancel (e) {
+      this.clear()
+      this.$emit('close')
+    },
+
+    // 保存提交
+    handleSubmit () {
+      const _this = this
+      this.form.validateFields((err, values) => {
+        if (!err) {
+          saveRolePower(Object.assign(this.formData, values.formData)).then(res => {
+            if (res.status + '' === '200') {
+              this.$message.success(res.message ? res.message : '保存成功')
+              this.$emit('refresh')
+              setTimeout(function () {
+                _this.cancel()
+              }, 300)
+            } else {
+              // this.$message.error(res.message)
+            }
+          })
+        }
+      })
+    },
+    // 取消
+    handleCancel () {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确定取消吗?',
+        okText: '确定',
+        cancelText: '取消',
+        onOk () {
+          _this.clear()
+          _this.cancel()
+        }
+      })
+    },
+    clear () {
+      this.form.resetFields()
+      delete this.formData.id
+      this.formData.name = ''
+      this.formData.isEnable = ''
+      this.formData.remarks = ''
+    }
+
+  },
+  mounted () {
+  },
+  beforeCreate () {
+    this.form = this.$form.createForm(this, { name: 'roleModal' })
+  },
+  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
+          this.formData.isEnable = Number(this.formData.isEnable)
+        } else {
+          this.titleText = '添加角色'
+        }
+      } else {
+        this.cancel()
+      }
+    }
+  }
+}
+</script>
+
+<style >
+  .modalBox{
+  }
+  .ant-modal-footer {
+    display: none;
+  }
+</style>

+ 242 - 0
src/views/CardVoucherAuth/user/userList.vue

@@ -0,0 +1,242 @@
+<template>
+  <a-card :bordered="false">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+          <a-col :md="6" :sm="24">
+            <a-form-item label="用户名称">
+              <a-input 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.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>
+            </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="table-operator">
+      <a-button type="primary" icon="plus" @click="openModal">新建</a-button>
+    </div>
+
+    <s-table
+      ref="table"
+      size="default"
+      rowKey="id"
+      :columns="columns"
+      :data="loadData"
+      bordered
+    >
+      <span slot="status" slot-scope="text, record">
+        <a-switch checkedChildren="" unCheckedChildren="" v-model="record.loginFlag" @change="changeFlagHandle(text, record)"/>
+      </span>
+      <div slot="roleNames" slot-scope="text, record" :title="record.roleNames">
+        <span v-if="record.roleNames">{{ record.roleNames.substr(0,12) + '...' }}</span>
+        <span v-else>无</span>
+      </div>
+      <span slot="action" slot-scope="text, record">
+        <template>
+          <div >
+            <a class="action-button" @click="handleEdit(record)">修改</a>
+            <a v-if="record.loginFlag" class="action-button reset-text" @click="resetPassword(record)">重置密码</a>
+            <a v-if="!record.loginFlag" class="action-button red-text" @click="delect(record)">删除</a>
+          </div>
+        </template>
+      </span>
+    </s-table>
+    <userModal :visible="showModal" @refresh="$refs.table.refresh(true)" :data="itemData" @close="showModal = false"></userModal>
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import userModal from './userModal.vue'
+import { resetPSD, updateEnableStatus, getPowerUserList, delectUserPower } from '@/api/power-user.js'
+export default {
+  name: 'UserList',
+  components: {
+    STable, VSelect, userModal
+  },
+  data () {
+    return {
+      // 查询参数
+      queryParam: {
+        name: '',
+        phone: '',
+        loginFlag: ''
+      },
+      showModal: false,
+      itemData: {}, // 编辑行数据
+      // 表头
+      columns: [
+        {
+          title: '序号',
+          dataIndex: 'no',
+          width: '40',
+          align: 'center'
+        },
+        {
+          title: '用户名称',
+          dataIndex: 'name',
+          width: '100',
+          align: 'center'
+        },
+        {
+          title: '手机号码',
+          dataIndex: 'phone',
+          width: '100',
+          align: 'center'
+        },
+        {
+          title: '角色',
+          width: '100',
+          align: 'center',
+          scopedSlots: { customRender: 'roleNames' }
+        },
+        {
+          title: '状态',
+          width: '100',
+          align: 'center',
+          scopedSlots: { customRender: 'status' }
+        },
+        {
+          title: '创建时间',
+          dataIndex: 'createDate',
+          width: '120',
+          align: 'center'
+        },
+        {
+          title: '操作',
+          width: '100',
+          align: 'center',
+          scopedSlots: { customRender: 'action' }
+        }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        return getPowerUserList(Object.assign(parameter, this.queryParam)).then(res => {
+          const no = (res.data.pageNo - 1) * res.data.pageSize
+          for (let i = 0; i < res.data.list.length; i++) {
+            const _item = res.data.list[i]
+            _item.no = no + i + 1
+            _item.loginFlag = _item.loginFlag + '' === '1'
+          }
+          return res.data
+        })
+      },
+      optionAlertShow: false
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      // vm.$refs.table.refresh()
+    })
+  },
+  methods: {
+    // 刷新列表
+    refreshTable () {
+      this.$refs.table.refresh(true)
+    },
+    // 新建
+    openModal () {
+      this.showModal = true
+      this.itemData = {}
+    },
+    // 重置密码
+    resetPassword (row) {
+      resetPSD({
+        id: row.id
+      }).then(res => {
+        if (res.status == 200) {
+          this.$message.success('密码重置成功')
+        } else {
+          this.$message.error(res.message)
+        }
+      }).catch(() => {
+        this.$message.success('密码重置失败, 请稍后重试')
+      })
+    },
+    // 删除
+    delect (row) {
+      const _this = this
+      this.$confirm({
+        title: '警告',
+        content: '删除后无法恢复,确认删除?',
+        okText: '确定',
+        cancelText: '取消',
+        onOk () {
+          delectUserPower({
+            id: row.id
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success('删除成功')
+              _this.$refs.table.refresh()
+            } else {
+              _this.$message.error(res.message)
+            }
+          }).catch(() => {
+            _this.$message.success('删除失败, 请稍后重试')
+          })
+        }
+      })
+    },
+    getBizStr (storeBizList) {
+      const str = []
+      storeBizList.forEach(item => {
+        str.push(item.bizTypeName)
+      })
+      return str.join(',')
+    },
+    handleEdit (row) {
+      this.showModal = true
+      this.itemData = row
+    },
+    // 修改状态
+    changeFlagHandle (text, record) {
+      const _data = {
+        id: record.id,
+        flag: record.loginFlag ? '1' : '0'
+      }
+      updateEnableStatus(_data).then(res => {
+        if (res.status + '' === '200') {
+          this.$message.success('修改成功')
+        } else {
+          record.loginFlag = !record.loginFlag
+        }
+      })
+    }
+  }
+}
+</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>

+ 268 - 0
src/views/CardVoucherAuth/user/userModal.vue

@@ -0,0 +1,268 @@
+<template>
+  <div>
+    <a-modal class="modalBox" :title="titleText" v-model="isshow" @cancle="cancel">
+      <a-form :form="form" @submit="handleSubmit">
+        <a-row :gutter="24">
+          <a-col :span="12">
+            <!-- 用户名称 -->
+            <a-form-item label="用户名称" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }">
+              <a-input
+                placeholder="请输入用户名称"
+                v-decorator="['formData.name', {
+                  initialValue: formData.name,
+                  rules: [{ required: true, message: '请输入用户名称!' },{pattern:'^[^<|>]{1,20}$',message:'请输入不含<或>的字符,最多20个字符'}] }]"
+              />
+            </a-form-item>
+          </a-col>
+          <a-col :span="12">
+            <!-- 手机号码 -->
+            <a-form-item label="手机号码" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }">
+              <a-input
+                placeholder="请输入手机号码"
+                v-decorator="['formData.phone', {
+                  initialValue: formData.phone,
+                  rules: [{ required: true, message: '请输入手机号码!' },{pattern:/^[1][0-9]{10}$/, message: '请输入正确的手机号码!'}] }]"
+              />
+            </a-form-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 }">
+              <v-select
+                code="SEX"
+                v-decorator="[
+                  'formData.sex',
+                  {
+                    initialValue: formData.sex,
+                    rules: [{ required: true, message: '请选择性别!' }] },
+                ]"
+                allowClear ></v-select>
+
+            </a-form-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-radio :value="1">是</a-radio>
+                <a-radio :value="0">否</a-radio>
+              </a-radio-group>
+
+            </a-form-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-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
+                >
+              </a-select>
+            </a-form-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;"
+                placeholder=""
+                autosize />
+            </a-form-item>
+          </a-col>
+        </a-row>
+        <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 { getRoleList, saveUserPower } from '@/api/power-user.js'
+export default {
+  name: 'UserModal',
+  components: {
+    STable, VSelect
+  },
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    data: {
+      type: Object,
+      default: function () {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      titleText: '添加用户',
+      isshow: this.visible,
+      formLayout: 'horizontal',
+      form: this.$form.createForm(this, { name: 'miniForm' }),
+      roleList: [],
+      formData: {
+        roleNames: undefined, // 角色
+        name: '',
+        loginFlag: '', // 活动状态
+        phone: '',
+        sex: '',
+        remarks: ''
+      }
+    }
+  },
+  methods: {
+    cancel (e) {
+      this.clear()
+      this.$emit('close')
+    },
+
+    // 保存提交
+    handleSubmit () {
+      const _this = this
+      this.form.validateFields((err, values) => {
+        if (!err) {
+          values.formData.roleNames = values.formData.roleNames.join(',')
+          saveUserPower(Object.assign({ id: this.data.id ? this.data.id : '' }, values.formData)).then(res => {
+            if (res.status + '' === '200') {
+              this.$message.success(res.message ? res.message : '保存成功')
+              this.$emit('refresh')
+              setTimeout(function () {
+                _this.cancel()
+              }, 300)
+            } else {
+              // this.$message.error(res.message)
+            }
+          })
+        }
+      })
+    },
+    // 取消
+    handleCancel () {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确定取消吗?',
+        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 => {
+        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
+          if (roleNames) {
+            roleNames = roleNames.split(',')
+            const arr = []
+            roleNames.map(item => {
+              const row = this.roleList.find(a => {
+                return a.name == item
+              })
+              if (row) {
+                arr.push(row.id)
+              }
+            })
+            this.formData.roleNames = arr
+          } else {
+            this.formData.roleNames = []
+          }
+
+          this.formData.loginFlag = Number(this.formData.loginFlag)
+        } else {
+          this.titleText = '添加用户'
+        }
+      } else {
+        this.cancel()
+      }
+    }
+  }
+}
+</script>
+
+<style >
+  .modalBox{
+  }
+  .ant-modal-footer {
+    display: none;
+  }
+</style>

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

@@ -0,0 +1,302 @@
+<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="请输入名称"
+            v-decorator="['formData.name', {
+              initialValue: formData.name,
+              rules: [{ required: true, message: '请输入名称!' },{pattern:'^[^<|>]{1,20}$',message:'请输入不含<或>的字符,最多20个字符'}] }]"
+          />
+        </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
+            type="number"
+            placeholder="请输入排序值"
+            v-decorator="['formData.sort', {
+              initialValue: formData.sort,
+              rules: [] }]"
+          />
+        </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>

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

@@ -0,0 +1,457 @@
+<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="请输入名称"
+              v-decorator="['formData.name', {
+                initialValue: formData.name,
+                rules: [{ required: true, message: '请输入名称!' },{pattern:'^[^<|>]{1,20}$',message:'请输入不含<或>的字符,最多20个字符'}] }]"
+            />
+          </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
+              type="number"
+              placeholder="请输入排序值"
+              v-decorator="['formData.sort', {
+                initialValue: formData.sort,
+                rules: [] }]"
+            />
+          </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>