index.vue 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. <template>
  2. <div class="p-base full">
  3. <div class="flex direction-column p-t-base p-b-base p-l-large fill-blank">
  4. <div class="flex items-center">
  5. <span class="m-r-base">角色</span>
  6. <base-select v-model="role" :options="ROLE_OPTION"></base-select>
  7. <el-button class="m-l-base" type="primary" :loading="loading" @click="onSubmit">保存</el-button>
  8. </div>
  9. <div class="flex-1 p-base m-t-large fill-lighter full-scroll-y-auto privilege-tree">
  10. <el-tree ref="treeRef" show-checkbox node-key="index" :data="menuTree || []" @check-change="onCheckChange">
  11. </el-tree>
  12. </div>
  13. </div>
  14. </div>
  15. </template>
  16. <script setup lang="ts" name="RoleSetting">
  17. /** 角色权限管理 */
  18. import { computed, nextTick, ref, watch } from 'vue'
  19. import { ElButton, ElTree, ElMessage } from 'element-plus'
  20. import { ROLE_OPTION } from '@/constants/dicts'
  21. import useFetch from '@/hooks/useFetch'
  22. import useMainLayoutStore from '@/store/layout'
  23. import BaseSelect from '@/components/element/BaseSelect.vue'
  24. import type { ExtractApiResponse } from '@/api/api'
  25. type MenuItem = MainLayoutStore.MenuItem
  26. type MenuItemWithId = MenuItem & { id: number }
  27. const props = defineProps<{ role: ROLE }>()
  28. const mainLayoutStore = useMainLayoutStore()
  29. const role = ref<ROLE>(props.role)
  30. const treeRef = ref<InstanceType<typeof ElTree>>()
  31. const checkedMenus = ref<MenuItemWithId[]>([])
  32. const { fetch: getPrivilege, result: privilege } = useFetch('getRolePrivilege')
  33. const { fetch: setPrivilege, loading } = useFetch('setRolePrivilege')
  34. watch(
  35. role,
  36. () => {
  37. role.value && getPrivilege({ role: role.value })
  38. },
  39. { immediate: true }
  40. )
  41. watch(privilege, () => {
  42. nextTick(() => {
  43. treeRef?.value?.setCheckedKeys(privilege?.value?.filter((d) => d.hasPrivilege)?.map((d) => d.code))
  44. })
  45. })
  46. function filterPrivilege(
  47. item: MenuItem,
  48. privilege: ExtractApiResponse<'getRolePrivilege'>
  49. ): MenuItemWithId | undefined {
  50. const privilegeItem = privilege.find((d) => item.index === d.code)
  51. if (privilegeItem) {
  52. return {
  53. ...item,
  54. id: privilegeItem.id,
  55. children: item.children?.map((child) => filterPrivilege(child, privilege)).filter((d) => !!d) as MenuItemWithId[],
  56. }
  57. }
  58. }
  59. const menuTree = computed(() => {
  60. return mainLayoutStore.menuList?.reduce((menus, menu) => {
  61. return menus.concat(filterPrivilege(menu, privilege.value || []) || [])
  62. }, [] as MenuItem[])
  63. })
  64. const onCheckChange = () => {
  65. checkedMenus.value = (treeRef?.value?.getCheckedNodes() as MenuItemWithId[]) || []
  66. }
  67. /** 保存 */
  68. const onSubmit = async () => {
  69. try {
  70. const checkedNodes = treeRef?.value?.getCheckedNodes() || []
  71. const checkedHalfNodes = treeRef?.value?.getHalfCheckedNodes() || []
  72. const privilegeIds = checkedNodes.concat(checkedHalfNodes).map((d) => d.id)
  73. await setPrivilege({ role: role.value, privilegeIds })
  74. ElMessage.success('保存成功')
  75. } catch (error) {
  76. console.error(error)
  77. }
  78. }
  79. </script>
  80. <style scoped lang="scss">
  81. .privilege-tree {
  82. width: 660px;
  83. min-height: 320px;
  84. }
  85. </style>