SpringBoot+SpringSecurity+MybatisPlus+Vue3小项目摘录(十)完结篇

角色信息管理模块化操作

提示:章节内容与用户管理的内容比较相似,可以参考/复制用户信息模块的code,做一回CV工程师吧!!!

角色管理【条件列表分页显示】

后端的控制SysRoleController请求方法编写

在这里插入图片描述

前端的视图处理

在这里插入图片描述

可以直接复制一套用户信息管理的内容,记得要将用户的一些内容全部修改成角色哦!

在这里插入图片描述

效果如下:

在这里插入图片描述

新增/修改角色信息管理

提示:用户信息模块化已经熟悉了就开始CV啊啊啊!!!

后端控制器的请求方法编写:

在这里插入图片描述

前端视图的处理
将用户模块的进行复制之后进行修改,需要的注意的点:
  • 1、角色信息表的属性对应表单进行一一的映射
  • 2、角色对象中属性的变化
  • 3、请求方法和路径的变化

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

效果如下:

在这里插入图片描述
在这里插入图片描述

删除/批量删除角色信息管理

行里的单个删除按钮和头部的批量删除的请求方法是共用的哦,需要主要的是删除之前按需要判断角色是否与用户进行了关联!!!

后端控制器的请求编写:

在这里插入图片描述

前端页面的处理:

在这里插入图片描述在这里插入图片描述

显示以及修改权限菜单树

参考中文官网https://element-plus.gitee.io/zh-CN/component/tree.html#%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95
在这里插入图片描述

预览效果:

在这里插入图片描述

后台控制器的的方法编写:

在这里插入图片描述

前端页面的处理:
参照官方的文档新建menuDialog.vue组件

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

预览效果如下:

在这里插入图片描述

代码规整:

后台控制器SysRoleController、SysMenuController如下:
SysRoleController
package com.xuguoguo.contorller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xuguoguo.common.ResponseData;
import com.xuguoguo.common.Result;
import com.xuguoguo.entity.*;
import com.xuguoguo.service.SysRoleMenuService;
import com.xuguoguo.service.SysRoleService;
import com.xuguoguo.service.SysUserRoleService;
import com.xuguoguo.utils.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 @Package: com.xuguoguo.contorller
 @ClassName: SysRoleController
 @Author: XuGuoGuo
 @CreateTime: 2023/12/18-22:52
 @Description:
 */



@RestController
@RequestMapping("/sys/role")
public class SysRoleController {
    @Autowired
    private SysRoleService sysRoleService;
    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private SysRoleMenuService sysRoleMenuService;

    /**
     * 获取当前角色的权限菜单ID集合
     * @param id
     * @return
     */
    @GetMapping("/menus/{id}")
    @PreAuthorize("hasAuthority('system:role:menu')")
    public Result menus(@PathVariable(value = "id")Integer id){
        List<SysRoleMenu> roleMenuList = sysRoleMenuService.list(new QueryWrapper<SysRoleMenu>().eq("role_id", id));
        List<Long> menuIdList = roleMenuList.stream().map(p -> p.getMenuId()).collect(Collectors.toList());
        return new Result().put("menuIdList",menuIdList);
    }

    /**
     * 更新角色权限信息
     * @param id
     * @param menuIds
     * @return
     */
    @Transactional
    @PostMapping("/updateMenus/{id}")
    @PreAuthorize("hasAuthority('system:role:menu')")
    public ResponseData updateMenus(@PathVariable(value = "id")Long id, @RequestBody Long[] menuIds){
        sysRoleMenuService.remove(new QueryWrapper<SysRoleMenu>().eq("role_id",id));
        List<SysRoleMenu> sysRoleMenuList=new ArrayList<>();
        Arrays.stream(menuIds).forEach(menuId->{
            SysRoleMenu roleMenu=new SysRoleMenu();
            roleMenu.setRoleId(id);
            roleMenu.setMenuId(menuId);
            sysRoleMenuList.add(roleMenu);
        });
        sysRoleMenuService.saveBatch(sysRoleMenuList);
        return new ResponseData("操作成功",200);
    }

