vue3-pc-template后台管理之角色管理与功能权限配置实践

在开发企业级应用时,权限控制无疑是至关重要且不可或缺的一部分。合理的权限控制不仅能够有效保障系统的安全性,还能确保不同用户角色在系统中拥有合适的操作权限,从而提高系统的使用效率和稳定性。本文将详细介绍如何在 Vue3 项目中实现功能权限配置,为开发者提供一个可参考的实践方案。

实现步骤

1、后端返回的数据结构

在进行功能权限配置之前,我们首先需要了解后端返回的数据结构。这些数据将为前端的权限展示和处理提供基础。

 1.1该角色可分配的所有权限

后端返回的 funtionsData1 数据结构中,包含了系统中各个菜单及其对应的功能权限信息。具体如下:

export const funtionsData1 = [
    {
        "menuId": 10000,
        "menuName": "系统管理",
        "listPermission": null,
        "sonMenuButtonCustom": [
            {
                "menuId": 10100,
                "menuName": "组织架构",
                "listPermission": null,
                "sonMenuButtonCustom": [
                    {
                        "menuId": 10101,
                        "menuName": "公司管理",
                        "listPermission": [
                            {
                                "id": 8,
                                "name": "增加公司",
                                "uri": "POST/organizes",
                                "menuId": 10101
                            },
                            {
                                "id": 9,
                                "name": "删除公司",
                                "uri": "DELETE/organizes/batch",
                                "menuId": 10101
                            },
                            {
                                "id": 10,
                                "name": "修改公司",
                                "uri": "PUT/organizes/{id}",
                                "menuId": 10101
                            }
                        ],
                        "sonMenuButtonCustom": null
                    },
                    {
                        "menuId": 10102,
                        "menuName": "部门管理",
                        "listPermission": [
                            {
                                "id": 11,
                                "name": "增加部门",
                                "uri": "POST/departments",
                                "menuId": 10102
                            },
                            {
                                "id": 12,
                                "name": "删除部门",
                                "uri": "DELETE/departments/batch",
                                "menuId": 10102
                            },
                            {
                                "id": 13,
                                "name": "修改部门",
                                "uri": "PUT/departments/{id}",
                                "menuId": 10102
                            }
                        ],
                        "sonMenuButtonCustom": null
                    },
                    {
                        "menuId": 10103,
                        "menuName": "用户管理",
                        "listPermission": [
                            {
                                "id": 1,
                                "name": "增加用户",
                                "uri": "POST/users",
                                "menuId": 10103
                            },
                            {
                                "id": 2,
                                "name": "删除用户",
                                "uri": "DELETE/users/batch",
                                "menuId": 10103
                            },
                            {
                                "id": 3,
                                "name": "修改用户",
                                "uri": "PUT/users/{id}",
                                "menuId": 10103
                            },
                            {
                                "id": 31,
                                "name": "用户角色分配",
                                "uri": "POST/users/{id}/role",
                                "menuId": 10103
                            }
                        ],
                        "sonMenuButtonCustom": null
                    },
                    {
                        "menuId": 10104,
                        "menuName": "角色管理",
                        "listPermission": [
                            {
                                "id": 14,
                                "name": "增加角色",
                                "uri": "POST/roles",
                                "menuId": 10104
                            },
                            {
                                "id": 15,
                                "name": "删除角色",
                                "uri": "DELETE/roles/batch",
                                "menuId": 10104
                            },
                            {
                                "id": 16,
                                "name": "修改角色",
                                "uri": "PUT/roles/{id}",
                                "menuId": 10104
                            },
                            {
                                "id": 17,
                                "name": "角色菜单分配",
                                "uri": "POST/roles/{id}/menu",
                                "menuId": 10104
                            },
                            {
                                "id": 18,
                                "name": "角色功能按钮分配",
                                "uri": "POST/roles/{id}/permission",
                                "menuId": 10104
                            }
                        ],
                        "sonMenuButtonCustom": null
                    }
                ]
            },
            {
                "menuId": 10200,
                "menuName": "入库管理",
                "listPermission": [
                    {
                        "id": 4,
                        "name": "增加入库单",
                        "uri": "POST/regulations",
                        "menuId": 10200
                    },
                    {
                        "id": 5,
                        "name": "删除入库单",
                        "uri": "DELETE/regulations/batch",
                        "menuId": 10200
                    },
                    {
                        "id": 6,
                        "name": "上传入库附件",
                        "uri": "POST/regulations/uploadFile",
                        "menuId": 10200
                    },
                    {
                        "id": 7,
                        "name": "修改入库单",
                        "uri": "PUT/regulations/{id}",
                        "menuId": 10200
                    }
                ],
                "sonMenuButtonCustom": []
            },
            {
                "menuId": 10300,
                "menuName": "出库管理",
                "listPermission": [
                    {
                        "id": 19,
                        "name": "增加出库单",
                        "uri": "POST/meters",
                        "menuId": 10300
                    },
                    {
                        "id": 20,
                        "name": "删除出库单",
                        "uri": "DELETE/meters/batch",
                        "menuId": 10300
                    },
                    {
                        "id": 21,
                        "name": "修改出库单",
                        "uri": "PUT/meters/{id}",
                        "menuId": 10300
                    },
                    {
                        "id": 22,
                        "name": "上传出库单附件",
                        "uri": "POST/meters/uploadFile",
                        "menuId": 10300
                    },
                    {
                        "id": 23,
                        "name": "记录溯源信息",
                        "uri": "POST/meters/source",
                        "menuId": 10300
                    },
                    {
                        "id": 24,
                        "name": "删除溯源信息",
                        "uri": "DELETE/meters/source/{id}",
                        "menuId": 10300
                    }
                ],
                "sonMenuButtonCustom": []
            },
            {
                "menuId": 10400,
                "menuName": "固定资产管理",
                "listPermission": [
                    {
                        "id": 25,
                        "name": "增加固定资产",
                        "uri": "POST/substances",
                        "menuId": 10400
                    },
                    {
                        "id": 26,
                        "name": "删除固定资产",
                        "uri": "DELETE/substances/batch",
                        "menuId": 10400
                    },
                    {
                        "id": 27,
                        "name": "修改固定资产",
                        "uri": "PUT/substances/{id}",
                        "menuId": 10400
                    },
                    {
                        "id": 28,
                        "name": "上传固定资产附件",
                        "uri": "POST/substances/uploadFile",
                        "menuId": 10400
                    },
                    {
                        "id": 29,
                        "name": "记录溯源信息",
                        "uri": "POST/substances/source",
                        "menuId": 10400
                    },
                    {
                        "id": 30,
                        "name": "删除溯源信息",
                        "uri": "DELETE/substances/source/{id}",
                        "menuId": 10400
                    }
                ],
                "sonMenuButtonCustom": []
            },
            {
                "menuId": 10500,
                "menuName": "日志管理",
                "listPermission": null,
                "sonMenuButtonCustom": []
            }
        ]
    },
    {
        "menuId": 20000,
        "menuName": "财务管理",
        "listPermission": null,
        "sonMenuButtonCustom": [
            {
                "menuId": 20300,
                "menuName": "对账单",
                "listPermission": [
                    {
                        "id": 32,
                        "name": "增加对账单",
                        "uri": "POST/calibrationLists",
                        "menuId": 20300
                    },
                    {
                        "id": 33,
                        "name": "删除对账单",
                        "uri": "DELETE/calibrationLists/batch",
                        "menuId": 20300
                    }
                ],
                "sonMenuButtonCustom": []
            }
        ]
    },
    {
        "menuId": 30000,
        "menuName": "报价管理",
        "listPermission": null,
        "sonMenuButtonCustom": [
            {
                "menuId": 30300,
                "menuName": "报价单",
                "listPermission": [
                    {
                        "id": 323,
                        "name": "增加报价单",
                        "uri": "POST/calibrationLists",
                        "menuId": 20300
                    },
                    {
                        "id": 333,
                        "name": "删除报价单",
                        "uri": "DELETE/calibrationLists/batch",
                        "menuId": 20300
                    }
                ],
                "sonMenuButtonCustom": []
            },
            {
                "menuId": 30400,
                "menuName": "委托服务管理",
                "sonMenuButtonCustom": [
                    {
                        "menuId": 304000,
                        "menuName": "委托单",
                        "sonMenuButtonCustom": [
                        ],
                        "listPermission": [
                            {
                                "id": 3233,
                                "name": "增加委托单",
                                "uri": "POST/calibrationLists",
                                "menuId": 203000
                            },
                            {
                                "id": 3333,
                                "name": "删除委托单",
                                "uri": "DELETE/calibrationLists/batch",
                                "menuId": 203000
                            }
                        ],


                    },
                    {
                        "menuId": 304001,
                        "menuName": "下厂单",
                        "sonMenuButtonCustom": [
                        ],
                        "listPermission": [
                            {
                                "id": 32333,
                                "name": "增加下厂单",
                                "uri": "POST/calibrationLists",
                                "menuId": 2030003
                            },
                            {
                                "id": 33333,
                                "name": "删除下厂单",
                                "uri": "DELETE/calibrationLists/batch",
                                "menuId": 2030003
                            }
                        ],


                    }
                ]
            }
        ]
    }
]

