|
@@ -0,0 +1,487 @@
|
|
|
+<template>
|
|
|
+ <a-card :bordered="false">
|
|
|
+ <a-row :gutter="24">
|
|
|
+ <a-button
|
|
|
+ v-if="$hasPermissions('B_power_menu_child_add')"
|
|
|
+ style="margin-right: 10px;"
|
|
|
+ type="primary"
|
|
|
+ icon="plus"
|
|
|
+ @click="addChild"
|
|
|
+ id="menu-addChild">新增子菜单</a-button>
|
|
|
+ <a-button
|
|
|
+ v-if="$hasPermissions('B_power_menu_top_add')"
|
|
|
+ style="margin-right: 10px;background-color: #19be6b;color: #fff;"
|
|
|
+ type=""
|
|
|
+ icon="plus"
|
|
|
+ @click="addTitle"
|
|
|
+ id="menu-addTitle">新增顶部菜单</a-button>
|
|
|
+ <a-button
|
|
|
+ v-if="$hasPermissions('B_power_menu_del')"
|
|
|
+ style="margin-right: 10px;background-color: red;color: #fff;"
|
|
|
+ type=""
|
|
|
+ icon="delete"
|
|
|
+ @click="delect()"
|
|
|
+ id="menu-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" id="menu-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"
|
|
|
+ allowClear
|
|
|
+ id="menu-name"
|
|
|
+ v-decorator="['formData.name', {
|
|
|
+ initialValue: formData.name,getValueFromEvent: $filterEmpty,
|
|
|
+ rules: [{ required: true, message: '请输入名称30个字以内!' },{pattern:'^[^<|>]{1,30}$',message:'请输入不含<或>的字符,最多30个字符'}] }]"
|
|
|
+ />
|
|
|
+ </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="请输入前端权限编码"
|
|
|
+ allowClear
|
|
|
+ id="menu-code"
|
|
|
+ v-decorator="[
|
|
|
+ 'formData.code',
|
|
|
+ {
|
|
|
+ initialValue: formData.code,getValueFromEvent: $filterEmpty,
|
|
|
+ rules: [{ required: true, message: '请输入前端权限编码!' }] },
|
|
|
+ ]"
|
|
|
+ />
|
|
|
+ </a-form-item>
|
|
|
+ <!-- 后台权限编码 -->
|
|
|
+ <a-form-item label="后台权限编码" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
|
|
|
+ <a-input
|
|
|
+ placeholder="请输入后台权限编码"
|
|
|
+ allowClear
|
|
|
+ id="menu-permission"
|
|
|
+ v-decorator="[
|
|
|
+ 'formData.permission',
|
|
|
+ {
|
|
|
+ initialValue: formData.permission,getValueFromEvent: $filterEmpty,
|
|
|
+ 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"
|
|
|
+ oninput="if(value.length>6)value=value.slice(0,6);if(value<0)value=0"
|
|
|
+ placeholder="请输入(0~999999)之间的排序值"
|
|
|
+ allowClear
|
|
|
+ id="menu-sort"
|
|
|
+ v-decorator="['formData.sort', {
|
|
|
+ initialValue: formData.sort,getValueFromEvent: $filterEmpty,
|
|
|
+ rules: [] }]"
|
|
|
+ />
|
|
|
+ </a-form-item>
|
|
|
+ <!-- 状态 -->
|
|
|
+ <a-form-item label="启用" :label-col="{ span: 5 }" :wrapper-col="{ span: 14 }">
|
|
|
+ <a-radio-group
|
|
|
+ name="radioGroup"
|
|
|
+ id="menu-status"
|
|
|
+ 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 v-if="$hasPermissions('B_power_menu_edit')" type="primary" @click="handleSubmit()" id="menu-handleSubmit">
|
|
|
+ 保存
|
|
|
+ </a-button>
|
|
|
+ <a-button :style="{ marginLeft: '8px' }" @click="clear" id="menu-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.clear()
|
|
|
+ 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>
|