    /**
     * 删除
     * @param ids
     * @return
     */
    @Transactional
    @PostMapping("/delete")
    @PreAuthorize("hasAuthority('system:role:delete')")
    public ResponseData delete(@RequestBody Long[] ids){
        sysRoleService.removeByIds(Arrays.asList(ids));
        sysUserRoleService.remove(new QueryWrapper<SysUserRole>().in("role_id",ids));
        return new ResponseData("操作成功",200);
    }

    /**
     * 添加或者修改
     * @param sysRole
     * @return
     */
    @PostMapping("/save")
    @PreAuthorize("hasAuthority('system:role:add')"+"||"+"hasAuthority('system:role:edit')")
    public ResponseData save(@RequestBody SysRole sysRole){
        if(sysRole.getId()==null || sysRole.getId()==-1){
            sysRole.setCreateTime(new Date());
            sysRole.setId(null);//自增
            sysRoleService.save(sysRole);
        }else{
            sysRole.setUpdateTime(new Date());
            sysRoleService.updateById(sysRole);
        }
        return new ResponseData("操作成功",200);
    }

    /**
     * 根据id查询
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    @PreAuthorize("hasAuthority('system:role:query')")
    public ResponseData findById(@PathVariable(value = "id")Integer id){
        SysRole sysRole = sysRoleService.getById(id);
        Map<String,Object> map=new HashMap<>();
        map.put("sysRole",sysRole);
        return new ResponseData(map);
    }



    /**
     * 根据条件分页查询角色信息
     * @param pageBean
     * @return
     */
    @PostMapping("/list")
    @PreAuthorize("hasAuthority('system:role:query')")
    public ResponseData list(@RequestBody PageBean pageBean){
        String query=pageBean.getQuery().trim();
        Page<SysRole> pageResult = sysRoleService.page(new Page<>(pageBean.getPageNum(), pageBean.getPageSize())
                ,new QueryWrapper<SysRole>().like(StringUtil.isNotEmpty(query),"name",query));
        List<SysRole> roleList = pageResult.getRecords();

        Map<String,Object> resultMap=new HashMap<>();
        resultMap.put("roleList",roleList);
        resultMap.put("total",pageResult.getTotal());
        return new ResponseData("请求成功!",200,resultMap);
    }


    @GetMapping("/listAll")
    @PreAuthorize("hasAuthority('system:role:query')")
    public ResponseData listAll(){
        Map<String,Object> resultMap=new HashMap<>();
        List<SysRole> roleList = sysRoleService.list();
        resultMap.put("roleList",roleList);
        return new ResponseData(resultMap);
    }
}

SysMenuController
package com.xuguoguo.contorller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xuguoguo.common.ResponseData;
import com.xuguoguo.common.Result;
import com.xuguoguo.entity.SysMenu;
import com.xuguoguo.service.SysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 @Package: com.xuguoguo.contorller
 @ClassName: SysMenuController
 @Author: XuGuoGuo
 @CreateTime: 2023/12/19-22:52
 @Description:
 */
@RestController
@RequestMapping("/sys/menu")
public class SysMenuController {

    @Autowired
    private SysMenuService sysMenuService;

    /**
     * 查询所有菜单树信息
     * @return
     */
    @RequestMapping("/treeList")
    @PreAuthorize("hasAuthority('system:menu:query')")
    public Result treeList(){
        List<SysMenu> menuList = sysMenuService.list(new QueryWrapper<SysMenu>().orderByAsc("order_num"));
        return new Result().put("treeMenu",sysMenuService.buildTreeMenu(menuList));
    }

}