该数据结构以树状形式呈现,每个菜单节点包含 menuId(菜单 ID)、menuName(菜单名称)、listPermission(当前菜单的功能权限列表)以及 sonMenuButtonCustom(子菜单及其功能权限)等信息。 

1.2该角色已经分配的权限id

rolePermissionData 数组中记录了当前角色已经分配的权限 ID。通过这些 ID,前端可以判断哪些功能权限是当前角色所拥有的。 

export const rolePermissionData = [
    32,
    8,
    9,
    10,
    11,
    12,
    13,
    1,
    2,
    3,
    31,
    14,
    15,
    16,
    17,
    18,
    6,
    19,
    20,
    21,
    25,
    26,
    27,
    28
]

2、 封装功能权限弹窗组件

为了更好地管理和展示功能权限配置,我们将功能权限弹窗相关逻辑封装成组件。

2.1 CustomFunctionsDialog.vue

CustomFunctionsDialog.vue 组件用于展示功能权限配置的弹窗界面。具体代码如下:

<template>
  <el-dialog title="功能权限" width="1000" center destroy-on-close>
    <div>
      <div>角色名称:jiaberr</div>
      <div>
        <text>功能权限:</text>
        <el-checkbox v-model="checkAll" @change="handleCheckAllChange">
          全选/全不选
        </el-checkbox>
      </div>
      <div class="w-p-100 containner">
        <nested-menu :data="funtionsData" :checkedData="checkedData" />
      </div>
    </div>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="close">取消</el-button>
        <el-button type="primary" @click="handleSubmit"> 确定 </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup>
