262 lines
7.8 KiB
Vue
262 lines
7.8 KiB
Vue
<template>
|
|
<section class="AppMenuManager">
|
|
<ai-list>
|
|
<ai-title slot="title" title="菜单配置" isShowBottomBorder/>
|
|
<template #content>
|
|
<ai-search-bar>
|
|
<template #left>
|
|
<el-button type="primary" icon="el-icon-circle-plus" @click="addRootMenu">添加一级目录</el-button>
|
|
</template>
|
|
<template #right>
|
|
<el-input size="small" v-model="search" clearable @change="$refs.MenuTree.filter(search)"
|
|
placeholder="菜单名称"/>
|
|
<el-button icon="iconfont iconResetting" @click="getData">刷新</el-button>
|
|
</template>
|
|
</ai-search-bar>
|
|
<el-row type="flex" class="headerRow">
|
|
<div class="menuName" v-text="`菜单名称`"/>
|
|
<el-row type="flex" align="middle" class="info">
|
|
<div class="style" v-text="`图标`"/>
|
|
<div class="type" v-text="`菜单类型`"/>
|
|
<div class="component" v-text="`应用模块`"/>
|
|
<div class="status" v-text="`是否显示`"/>
|
|
<div class="showIndex" v-text="`排序`"/>
|
|
</el-row>
|
|
<div class="operation" v-text="`操作`"/>
|
|
</el-row>
|
|
<el-scrollbar>
|
|
<el-tree ref="MenuTree" :data="treeData" :props="{children:'subSet'}" highlight-current node-key="id"
|
|
:filter-node-method="handleSearch">
|
|
<el-row type="flex" align="middle" slot-scope="{node,data}" class="menuItem">
|
|
<div class="menuName" v-text="data.name"/>
|
|
<el-row type="flex" align="middle" class="info">
|
|
<div class="style" :class="data.style"/>
|
|
<div class="type" v-text="dict.getLabel('menuType',data.type)"/>
|
|
<div class="component" v-text="data.component"/>
|
|
<div class="status" v-text="dict.getLabel('yesOrNo',data.status)"/>
|
|
<div class="showIndex" v-text="data.showIndex"/>
|
|
</el-row>
|
|
<el-row type="flex" align="middle" class="operation">
|
|
<div v-if="node.isLeaf" class="opBtn del" v-text="`删除`" @click="handleDelete(data)"/>
|
|
<div v-if="data.type<2" class="opBtn" v-text="`添加下级`" @click="addMenu(data)"/>
|
|
<div class="opBtn" v-text="`编辑`" @click="handleEdit(data)"/>
|
|
</el-row>
|
|
</el-row>
|
|
</el-tree>
|
|
</el-scrollbar>
|
|
</template>
|
|
</ai-list>
|
|
<ai-dialog :visible.sync="dialog" title="菜单设置" width="500px" @onConfirm="handleSubmit"
|
|
@closed="form={},selected={}">
|
|
<el-form ref="MenuForm" :model="form" size="small" label-width="100px" :rules="rules">
|
|
<el-form-item label="菜单名称" prop="name">
|
|
<el-input v-model="form.name" placeholder="请输入" clearable/>
|
|
</el-form-item>
|
|
<el-form-item label="菜单类型" prop="type">
|
|
<ai-select v-model="form.type" clearable :selectList="dict.getDict('menuType')"/>
|
|
</el-form-item>
|
|
<template v-if="form.type==0">
|
|
<el-form-item label="菜单图标" prop="style">
|
|
<el-input v-model="form.style" placeholder="请输入" clearable/>
|
|
</el-form-item>
|
|
</template>
|
|
<template v-if="form.type==1">
|
|
<el-form-item label="菜单应用" prop="component">
|
|
<el-input v-model="form.component" placeholder="请输入" clearable/>
|
|
</el-form-item>
|
|
<el-form-item label="路径(path)" prop="path">
|
|
<el-input v-model="form.path" placeholder="请输入" clearable/>
|
|
</el-form-item>
|
|
</template>
|
|
<template v-if="form.type==2">
|
|
<el-form-item label="权限码" prop="permission">
|
|
<el-input v-model="form.permission" placeholder="请输入" clearable/>
|
|
</el-form-item>
|
|
</template>
|
|
<el-form-item label="显示菜单" prop="status">
|
|
<ai-select v-model="form.status" clearable :selectList="dict.getDict('yesOrNo')"/>
|
|
</el-form-item>
|
|
<el-form-item v-if="form.type<2" label="排序" prop="showIndex">
|
|
<el-input v-model="form.showIndex" placeholder="请输入" clearable/>
|
|
</el-form-item>
|
|
</el-form>
|
|
</ai-dialog>
|
|
</section>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
name: "AppMenuManager",
|
|
label: "菜单管理",
|
|
props: {
|
|
instance: Function,
|
|
dict: {default: () => ({})}
|
|
},
|
|
data() {
|
|
return {
|
|
treeData: [],
|
|
dialog: false,
|
|
form: {},
|
|
selected: {},
|
|
rules: {
|
|
name: [{required: true, message: "请输入 菜单名称"}],
|
|
type: [{required: true, message: "请选择 菜单类型"}],
|
|
status: [{required: true, message: "请选择 显示菜单"}],
|
|
showIndex: [{required: true, message: "请输入 排序"}],
|
|
permission: [{required: true, message: "请输入 权限码"}],
|
|
},
|
|
search: ""
|
|
}
|
|
},
|
|
methods: {
|
|
getData() {
|
|
return this.instance.post("/admin/menu/menuTree").then(res => {
|
|
if (res?.data) {
|
|
this.treeData = res.data
|
|
}
|
|
})
|
|
},
|
|
handleSubmit() {
|
|
this.$refs.MenuForm.validate(v => {
|
|
if (v) {
|
|
this.instance.post("/admin/menu/addOrUpdate", this.form).then(res => {
|
|
if (res?.code == 0) {
|
|
this.$message.success("提交成功!")
|
|
this.dialog = false
|
|
if (!!this.form.id) {
|
|
let node = this.$refs.MenuTree.getNode(this.form)
|
|
node.data = this.form
|
|
} else if (!!this.form.parentId) {
|
|
this.$refs.MenuTree.append(this.form, this.selected)
|
|
} else this.getData()
|
|
}
|
|
})
|
|
}
|
|
})
|
|
},
|
|
handleDelete(data) {
|
|
let {id} = data
|
|
this.$confirm("是否要删除该菜单").then(() => {
|
|
this.instance.post("/admin/menu/delete", null, {
|
|
params: {id}
|
|
}).then(res => {
|
|
if (res?.code == 0) {
|
|
this.$message.success("删除成功!")
|
|
this.dialog = false
|
|
this.$refs.MenuTree.remove(data)
|
|
}
|
|
})
|
|
}).catch(() => 0)
|
|
},
|
|
addRootMenu(row) {
|
|
this.dialog = true
|
|
this.selected = row
|
|
},
|
|
addMenu(row) {
|
|
this.dialog = true
|
|
this.form = {parentId: row.id}
|
|
this.selected = row
|
|
},
|
|
handleEdit(row) {
|
|
this.dialog = true
|
|
this.form = JSON.parse(JSON.stringify(row))
|
|
this.selected = row
|
|
},
|
|
handleSearch(value, data) {
|
|
if (!value) return true;
|
|
return data.name.indexOf(value) !== -1;
|
|
}
|
|
},
|
|
created() {
|
|
this.getData()
|
|
this.dict.load("yesOrNo", "menuType")
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.AppMenuManager {
|
|
height: 100%;
|
|
|
|
::v-deep .ai-list__content--right-wrapper {
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
.el-tree {
|
|
width: 100%;
|
|
height: 100%;
|
|
font-size: 14px;
|
|
|
|
.menuItem {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.el-tree-node__content {
|
|
border-bottom: 1px solid #d0d4dc;
|
|
}
|
|
}
|
|
|
|
.el-scrollbar {
|
|
flex: 1;
|
|
min-height: 0;
|
|
|
|
.el-scrollbar__wrap {
|
|
overflow-x: auto;
|
|
}
|
|
}
|
|
|
|
|
|
.headerRow {
|
|
background: #f3f4f5;
|
|
color: #666;
|
|
font-weight: bold;
|
|
align-items: center;
|
|
height: 40px;
|
|
|
|
.menuName {
|
|
padding-left: 16px;
|
|
}
|
|
}
|
|
|
|
.info {
|
|
gap: 16px;
|
|
text-align: center;
|
|
|
|
.showIndex, .status, .type, .style {
|
|
width: 80px;
|
|
}
|
|
|
|
.component {
|
|
width: 300px;
|
|
}
|
|
}
|
|
|
|
.operation {
|
|
width: 200px;
|
|
flex-shrink: 0;
|
|
justify-content: flex-end;
|
|
text-align: center;
|
|
|
|
.opBtn {
|
|
cursor: pointer;
|
|
width: 60px;
|
|
|
|
font-size: 14px;
|
|
color: #26f;
|
|
|
|
&.del {
|
|
color: #f46;
|
|
}
|
|
}
|
|
}
|
|
|
|
.menuName {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
}
|
|
}
|
|
</style>
|