前端的视图组件代码:
各组件的详细代码如下:
sys/role/index.vue
<template>
  <div class="app-container">

    <el-row :gutter="20" class="header">
      <el-col :span="7">
        <el-input placeholder="请输入角色名..." v-model="queryForm.query" clearable ></el-input>
      </el-col>
      <el-button type="primary" :icon="Search" @click="initRoleList">搜索</el-button>
      <el-button type="success" :icon="DocumentAdd" @click="handleDialogValue()">新增</el-button>
      <el-popconfirm title="您确定批量删除这些记录吗?" @confirm="handleDelete(null)">
        <template #reference>
         <el-button type="danger" :disabled="delBtnStatus" :icon="Delete" >批量删除</el-button>
        </template>
       </el-popconfirm>
    </el-row>

    <el-table :data="tableData" stripe style="width: 100%" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" />
        <el-table-column prop="name" label="角色名"  width="100" align="center"/>
        <el-table-column prop="code" label="权限字符" width="200" align="center"/>
        <el-table-column prop="createTime" label="创建时间" width="200" align="center"/>
        <el-table-column prop="remark" label="备注"  />
        <el-table-column prop="action" label="操作" width="400" fixed="right" align="center">
        <template v-slot="scope" >
          <el-button  type="primary" :icon="Tools" @click="handleMenuDialogValue(scope.row.id)">分配权限</el-button>
          <el-button v-if="scope.row.code!='admin'" type="primary" :icon="Edit" @click="handleDialogValue(scope.row.id)" />
          <el-popconfirm  v-if="scope.row.code!='admin'" title="您确定要删除这条记录吗?" @confirm="handleDelete(scope.row.id)">
            <template #reference>
              <el-button  type="danger" :icon="Delete" />
            </template>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
        v-model:currentPage="queryForm.pageNum"
        v-model:page-size="queryForm.pageSize"
        :page-sizes="[5, 10, 15, 20]"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
    />
  </div>
  <Dialog v-model="dialogVisible" :dialogVisible="dialogVisible" :id="id" :dialogTitle="dialogTitle" @initRoleList="initRoleList"/>
  <MenuDialog v-model="menuDialogVisible"  :menuDialogVisible="menuDialogVisible" :id="id" @initRoleList="initRoleList"></MenuDialog>
</template>

<script setup>
import {ref} from 'vue';
import requestUtil,{getServerUrl} from "@/util/request";
import { Search ,Delete,DocumentAdd ,Edit, Tools, RefreshRight} from '@element-plus/icons-vue'
import Dialog from './components/dialog'
import { ElMessage, ElMessageBox } from 'element-plus'
import MenuDialog from './components/menuDialog'

const tableData=ref([]);

const total=ref(0);

const queryForm=ref({
  query:'',
  pageNum:1,
  pageSize:10
})

const dialogVisible=ref(false);

const dialogTitle=ref("");

const id=ref(-1);

const delBtnStatus=ref(true);

const multipleSelection=ref([]);

const sysRoleList=ref([]);

const menuDialogVisible=ref(false);

const handleSelectionChange=(selection)=>{
  console.log("勾选了");
  console.log(selection);
  multipleSelection.value=selection;
  delBtnStatus.value=selection.length==0;
}

const handleMenuDialogValue=(roleId)=>{
  console.log("roleId="+roleId);
  id.value=roleId;
  menuDialogVisible.value=true;
}

const initRoleList=async()=>{
  const res=await requestUtil.post("sys/role/list",queryForm.value);
  tableData.value=res.data.data.roleList;
  total.value=res.data.data.total;
}

initRoleList();

const handleSizeChange=(pageSize)=>{
  queryForm.value.pageNum=1;
  queryForm.value.pageSize=pageSize;
  initRoleList();
}

const handleCurrentChange=(pageNum)=>{
  queryForm.value.pageNum=pageNum;
  initRoleList();
}

const handleDialogValue=(roleId)=>{
  if(roleId){
    id.value=roleId;
    dialogTitle.value="角色修改";
  }else{
    id.value=-1;
    dialogTitle.value="角色添加";
  }
  dialogVisible.value=true;
}

const handleDelete=async (id)=>{
  var ids = [];
  if(id){
    ids.push(id);
  }else{
    multipleSelection.value.forEach(row=>{
      ids.push(row.id)
    })
  }
  const res=await requestUtil.post("sys/role/delete",ids);
  if(res.data.code==200){
    ElMessage({
      type: 'success',
      message: '执行成功!'
    })
    initRoleList();
  }else{
    ElMessage({
      type: 'error',
      message: res.data.msg,
    })
  }
}

const handleResetPassword=async (id)=>{
  const res=await requestUtil.get("sys/role/resetPassword/"+id)
  if(res.data.code==200){
    ElMessage({
      type: 'success',
      message: '执行成功!'
    })
    initRoleList();
  }else{
    ElMessage({
      type: 'error',
      message: res.data.msg,
    })
  }
}

const statusChangeHandle=async (row)=>{
  let res=await requestUtil.get("sys/role/updateStatus/"+row.id+"/status/"+row.status);
  if(res.data.code==200){
    ElMessage({
      type: 'success',
      message: '执行成功!'
    })
  }else{
    ElMessage({
      type: 'error',
      message: res.data.msg,
    })
    initRoleList();
  }
}

