PagePermission.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. <template>
  2. <div class="page-permission">
  3. <el-row :gutter="12">
  4. <!-- 左侧权限树 -->
  5. <el-col :span="6">
  6. <el-card shadow="hover">
  7. <template #header>
  8. <el-space>
  9. <el-button type="primary" icon-placement="left" @click="openCreateDrawer">
  10. 添加权限
  11. <template #icon>
  12. <div class="flex items-center">
  13. <el-icon size="14">
  14. <FileAddOutlined />
  15. </el-icon>
  16. </div>
  17. </template>
  18. </el-button>
  19. <el-button type="primary" plain icon-placement="left" @click="packHandle">
  20. 全部{{ expandedKeys.length ? '收起' : '展开' }}
  21. <template #icon>
  22. <div class="flex items-center">
  23. <el-icon size="14">
  24. <AlignLeftOutlined />
  25. </el-icon>
  26. </div>
  27. </template>
  28. </el-button>
  29. </el-space>
  30. </template>
  31. <div class="w-full">
  32. <div v-loading="loading">
  33. <el-scrollbar height="620px">
  34. <el-tree
  35. ref="treeRef"
  36. :data="permissionViewTree"
  37. nodeKey="value"
  38. highlight-current
  39. check-strictly
  40. @current-change="onSelectTreeNode"
  41. @update:expanded-keys="onExpandedKeys"
  42. />
  43. </el-scrollbar>
  44. </div>
  45. </div>
  46. </el-card>
  47. </el-col>
  48. <!-- 右侧编辑权限 -->
  49. <el-col :span="18">
  50. <el-card shadow="hover">
  51. <template #header>
  52. <div class="flex justify-between">
  53. <el-space>
  54. <span>编辑权限: </span>
  55. <span>{{ treeItemTitle }}</span>
  56. </el-space>
  57. <el-popconfirm v-if="isEditing" :title="`确定要删除${treeItemTitle}吗?`" width="200" @confirm="handleDeletePermission">
  58. <template #reference>
  59. <el-button type="danger" size="small">删除权限</el-button>
  60. </template>
  61. </el-popconfirm>
  62. </div>
  63. </template>
  64. <!-- 表单 -->
  65. <div class="pt-6">
  66. <PermissionForm
  67. v-show="selectedPermissionId != null"
  68. ref="formInstance"
  69. :permissionList="permissionViewTree"
  70. @change="handleChangePermssion"
  71. isShowSubmit
  72. class="w-2/3 ml-10"
  73. />
  74. <el-empty v-show="selectedPermissionId == null" description="从左侧列表选择一项后,进行编辑" />
  75. </div>
  76. </el-card>
  77. </el-col>
  78. </el-row>
  79. <!-- 添加新权限 -->
  80. <CreateDrawer
  81. ref="drawerInstance"
  82. :permissionList="permissionViewTree"
  83. @change="handleChangePermssion"
  84. />
  85. </div>
  86. </template>
  87. <script setup lang="ts">
  88. import { ref, shallowRef, onMounted } from 'vue';
  89. import PermissionForm from './PermissionForm.vue';
  90. import CreateDrawer from './CreateDrawer.vue';
  91. import { AlignLeftOutlined, FileAddOutlined } from '@vicons/antd';
  92. import { PermissionTree, PermissionView, PermissionViewItem, PermissionViewTree, Permission } from '@/types/permission/type';
  93. import { getPermissionTree, deletePermission } from '@/api/system/permission';
  94. import { getTreeItem } from '@/utils';
  95. import { cloneDeep } from 'lodash-es';
  96. import { ElMessage } from 'element-plus';
  97. // 左侧权限树相关
  98. const expandedKeys = ref<PermissionViewItem['value'][]>([]);
  99. const loading = ref(true);
  100. const treeRef = ref();
  101. const permissionTree = shallowRef<PermissionTree>([]);
  102. const permissionViewTree = shallowRef<PermissionViewTree>([]);
  103. // 右侧编辑菜单相关
  104. const treeItemTitle = ref('');
  105. const isEditing = ref(false);
  106. const selectedPermissionId = ref<number | null>(null);
  107. const formInstance = ref<InstanceType<typeof PermissionForm>>();
  108. // 抽屉相关
  109. const drawerInstance = ref<InstanceType<typeof CreateDrawer>>();
  110. const queryPermissionTree = async () => {
  111. loading.value = true;
  112. try {
  113. permissionTree.value = await getPermissionTree();
  114. permissionViewTree.value = transformToViewTree(permissionTree.value);
  115. } catch (e) {
  116. console.error(e);
  117. } finally {
  118. loading.value = false;
  119. }
  120. };
  121. const transformToViewTree = (tree: PermissionTree | null): PermissionViewTree => {
  122. if (tree == null) return [];
  123. const viewTree: PermissionViewTree = [];
  124. for (const item of tree) {
  125. const viewItem: PermissionView = {
  126. value: item.id!,
  127. label: item.permissionName,
  128. };
  129. if (Array.isArray(item.children) && item.children.length > 0) {
  130. viewItem.children = transformToViewTree(item.children);
  131. viewTree.push(viewItem);
  132. } else {
  133. viewTree.push(viewItem);
  134. }
  135. }
  136. return viewTree;
  137. };
  138. const onSelectTreeNode = (data: PermissionView, node: any) => {
  139. console.log(node);
  140. const permissionId = data.value as number;
  141. selectedPermissionId.value = permissionId;
  142. isEditing.value = true;
  143. treeItemTitle.value = data.label;
  144. const treeItem: Permission = getTreeItem(permissionTree.value, permissionId, 'id');
  145. const permission = cloneDeep(treeItem);
  146. delete permission.children;
  147. formInstance.value?.setData(permission);
  148. };
  149. /**
  150. * 左侧权限树 展开 / 收起
  151. */
  152. const packHandle = () => {
  153. if (!expandedKeys.value.length) {
  154. treeNodeExpand(true);
  155. expandedKeys.value = permissionViewTree.value?.map((item) => item.value);
  156. } else {
  157. expandedKeys.value = [];
  158. treeNodeExpand(false);
  159. }
  160. };
  161. const treeNodeExpand = (status) => {
  162. for (var i = 0; i < treeRef.value.store._getAllNodes().length; i++) {
  163. treeRef.value.store._getAllNodes()[i].expanded = status;
  164. }
  165. };
  166. const onExpandedKeys = (keys) => {
  167. expandedKeys.value = keys;
  168. };
  169. function clearEditing() {
  170. isEditing.value = false;
  171. treeItemTitle.value = '';
  172. selectedPermissionId.value = null;
  173. }
  174. /**
  175. * 编辑权限,或者 新建权限 后的 change 事件处理
  176. */
  177. const handleChangePermssion = () => {
  178. clearEditing();
  179. queryPermissionTree();
  180. };
  181. /**
  182. * 不允许删除父节点
  183. */
  184. const handleDeletePermission = async () => {
  185. const treeItem: Permission = getTreeItem(permissionTree.value, selectedPermissionId.value!, 'id');
  186. if (treeItem.children && treeItem.children.length > 0) {
  187. ElMessage.error('当前权限含有子权限,无法删除');
  188. return;
  189. }
  190. try {
  191. await deletePermission(selectedPermissionId.value!);
  192. clearEditing();
  193. queryPermissionTree();
  194. } catch(e) {
  195. console.error(e);
  196. }
  197. }
  198. function openCreateDrawer() {
  199. drawerInstance.value?.openDrawer();
  200. }
  201. onMounted(() => {
  202. queryPermissionTree();
  203. });
  204. </script>
  205. <style scoped>
  206. .page-permission {
  207. height: calc(100vh - 100px);
  208. }
  209. </style>