258 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			258 lines
		
	
	
		
			7.6 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() {
 | |
|       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("提交成功!")
 | |
|               if (!this.form.id) {
 | |
|                 this.getData()
 | |
|               } else this.$refs.MenuTree.append(this.form, this.selected)
 | |
|             }
 | |
|           })
 | |
|         }
 | |
|       })
 | |
|     },
 | |
|     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>
 |