import { ref, provide, watchEffect } from "vue";
import {
  funtionsData1,
  funtionsData2,
  rolePermissionData,
} from "./simulatedData.js";
import NestedMenu from "./NestedMenu.vue"; // 确保正确导入NestedMenu组件

const props = defineProps({
  roleId: {
    Type: Number,
    required: true,
  },
});

const checkAll = ref(false);
const funtionsData = ref();
watchEffect(() => {

  // 仅模拟页面效果使用,真实项目funtionsData需根据id获取后台数据
  if (props.roleId == 1) {
    funtionsData.value = funtionsData1;
  } else {
    funtionsData.value = funtionsData2;
  }
});

const emits = defineEmits(["close"]);
const close = () => {
  emits("close");
};
const checkedData = ref(rolePermissionData);
const handleCheckAllChange = (val) => {
  checkedData.value = val ? permissionIds : [];
  console.log(checkedData.value);
};
// provide('checkedData', checkedData.value);
const handleCheckData = (id) => {
  let index = checkedData.value.findIndex((val) => val == id);
  if (index != -1) {
    checkedData.value.splice(index, 1);
  } else {
    checkedData.value.push(id);
  }
};
provide("handleEvent", handleCheckData);

// 提交
const handleSubmit = () => {
  // 将选中的id数组上传至后台接口
  console.log(checkedData.value);

  emits("close");
};

// 收集所有功能权限的id
const extractPermissionIds = (data) => {
  const ids = [];

  // 递归遍历函数
  function traverse(node) {
    if (node.listPermission && Array.isArray(node.listPermission)) {
      // 将 listPermission 中的 id 添加到 ids 数组
      node.listPermission.forEach((permission) => {
        ids.push(permission.id);
      });
    }

    // 如果有子节点,继续递归遍历
    if (node.sonMenuButtonCustom && Array.isArray(node.sonMenuButtonCustom)) {
      node.sonMenuButtonCustom.forEach((child) => traverse(child));
    }
  }

  // 遍历根节点
  data.forEach((item) => traverse(item));

  return ids;
};
const permissionIds = extractPermissionIds(funtionsData.value);
</script>

<style lang="scss" scoped>
.containner {
  border-top: 1px solid #d3d3d3;
  border-right: 1px solid #d3d3d3;
  border-bottom: 1px solid #d3d3d3;
}
</style>

该组件通过接收 roleId 来获取对应的权限数据,并提供了全选、单选以及提交功能权限配置的功能。 