</script>

<style lang="scss" scoped>

.header{
  padding-bottom: 16px;
  box-sizing: border-box;
}

.el-pagination{
  float: right;
  padding: 20px;
  box-sizing: border-box;
}

::v-deep th.el-table__cell{
  word-break: break-word;
  background-color: #f8f8f9 !important;
  color: #515a6e;
  height: 40px;
  font-size: 13px;

}

.el-tag--small {
  margin-left: 5px;
}
</style>

sys/role/components/dialog.vue
<template>

  <el-dialog
    v-model="dialogVisible"
    :title="dialogTitle"
    width="30%"
    @close="handleClose"
  >
       <el-form
        ref="formRef"
        :model="form"
        :rules="rules"
        label-width="100px"
    >
      <el-form-item label="角色名称" prop="name">
        <el-input v-model="form.name"  />
      </el-form-item>

      <el-form-item label="权限字符" prop="code">
        <el-input v-model="form.code" />
      </el-form-item>


      <el-form-item label="备注" prop="remark">
        <el-input v-model="form.remark" type="textarea" :rows="4"/>
      </el-form-item>


    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button type="primary" @click="handleConfirm">确认</el-button>
        <el-button @click="handleClose"
          >取消</el-button
        >
      </span>
    </template>
  </el-dialog>

</template>

<script setup>
import {defineEmits, defineProps,ref,watch } from "vue"
import requestUtil,{getServerUrl} from "@/util/request";
import { ElMessage } from 'element-plus'

const props=defineProps(
    {
      id:{
        type:Number,
        default:-1,
        required:true
      },
      dialogTitle:{
        type:String,
        default:'',
        required:true
      },
      dialogVisible:{
        type:Boolean,
        default:false,
        required:true
      }
    }
)

const dialogVisible=ref(false);

const form=ref({
  id:-1,
  name:"",
  code:"",
  remark:""
})




const rules=ref({
  name:[
    { required: true, message: '请输入角色名称'}
  ],
  code:[
    { required: true, message: '请输入权限字符'}
  ],
})

const formRef=ref(null)

const initFormData=async(id)=>{
  const res=await requestUtil.get("sys/role/"+id);
  form.value=res.data.data.sysRole;
}

watch(
    ()=>props.dialogVisible,
    ()=>{
      let id=props.id;
      console.log("id="+id)
      if(id!=-1){
        initFormData(id);
      }else{
        form.value={
          id:-1,
          name:"",
          code:"",
          remark:""
        }
      }
    }
)

const emits=defineEmits(['update:modelValue','initRoleList'])

const handleClose=()=>{
  emits('update:modelValue',false)
}

const handleConfirm=()=>{
  formRef.value.validate(async(valid)=>{
    if(valid){
      let result=await requestUtil.post("sys/role/save",form.value);
      let data=result.data;
      if(data.code==200){
        ElMessage.success("执行成功!")
        formRef.value.resetFields();
        emits("initRoleList")
        handleClose();
      }else{
        ElMessage.error(data.msg);
      }
    }else{
      console.log("fail")
    }
  })
}

</script>

<style lang="scss" scoped>

</style>

sys/role/components/menuDialog.vue
<template>
  <el-dialog
    model-value="menuDialogVisible"
    title="分配权限"
    width="30%"
    @close="handleClose"
  >

    <el-form
        ref="formRef"
        :model="form"
        label-width="100px"
    >

      <el-tree
          ref="treeRef"
          :data="treeData"
          :props="defaultProps"
          show-checkbox
          :default-expand-all=true
          node-key="id"
          :check-strictly=true
      />

    </el-form>

    <template #footer>
      <span class="dialog-footer">
        <el-button type="primary" @click="handleConfirm">确认</el-button>
        <el-button  @click="handleClose">取消</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<script setup>

import {defineEmits, defineProps, ref, watch} from "vue";
import requestUtil,{getServerUrl} from "@/util/request";
import { ElMessage } from 'element-plus'

