grant.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. <script lang="ts" setup>
  2. import type { Recordable } from '@vben/types';
  3. import type { RelationRequest } from '#/api/model';
  4. import { onMounted, reactive, ref, unref } from 'vue';
  5. import { useVbenDrawer } from '@vben/common-ui';
  6. import { Button, message, Tree, type TreeProps } from 'ant-design-vue';
  7. import { MenuApi, RoleApi, TenantApi } from '#/api';
  8. import { Icon } from '#/components/icon';
  9. import { getLeafNodeIds } from '#/utils';
  10. defineOptions({
  11. name: 'MenuGrant',
  12. });
  13. const emit = defineEmits(['success']);
  14. const modelRef = ref<Recordable<any>>({});
  15. const state = reactive<{
  16. checkedKeys: number[] | string[];
  17. expandedKeys: number[] | string[];
  18. lastLeafKeys: number[] | string[];
  19. selectedKeys: number[] | string[];
  20. }>({
  21. selectedKeys: [],
  22. expandedKeys: [],
  23. checkedKeys: [],
  24. lastLeafKeys: [],
  25. });
  26. const treeData = ref<TreeProps['treeData']>([]);
  27. const isExpand = ref(false);
  28. // 所有节点key
  29. const allNodeIds = ref([]);
  30. // 当前展开的key
  31. const currentExpandedKeys = ref([]);
  32. const getRoleDetailData = async () => {
  33. const data =
  34. modelRef.value.type === 'tenant'
  35. ? await TenantApi.getMenuIds(unref(modelRef).id)
  36. : await RoleApi.getMenuIds(unref(modelRef).id);
  37. state.checkedKeys = data || [];
  38. state.expandedKeys = data || [];
  39. state.selectedKeys = data.filter((item: number | string) => {
  40. return state.lastLeafKeys.includes(item as never);
  41. });
  42. };
  43. const [Drawer, { close, setState, getData }] = useVbenDrawer({
  44. onConfirm: async () => {
  45. try {
  46. setState({ confirmLoading: true });
  47. const postData: RelationRequest = {
  48. id: unref(modelRef).id,
  49. relationIds: state.checkedKeys,
  50. };
  51. modelRef.value.type === 'tenant'
  52. ? await TenantApi.updateGrant(postData)
  53. : await RoleApi.updateGrant(postData);
  54. message.success('操作成功');
  55. close();
  56. emit('success');
  57. } catch {
  58. message.error('操作失败');
  59. } finally {
  60. setState({ confirmLoading: false });
  61. }
  62. },
  63. onOpenChange: async (isOpen: boolean) => {
  64. if (isOpen) {
  65. setState({ loading: true });
  66. const data = getData<Recordable<any>>();
  67. modelRef.value = { ...data.baseData };
  68. await getRoleDetailData();
  69. setState({ loading: false });
  70. }
  71. },
  72. });
  73. const fetch = async () => {
  74. treeData.value = (await MenuApi.getList(
  75. {},
  76. )) as unknown as TreeProps['treeData'];
  77. state.lastLeafKeys = getLeafNodeIds(unref(treeData));
  78. };
  79. onMounted(async () => {
  80. await fetch();
  81. });
  82. /**
  83. * 点击复选框触发处理
  84. * @param mCheckedKeys
  85. */
  86. const handleCheck = (mCheckedKeys: any, e: any) => {
  87. state.selectedKeys = mCheckedKeys;
  88. state.checkedKeys = [...mCheckedKeys, ...e.halfCheckedKeys];
  89. };
  90. const handleExpand = (expandedKeys: any) => {
  91. state.expandedKeys = expandedKeys;
  92. };
  93. // 展开折叠按钮事件
  94. const handleExpandAndCollapse = () => {
  95. isExpand.value = !isExpand.value;
  96. currentExpandedKeys.value = isExpand.value ? allNodeIds.value : [];
  97. };
  98. </script>
  99. <template>
  100. <Drawer class="w-[1000px]" title="授权菜单">
  101. <Button type="primary" @click="handleExpandAndCollapse">
  102. {{ isExpand ? '折叠' : '展开' }}
  103. </Button>
  104. <Tree
  105. v-model:checked-keys="state.selectedKeys"
  106. :block-node="true"
  107. :checkable="true"
  108. :default-expand-all="true"
  109. :expanded-keys="state.expandedKeys"
  110. :field-names="{
  111. title: 'title',
  112. key: 'id',
  113. }"
  114. :tree-data="treeData"
  115. @check="handleCheck"
  116. @expand="handleExpand"
  117. >
  118. <template #title="{ meta }">
  119. <div class="flex items-center">
  120. <Icon v-if="meta.icon" :icon="meta.icon" class="mr-1" />
  121. <span>{{ meta.title }}</span>
  122. </div>
  123. </template>
  124. </Tree>
  125. </Drawer>
  126. </template>