2.2 NestedMenu.vue 

由于后台返回的数据层级关系较为复杂,为了更方便地处理权限分配的展示,我们将权限展示部分单独抽离成 NestedMenu.vue 组件。该组件可以实现循环嵌套,以展示不同层级的菜单和权限。

<template>
  <div class="flex1 border-left">
    <div
      v-for="(item, index) in data"
      :key="item.menuId + index"
      class="flex align-center"
      :class="index == data.length - 1 ? '' : 'border-bottom'"
    >
      <div class="menuName text-center">{{ item.menuName }}</div>
      <nested-menu
        v-if="item.sonMenuButtonCustom && item.sonMenuButtonCustom.length"
        :data="item.sonMenuButtonCustom"
        :checked-data="checkedData"
      />
      <div
        v-else
        class="flex flex-wrap flex1 border-left pl-10 pt-5 pr-10 pb-5 min-height"
      >
        <el-checkbox
          v-for="(ite, idx) in item.listPermission"
          :key="ite.id || idx"
          :model-value="isChecked(ite.id)"
          @change="handleChange(ite.id)"
        >
          {{ ite.name }}
        </el-checkbox>
      </div>
    </div>
  </div>
</template>
  
  <script setup>
import { inject } from "vue";
const handleEvent = inject("handleEvent");
const props = defineProps({
  data: Array,
  checkedData: Array,
});

// 判断是否选中
const isChecked = (id) => {
  return props.checkedData.includes(id);
};

// 调用父组件的方法,修改checkedData
const handleChange = (id) => {
  handleEvent(id);
};
</script>
  <style scoped>
.border-bottom {
  border-bottom: 1px solid #d3d3d3;
}

.border-left {
  border-left: 1px solid #d3d3d3;
}

.menuName {
  width: 110px;
}
.min-height {
  min-height: 40px;
}
</style>
  

该组件通过接收父组件传递的权限数据和已选中的权限数据,动态展示菜单和权限的勾选状态,并在权限勾选状态发生变化时通知父组件。 

3、在角色管理页面中使用

我们在角色管理页面 role.vue 中引入上述封装的组件,以实现功能权限配置的具体应用。

3.1 role.vue
<template>
  <div>
    <CustomSearch
      class="mb-20"
      :searchConfig="roleSearchConfig"
      @updateQueryData="updateQueryData"
    ></CustomSearch>
    <CustomTable
      :tableConfig="roleTableConfig"
      :tableData="roleData"
      :total="total"
      @updateQueryData="updateQueryData"
    >
    <template #handle="row">
     <el-button text type="success" size="small">编辑</el-button>
     <el-button text type="danger" size="small">删除</el-button>
     <el-button text type="primary" size="small">菜单权限</el-button>
     <el-button text type="primary" size="small" @click="handleFunctionalAuthority(row.row.id)">功能权限</el-button>
    </template>
  </CustomTable>
  </div>
  <CustomFunctionsDialog v-model="functionsDialogVisible" @close = "functionsDialogVisible = false" :roleId="roleId"></CustomFunctionsDialog>
</template>

<script setup>
import CustomTable from "@/components/CustomTable/index.vue";
import CustomSearch from "@/components/CustomSearch/index.vue";
import CustomFunctionsDialog from "./CustomFunctionsDialog.vue"
import { roleTableConfig } from "./tableConfig.js";
import { roleSearchConfig } from "./searchConfig.js";
import { roleData } from "./simulatedData.js";
import { ref } from "vue";

const total = ref(0);

const updateQueryData = (params, bool) => {};

// 打开功能权限弹窗
const roleId = ref() // 根据不同的角色id获取不同的权限按钮
const functionsDialogVisible = ref(false)
const handleFunctionalAuthority = (id) => {
  roleId.value = id
  functionsDialogVisible.value = true
}


</script>

<style lang="scss" scoped>
</style>

在 role.vue 页面中,通过点击 “功能权限” 按钮,可以打开功能权限配置弹窗,并根据不同的角色 ID 获取相应的权限数据进行展示和配置。 

4. 总结

通过上述步骤,我们在Vue3项目中实现了基本的功能权限配置。这种权限控制方式不仅提高了系统的安全性,还使得代码更加模块化和易于维护。在实际应用中,可以根据具体需求进一步完善和扩展权限管理系统。

完整代码实现请参考开源项目:vue3-pc-template

欢迎 Star 和 Fork 项目,一起构建更完善的权限管理体系!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jiaberrrr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值