const defaultProps = {
  children: 'children',
  label: 'name'
}
const props=defineProps(
    {
      id:{
        type:Number,
        default:-1,
        required:true
      },
      menuDialogVisible:{
        type:Boolean,
        default:false,
        required:true
      }
    }
)
const treeRef=ref(null);
const treeData=ref([]);
const form=ref({
  id:-1
})
const formRef=ref(null);
const initFormData=async(id)=>{
  const res=await requestUtil.get("sys/menu/treeList");
  treeData.value=res.data.treeMenu;
  form.value.id=id;

  const res2=await requestUtil.get("sys/role/menus/"+id);
  treeRef.value.setCheckedKeys(res2.data.menuIdList);
}


  watch(
      ()=>props.menuDialogVisible,
      ()=>{
        let id=props.id;
        console.log("id="+id);
        if(id!=-1){
          initFormData(id);
        }
      }
  )


  const emits=defineEmits(['update:modelValue','initRoleList']);
  const handleClose=()=>{
    emits('update:modelValue',false);
  }

  const handleConfirm=()=>{
    formRef.value.validate(async(valid)=>{
      if(valid){
          var menuIds=treeRef.value.getCheckedKeys();
          let result=await requestUtil.post("sys/role/updateMenus/"+form.value.id,menuIds);
          let data=result.data;
          if(data.code==200){
            ElMessage.success("执行成功!");
            emits("initRoleList");
            handleClose();;
          }else{
            ElMessage.error(data.msg);
          }
      }else{
        console.log("fail");
      }
    })
  }

</script>

<style scoped>

</style>

菜单信息管理模块化操作

菜单管理【树形表格菜单列表显示】

后端的控制SysMenuController请求方法编写

在这里插入图片描述

前端页面的处理:

在这里插入图片描述
在这里插入图片描述

预览效果:

在这里插入图片描述

添加/修改权限菜单实现:

后端控制器的请求方法编写:

在这里插入图片描述

前端的组件编写:

在这里插入图片描述
在这里插入图片描述

预览效果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

删除菜单功能实现

后台控制器请求方法

在这里插入图片描述

前端页面组件处理:

在这里插入图片描述在这里插入图片描述

预览效果如下:

在这里插入图片描述

代码规整:

后台控制器SysMenuController如下:
SysMenuController
package com.xuguoguo.contorller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xuguoguo.common.ResponseData;
import com.xuguoguo.common.Result;
import com.xuguoguo.entity.SysMenu;
import com.xuguoguo.service.SysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 @Package: com.xuguoguo.contorller
 @ClassName: SysMenuController
 @Author: XuGuoGuo
 @CreateTime: 2023/12/19-22:52
 @Description:
 */
@RestController
@RequestMapping("/sys/menu")
public class SysMenuController {

    @Autowired
    private SysMenuService sysMenuService;

    /**
     * 添加或者修改
     * @param sysMenu
     * @return
     */
    @PostMapping("/save")
    @PreAuthorize("hasAuthority('system:menu:add')"+"||"+"hasAuthority('system:menu:edit')")
    public ResponseData save(@RequestBody SysMenu sysMenu){
        if(sysMenu.getId()==null || sysMenu.getId()==-1){
            sysMenu.setCreateTime(new Date());
            sysMenuService.save(sysMenu);
        }else{
            sysMenu.setUpdateTime(new Date());
            sysMenuService.updateById(sysMenu);
        }
        return new ResponseData("操作成功",200);
    }

    /**
     * 根据id查询
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    @PreAuthorize("hasAuthority('system:menu:query')")
    public ResponseData findById(@PathVariable(value = "id")Long id){
        SysMenu sysMenu = sysMenuService.getById(id);
        Map<String,Object> map=new HashMap<>();
        map.put("sysMenu",sysMenu);
        return new ResponseData(map);
    }

    /**
     * 删除
     * @param id
     * @return
     */
    @GetMapping("/delete/{id}")
    @PreAuthorize("hasAuthority('system:menu:delete')")
    public ResponseData delete(@PathVariable(value = "id")Long id){
        long count = sysMenuService.count(new QueryWrapper<SysMenu>().eq("parent_id", id));
        if(count>0){
            return new ResponseData("请先删除子菜单!",500);
        }
        sysMenuService.removeById(id);
        return new ResponseData("操作成功",200);
    }


