菜单优化

This commit is contained in:
吕金泽 2022-01-07 01:08:42 +08:00
parent bbb1c5ccc7
commit 02cd4e7986
8 changed files with 162 additions and 82 deletions

View File

@ -4,11 +4,11 @@
"script" : null, "script" : null,
"groupId" : "67b2ce258e24491194b74992958c74aa", "groupId" : "67b2ce258e24491194b74992958c74aa",
"name" : "修改是否显示", "name" : "修改是否显示",
"createTime" : 1634724871168, "createTime" : null,
"updateTime" : 1634724871168, "updateTime" : 1641482987357,
"lock" : "0", "lock" : "0",
"method" : "GET", "method" : "GET",
"path" : "/change/show", "path" : "/change",
"parameters" : [ ], "parameters" : [ ],
"option" : "[{\"name\":\"wrap_request_parameter\",\"value\":\"data\",\"description\":\"包装请求参数到一个变量中\"}]", "option" : "[{\"name\":\"wrap_request_parameter\",\"value\":\"data\",\"description\":\"包装请求参数到一个变量中\"}]",
"requestBody" : "", "requestBody" : "",

View File

@ -5,7 +5,7 @@
"groupId" : "67b2ce258e24491194b74992958c74aa", "groupId" : "67b2ce258e24491194b74992958c74aa",
"name" : "当前用户菜单", "name" : "当前用户菜单",
"createTime" : null, "createTime" : null,
"updateTime" : 1641279378685, "updateTime" : 1641482674575,
"lock" : "0", "lock" : "0",
"method" : "POST", "method" : "POST",
"path" : "/current/menus", "path" : "/current/menus",
@ -453,7 +453,8 @@ var menus = db.select("""
sm.is_show, sm.is_show,
sm.url, sm.url,
sm.sort, sm.sort,
sm.icon sm.icon,
sm.keep_alive
from sys_menu sm where 1=1 from sys_menu sm where 1=1
?{userId != '1', ?{userId != '1',
and sm.id in ( and sm.id in (
@ -470,6 +471,7 @@ for(menu in menus){
menu.meta = {} menu.meta = {}
menu.meta.title = menu.name menu.meta.title = menu.name
menu.meta.icon = menu.icon menu.meta.icon = menu.icon
menu.meta.keepAlive = (menu.keepAlive == '1' ? true : false)
} }
var nodes = menus.toMap(it => it.id) var nodes = menus.toMap(it => it.id)
nodes.each((key, node) => { nodes.each((key, node) => {

View File

@ -5,7 +5,7 @@
"groupId" : "67b2ce258e24491194b74992958c74aa", "groupId" : "67b2ce258e24491194b74992958c74aa",
"name" : "获取菜单tree", "name" : "获取菜单tree",
"createTime" : null, "createTime" : null,
"updateTime" : 1641016870466, "updateTime" : 1641483087321,
"lock" : "0", "lock" : "0",
"method" : "GET", "method" : "GET",
"path" : "/tree", "path" : "/tree",
@ -94,7 +94,7 @@
} }
================================ ================================
var toTree = (list,pid) => select t.*,toTree(list,t.id) children from list t where t.pid = pid var toTree = (list,pid) => select t.*,toTree(list,t.id) children from list t where t.pid = pid
var list = toTree(db.select('select id,name,pid,is_show,url,sort,permission,desc_ribe,icon from sys_menu where is_del = 0 order by sort'),'0') var list = toTree(db.select('select id,name,pid,is_show,url,sort,permission,desc_ribe,icon,keep_alive from sys_menu where is_del = 0 order by sort'),'0')
return { return {
list: list, list: list,

View File

@ -1,10 +1,9 @@
<template> <template>
<section class="app-main"> <section class="app-main">
<transition name="fade-transform" mode="out-in"> <keep-alive>
<keep-alive :include="cachedViews"> <router-view v-if="$route.meta.keepAlive" :key="key" />
<router-view :key="key" /> </keep-alive>
</keep-alive> <router-view v-if="!$route.meta.keepAlive" :key="key" />
</transition>
</section> </section>
</template> </template>
@ -12,9 +11,6 @@
export default { export default {
name: 'AppMain', name: 'AppMain',
computed: { computed: {
cachedViews() {
return this.$store.state.tagsView.cachedViews
},
key() { key() {
return this.$route.path return this.$route.path
} }

View File

@ -1,3 +1,19 @@
<template> <template>
<router-view /> <div>
<keep-alive>
<router-view v-if="$route.meta.keepAlive" :key="key" />
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" :key="key" />
</div>
</template> </template>
<script>
export default {
name: 'None',
computed: {
key() {
return this.$route.path
}
}
}
</script>

View File

@ -14,9 +14,9 @@ export const constantRoutes = [
redirect: '/dashboard', redirect: '/dashboard',
children: [{ children: [{
path: 'dashboard', path: 'dashboard',
name: '首页', name: 'Dashboard',
component: () => import('@/views/dashboard/index'), component: () => import('@/views/dashboard/index'),
meta: { title: '首页', icon: 'home' } meta: { title: '首页', icon: 'home', noCache: false }
}] }]
}, },

View File

@ -3,50 +3,83 @@
<div class="filter-container"> <div class="filter-container">
<el-form :inline="true"> <el-form :inline="true">
<el-form-item label="搜索菜单名称"> <el-form-item label="菜单搜索">
<el-input v-model="searchValue" @input="searchMenu"></el-input> <el-input v-model="searchValue" @input="searchMenu" placeholder="菜单名称、链接、权限标识" style="width: 200px"></el-input>
</el-form-item> </el-form-item>
<el-button class="filter-item" style="margin-bottom:10px;" type="primary" icon="el-icon-edit" @click="addSubMenu('0')"> <el-button class="filter-item" type="primary" icon="el-icon-search" @click="searchMenu">
添加菜单 搜索
</el-button>
<el-button class="filter-item" icon="el-icon-delete" @click="() => { this.searchValue = ''; searchMenu() }">
清空
</el-button> </el-button>
</el-form> </el-form>
</div> </div>
<el-row style="margin-bottom: 5px">
<el-button class="filter-item" style="margin-bottom:10px;" type="primary" icon="el-icon-edit" @click="addSubMenu('0')">
添加菜单
</el-button>
</el-row>
<pd-table ref="table" v-bind="tableOptions" v-if="menuData && menuData.length > 0" /> <pd-table ref="table" v-bind="tableOptions" v-if="menuData && menuData.length > 0" />
<pd-dialog ref="menuFormDialog" width="800px" :title="textMap[dialogStatus]" @confirm-click="save()"> <pd-dialog ref="menuFormDialog" width="800px" :title="textMap[dialogStatus]" @confirm-click="save()">
<template #content> <template #content>
<el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="100px" style="width: 600px; margin-left:50px;"> <el-form ref="dataForm" :rules="rules" :model="temp" label-position="right" label-width="80px" style="width: 600px; margin-left:50px;">
<el-form-item label="上级菜单" prop="pid"> <el-row :gutter="24">
<treeselect v-model="temp.pid" :options="menuTree" /> <el-col :span="12">
</el-form-item> <el-form-item label="菜单类型" prop="type">
<el-radio-group v-model="temp.type" size="small">
<el-radio-button label="menu">菜单</el-radio-button>
<el-radio-button label="button">按钮</el-radio-button>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="上级菜单" prop="pid">
<treeselect v-model="temp.pid" :options="menuTree" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="菜单名称" prop="name"> <el-form-item label="菜单名称" prop="name">
<el-input v-model="temp.name" /> <el-input v-model="temp.name" />
</el-form-item> </el-form-item>
<el-form-item label="菜单链接" prop="url"> <el-form-item label="菜单链接" prop="url" v-if="temp.type == 'menu'">
<el-input v-model="temp.url" /> <el-input v-model="temp.url" />
</el-form-item> </el-form-item>
<el-form-item label="权限标识" prop="permission"> <el-form-item label="权限标识" prop="permission">
<el-input v-model="temp.permission" /> <el-input v-model="temp.permission" />
</el-form-item> </el-form-item>
<el-form-item label="图标" prop="icon"> <el-row :gutter="24">
<a @click="openIcons"> <el-col :span="12">
<el-input placeholder="请选择图标" v-model="temp.icon" class="input-with-select"> <el-form-item label="图标" prop="icon" v-if="temp.type == 'menu'">
<el-button class="icon-btn" slot="append"> <a @click="openIcons">
<i v-html="generateIconCode(temp.icon)"></i> <el-input placeholder="请选择图标" v-model="temp.icon" class="input-with-select">
</el-button> <el-button class="icon-btn" slot="append">
</el-input> <i v-html="generateIconCode(temp.icon)"></i>
</a> </el-button>
</el-form-item> </el-input>
<el-form-item label="排序" prop="sort"> </a>
<el-input v-model="temp.sort" /> </el-form-item>
</el-form-item> </el-col>
<el-form-item label="描述"> <el-col :span="12">
<el-input v-model="temp.descRibe" :autosize="{ minRows: 4, maxRows: 6}" type="textarea" /> <el-form-item label="排序" prop="sort">
</el-form-item> <el-input-number v-model="temp.sort" controls-position="right" />
<el-form-item label="是否显示"> </el-form-item>
<el-checkbox v-model="temp.isShow">显示</el-checkbox> </el-col>
</el-form-item> </el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="是否显示" v-if="temp.type == 'menu'">
<el-switch v-model="temp.isShow" :active-value="1" :inactive-value="0"></el-switch>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否缓存" v-if="temp.type == 'menu'">
<el-switch v-model="temp.keepAlive" :active-value="1" :inactive-value="0"></el-switch>
</el-form-item>
</el-col>
</el-row>
</el-form> </el-form>
</template> </template>
</pd-dialog> </pd-dialog>
@ -90,13 +123,15 @@ export default {
{ {
field: 'url', field: 'url',
title: '路径', title: '路径',
align: 'left' align: 'left',
type: 'html'
}, },
{ {
field: 'permission', field: 'permission',
title: '权限标识', title: '权限标识',
width: 150, width: 150,
align: 'left' align: 'left',
type: 'html'
}, },
{ {
field: 'icon', field: 'icon',
@ -118,12 +153,24 @@ export default {
type: 'switch', type: 'switch',
width: 100, width: 100,
change: (row) => { change: (row) => {
this.$get('menu/change/show', { this.$get('menu/change', {
id: row.id, id: row.id,
isShow: row.isShow isShow: row.isShow
}) })
} }
}, },
{
field: 'keepAlive',
title: '是否缓存',
type: 'switch',
width: 100,
change: (row) => {
this.$get('menu/change', {
id: row.id,
keepAlive: row.keepAlive
})
}
},
{ {
title: '操作', title: '操作',
type: 'btns', type: 'btns',
@ -172,13 +219,26 @@ export default {
rules: { rules: {
pid: [{ required: true, message: '请选择上级菜单', trigger: 'change' }], pid: [{ required: true, message: '请选择上级菜单', trigger: 'change' }],
name: [{ required: true, message: '请输入菜单名称', trigger: 'change' }] name: [{ required: true, message: '请输入菜单名称', trigger: 'change' }]
} },
searchTimeout: ''
} }
}, },
mounted() { mounted() {
this.reloadTable() this.reloadTable()
}, },
watch: { watch: {
'temp.type'(type) {
for (var t in this.getTemp()) {
if(t != 'type'){
this.temp[t] = row[t]
}
}
if(type == 'menu'){
this.temp.isShow = 1
}else{
this.temp.isShow = 0
}
},
menuData() { menuData() {
this.menuTree = [{ this.menuTree = [{
label: '根节点', label: '根节点',
@ -234,11 +294,15 @@ export default {
return menuTree return menuTree
}, },
searchMenu() { searchMenu() {
if(this.searchValue){ var _this = this
this.$set(this.tableOptions, 'data', this.recursionSearch(this.$common.copyNew(this.menuData), this.searchValue)) clearTimeout(this.searchTimeout)
}else{ this.searchTimeout = setTimeout(() => {
this.$set(this.tableOptions, 'data', this.menuData) if(_this.searchValue){
} _this.$set(_this.tableOptions, 'data', _this.recursionSearch(_this.$common.copyNew(_this.menuData), _this.searchValue))
}else{
_this.$set(_this.tableOptions, 'data', _this.menuData)
}
},1000)
}, },
recursionSearch(data, text){ recursionSearch(data, text){
var searchData = [] var searchData = []
@ -248,21 +312,28 @@ export default {
if(children && children.length > 0){ if(children && children.length > 0){
var childrenSearch = this.recursionSearch(children, text) var childrenSearch = this.recursionSearch(children, text)
treeNode.children = childrenSearch && childrenSearch.length > 0 ? childrenSearch : treeNode.children treeNode.children = childrenSearch && childrenSearch.length > 0 ? childrenSearch : treeNode.children
if(treeNode.name.indexOf(text) != -1 || childrenSearch.length > 0){ this.treeNodeReplace(searchData, treeNode, text, childrenSearch)
treeNode.name = treeNode.name.replace(text, `<font color="#FAA353">${text}</font>`)
searchData.push(treeNode)
}
}else{ }else{
if(treeNode.name.indexOf(text) != -1){ this.treeNodeReplace(searchData, treeNode, text)
treeNode.name = treeNode.name.replace(text, `<font color="#FAA353">${text}</font>`)
searchData.push(treeNode)
}
} }
} }
return searchData return searchData
}, },
treeNodeReplace(searchData, treeNode, text, childrenSearch){
var exist = false
var fields = ['name', 'url', 'permission']
fields.forEach((f) => {
if(treeNode[f] && treeNode[f].indexOf(text) != -1){
treeNode[f] = treeNode[f].replace(text, `<font color="#FAA353">${text}</font>`)
exist = true
}
})
if(exist || (childrenSearch && childrenSearch.length > 0)){
searchData.push(treeNode)
}
},
generateIconCode(symbol) { generateIconCode(symbol) {
return `<svg style="width: 20px;height: 20px" aria-hidden="true" class="svg-icon disabled"><use href="#icon-${symbol}"></use></svg>` return `<svg style="width: 20px;height: 20px;fill: #999" aria-hidden="true" class="svg-icon disabled"><use href="#icon-${symbol}"></use></svg>`
}, },
selectIcon(symbol) { selectIcon(symbol) {
this.$set(this.temp, 'icon', symbol) this.$set(this.temp, 'icon', symbol)
@ -279,9 +350,11 @@ export default {
permission: '', permission: '',
sort: 0, sort: 0,
descRibe: '', descRibe: '',
isShow: true, isShow: 1,
pid: '', pid: '',
icon: '' icon: '',
type: 'menu',
keepAlive: 1
} }
}, },
resetTemp() { resetTemp() {
@ -324,7 +397,6 @@ export default {
}) })
return return
} }
this.temp.isShow = this.temp.isShow === true ? 1 : 0
this.$post('menu/save', this.temp).then(() => { this.$post('menu/save', this.temp).then(() => {
this.reloadTable() this.reloadTable()
this.$refs.menuFormDialog.hide() this.$refs.menuFormDialog.hide()
@ -346,16 +418,9 @@ export default {
}, },
handleUpdate(row) { handleUpdate(row) {
for (var t in this.temp) { for (var t in this.temp) {
if (t === 'isShow') { this.temp[t] = row[t]
if (row[t] === 1) {
this.temp[t] = true
} else {
this.temp[t] = false
}
} else {
this.temp[t] = row[t]
}
} }
this.temp.type = this.temp.url ? 'menu' : 'button'
this.temp.name = this.temp.name.replaceAll(/<font.*?>(.*?)<\/font>/g,'$1') this.temp.name = this.temp.name.replaceAll(/<font.*?>(.*?)<\/font>/g,'$1')
this.dialogStatus = 'update' this.dialogStatus = 'update'
this.$refs.menuFormDialog.show() this.$refs.menuFormDialog.show()

View File

@ -11,20 +11,21 @@
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="reloadTable"> <el-button class="filter-item" type="primary" icon="el-icon-search" @click="reloadTable">
搜索 搜索
</el-button> </el-button>
<el-button v-permission="'user:save'" class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate"> <el-button :loading="downloadLoading" class="filter-item" icon="el-icon-delete" @click="tableOptions.where = {}">
添加 清空
</el-button> </el-button>
<el-button :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload"> <el-button :loading="downloadLoading" class="filter-item" icon="el-icon-download" @click="handleDownload">
导出 导出
</el-button> </el-button>
</el-form> </el-form>
</div> </div>
<hr> <el-row style="margin-bottom: 15px">
<el-row style="margin-bottom: 6px"> <el-button v-permission="'user:save'" class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">
<pd-button plain :request-url="'user/delete'" :btn-type="'delete'" :request-data="{ id: ids }" :after-handler="reloadTable" /> 添加
</el-button>
<pd-button :el="{ plain: true }" :request-url="'user/delete'" :btn-type="'delete'" :request-data="{ id: ids }" :after-handler="reloadTable" />
</el-row> </el-row>
<hr>
<pd-table ref="table" v-bind="tableOptions" @selection-change="selectionChange" /> <pd-table ref="table" v-bind="tableOptions" @selection-change="selectionChange" />