    /**
     * 查询所有菜单树信息
     * @return
     */
    @RequestMapping("/treeList")
    @PreAuthorize("hasAuthority('system:menu:query')")
    public Result treeList(){
        List<SysMenu> menuList = sysMenuService.list(new QueryWrapper<SysMenu>().orderByAsc("order_num"));
        return new Result().put("treeMenu",sysMenuService.buildTreeMenu(menuList));
    }

}

前端页面组件代码:
sys/menu/index.vue
<template>
  <div class="app-container">
    <el-row  class="header">
      <el-button type="success" :icon="DocumentAdd" @click="handleDialogValue()">新增</el-button>
    </el-row>
     <el-table
          :data="tableData"
          row-key="id"
          stripe
          style="width: 100%; margin-bottom: 20px"
          border
          default-expand-all
          :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      >

        <el-table-column prop="name" label="菜单名称"  width="200"/>
        <el-table-column prop="icon" label="图标"  width="70" align="center">
          <template v-slot="scope">
            <el-icon><svg-icon :icon="scope.row.icon" /></el-icon>
          </template>
        </el-table-column>
        <el-table-column prop="orderNum" label="排序"  width="70" align="center"/>
        <el-table-column prop="perms" label="权限标识"  width="200" />
        <el-table-column prop="path" label="组件路径"  width="180" />
        <el-table-column prop="menuType" label="菜单类型"  width="120" align="center">
          <template v-slot="scope">
            <el-tag size="small" v-if="scope.row.menuType === 'M'" type="danger" effect="dark">目录</el-tag>
            <el-tag size="small" v-else-if="scope.row.menuType === 'C'" type="success" effect="dark">菜单</el-tag>
            <el-tag size="small" v-else-if="scope.row.menuType === 'F'" type="warning" effect="dark">按钮</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="createTime" label="创建时间" align="center"/>
        <el-table-column prop="action" label="操作" width="400" fixed="right" align="center">
        <template v-slot="scope" >
          <el-button  type="primary" :icon="Edit" @click="handleDialogValue(scope.row.id)" />
          <el-popconfirm  title="您确定要删除这条记录吗?" @confirm="handleDelete(scope.row.id)">
            <template #reference>
              <el-button  type="danger" :icon="Delete" />
            </template>
          </el-popconfirm>
        </template>
      </el-table-column>
      </el-table>

  </div>
  <Dialog v-model="dialogVisible" :tableData="tableData" :dialogVisible="dialogVisible" :id="id" :dialogTitle="dialogTitle" @initMenuList="initMenuList"/>

</template>

<script setup>
import {ref} from 'vue';
import requestUtil,{getServerUrl} from "@/util/request";
import { Search ,Delete,DocumentAdd ,Edit, Tools, RefreshRight} from '@element-plus/icons-vue'
import Dialog from './components/dialog'
import { ElMessage, ElMessageBox } from 'element-plus'

const tableData=ref([]);
const dialogVisible=ref(false);
const dialogTitle=ref("");
const id=ref(-1);

const initMenuList=async()=>{
  const res=await requestUtil.get("sys/menu/treeList");
  tableData.value=res.data.treeMenu;

}

initMenuList();

const handleDialogValue=(menuId)=>{
  if(menuId){
    id.value=menuId;
    dialogTitle.value="菜单修改";
  }else{
    id.value=-1;
    dialogTitle.value="菜单添加";
  }
  dialogVisible.value=true;
}

const handleDelete=async (id)=>{
  const res=await requestUtil.get("sys/menu/delete/"+id);
  if(res.data.code==200){
    ElMessage({
      type: 'success',
      message: '执行成功!'
    })
    initMenuList();
  }else{
    ElMessage({
      type: 'error',
      message: res.data.msg,
    })
  }
}

</script>

<style lang="scss" scoped>

.header{
  padding-bottom: 16px;
  box-sizing: border-box;
}

.el-pagination{
  float: right;
  padding: 20px;
  box-sizing: border-box;
}

::v-deep th.el-table__cell{
  word-break: break-word;
  background-color: #f8f8f9 !important;
  color: #515a6e;
  height: 40px;
  font-size: 13px;

}

.el-tag--small {
  margin-left: 5px;
}
</style>

sys/menu/components/dialog.vue
<template>
  <el-dialog
    model-value="dialogVisible"
    :title="dialogTitle"
    width="30%"
  @close="handleClose"
  >
    <el-form
        ref="formRef"
        :model="form"
        :rules="rules"
        label-width="100px"
    >
      <el-form-item label="上级菜单" prop="parentId">
        <el-select v-model="form.parentId" placeholder="请选择上级菜单" @change="$forceUpdate()">
          <template v-for="item in tableData" :key="item.id">
            <el-option :label="item.name" :value="item.id"></el-option>
            <template v-for="child in item.children" :key="child.id">
              <el-option :label="child.name" :value="child.id">
                <span>{{ "    -- " + child.name }}</span>
              </el-option>
            </template>
          </template>
        </el-select>
      </el-form-item>
      <el-form-item label="菜单类型" prop="menuType" label-width="100px">
     <el-radio-group v-model="form.menuType">
      <el-radio :label="'M'">目录</el-radio>
      <el-radio :label="'C'">菜单</el-radio>
      <el-radio :label="'F'">按钮</el-radio>
     </el-radio-group>
    </el-form-item>
      <el-form-item label="菜单图标" prop="icon">
        <el-input v-model="form.icon" />
      </el-form-item>
      <el-form-item label="菜单名称" prop="name">
        <el-input v-model="form.name" />
      </el-form-item>
      <el-form-item label="权限标识" prop="perms">
        <el-input v-model="form.perms" />
      </el-form-item>
      <el-form-item label="组件路径" prop="component">
        <el-input v-model="form.component" />
      </el-form-item>
      <el-form-item label="显示顺序" prop="orderNum" >
     <el-input-number v-model="form.orderNum" :min="1" label="显示顺序"></el-input-number>
    </el-form-item>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button type="primary" @click="handleConfirm">确认</el-button>
        <el-button  @click="handleClose">取消</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<script setup>

import {defineEmits, defineProps, ref, watch} from "vue";
import requestUtil,{getServerUrl} from "@/util/request";
import { ElMessage } from 'element-plus'

  const tableData=ref([])


  const props=defineProps(
      {
        id:{
          type:Number,
          default:-1,
          required:true
        },
        dialogTitle:{
          type:String,
          default:'',
          required:true
        },
        dialogVisible:{
          type:Boolean,
          default:false,
          required:true
        },
        tableData:{
          type:Array,
          default:[],
          required:true
        }
      }
  )


const form=ref({
  id:-1,
  parentId:'',
  menuType:"M",
  icon:'',
  name:'',
  perms:'',
  component:'',
  orderNum:1
})


const rules=ref({
  parentId:[
    { required: true, message: '请选择上级菜单'}
  ],
  name: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }]
})

const formRef=ref(null)

const initFormData=async(id)=>{
 const res=await requestUtil.get("sys/menu/"+id);
 form.value=res.data.data.sysMenu;
}



  watch(
      ()=>props.dialogVisible,
      ()=>{
        let id=props.id;
        tableData.value=props.tableData;
        if(id!=-1){
          initFormData(id)
        }else{
          form.value={
            id:-1,
            parentId:'',
            menuType:"M",
            icon:'',
            name:'',
            perms:'',
            component:'',
            orderNum:1
          }
        }
      }
  )


  const emits=defineEmits(['update:modelValue','initMenuList'])

  const handleClose=()=>{
    emits('update:modelValue',false)
  }

  const handleConfirm=()=>{
    formRef.value.validate(async(valid)=>{
      if(valid){
          let result=await requestUtil.post("sys/menu/save",form.value);
          let data=result.data;
          if(data.code==200){
            ElMessage.success("执行成功!")
            formRef.value.resetFields();
            emits("initMenuList")
            handleClose();
          }else{
            ElMessage.error(data.msg);
          }
      }else{
        console.log("fail")
      }
    })
  }

</script>

<style scoped>

</style>

小结

提示:本节也是本章内容的结束哦!其余功能大家可以按照自己的项目进行扩展即可,有不会或者想要实现的功能块可以留言评论都可,看到后会立马回复滴@许锅锅啊

本章的第十小节完毕,敬请期待后续更新(可留言需要学习哪方面的内容哈)!如果需要源码或者工具的朋友们可关注微信公众号"锅锅编程生活"或者扫描二维码关注回复关键字/后台留言获取即可!
在这里插入图片描述

  • 19
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值