RoleAssignMenuForm.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <template>
  2. <Dialog v-model="dialogVisible" title="菜单权限">
  3. <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px">
  4. <el-form-item label="角色名称">
  5. <el-tag>{{ formData.name }}</el-tag>
  6. </el-form-item>
  7. <el-form-item label="角色标识">
  8. <el-tag>{{ formData.code }}</el-tag>
  9. </el-form-item>
  10. <el-form-item label="菜单权限">
  11. <el-card class="cardHeight">
  12. <template #header>
  13. 全选/全不选:
  14. <el-switch
  15. v-model="treeNodeAll"
  16. active-text="是"
  17. inactive-text="否"
  18. inline-prompt
  19. @change="handleCheckedTreeNodeAll"
  20. />
  21. 全部展开/折叠:
  22. <el-switch
  23. v-model="menuExpand"
  24. active-text="展开"
  25. inactive-text="折叠"
  26. inline-prompt
  27. @change="handleCheckedTreeExpand"
  28. />
  29. </template>
  30. <el-tree
  31. ref="treeRef"
  32. :data="menuOptions"
  33. :props="defaultProps"
  34. empty-text="加载中,请稍候"
  35. node-key="id"
  36. show-checkbox
  37. />
  38. </el-card>
  39. </el-form-item>
  40. </el-form>
  41. <template #footer>
  42. <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
  43. <el-button @click="dialogVisible = false">取 消</el-button>
  44. </template>
  45. </Dialog>
  46. </template>
  47. <script lang="ts" name="SystemRoleAssignMenuForm" setup>
  48. import { defaultProps, handleTree } from '@/utils/tree'
  49. import * as RoleApi from '@/api/system/role'
  50. import * as MenuApi from '@/api/system/menu'
  51. import * as PermissionApi from '@/api/system/permission'
  52. const { t } = useI18n() // 国际化
  53. const message = useMessage() // 消息弹窗
  54. const dialogVisible = ref(false) // 弹窗的是否展示
  55. const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  56. const formData = reactive({
  57. id: 0,
  58. name: '',
  59. code: '',
  60. menuIds: []
  61. })
  62. const formRef = ref() // 表单 Ref
  63. const menuOptions = ref<any[]>([]) // 菜单树形结构
  64. const menuExpand = ref(false) // 展开/折叠
  65. const treeRef = ref() // 菜单树组件 Ref
  66. const treeNodeAll = ref(false) // 全选/全不选
  67. /** 打开弹窗 */
  68. const open = async (row: RoleApi.RoleVO) => {
  69. dialogVisible.value = true
  70. resetForm()
  71. // 加载 Menu 列表。注意,必须放在前面,不然下面 setChecked 没数据节点
  72. menuOptions.value = handleTree(await MenuApi.getSimpleMenusList())
  73. // 设置数据
  74. formData.id = row.id
  75. formData.name = row.name
  76. formData.code = row.code
  77. formLoading.value = true
  78. try {
  79. formData.value.menuIds = await PermissionApi.getRoleMenuList(row.id)
  80. // 设置选中
  81. formData.value.menuIds.forEach((menuId: number) => {
  82. treeRef.value.setChecked(menuId, true, false)
  83. })
  84. } finally {
  85. formLoading.value = false
  86. }
  87. }
  88. defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  89. /** 提交表单 */
  90. const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  91. const submitForm = async () => {
  92. // 校验表单
  93. if (!formRef) return
  94. const valid = await formRef.value.validate()
  95. if (!valid) return
  96. // 提交请求
  97. formLoading.value = true
  98. try {
  99. const data = {
  100. roleId: formData.id,
  101. menuIds: [
  102. ...(treeRef.value.getCheckedKeys(false) as unknown as Array<number>), // 获得当前选中节点
  103. ...(treeRef.value.getHalfCheckedKeys() as unknown as Array<number>) // 获得半选中的父节点
  104. ]
  105. }
  106. await PermissionApi.assignRoleMenu(data)
  107. message.success(t('common.updateSuccess'))
  108. dialogVisible.value = false
  109. // 发送操作成功的事件
  110. emit('success')
  111. } finally {
  112. formLoading.value = false
  113. }
  114. }
  115. /** 重置表单 */
  116. const resetForm = () => {
  117. // 重置选项
  118. treeNodeAll.value = false
  119. menuExpand.value = false
  120. // 重置表单
  121. formData.value = {
  122. id: 0,
  123. name: '',
  124. code: '',
  125. menuIds: []
  126. }
  127. treeRef.value?.setCheckedNodes([])
  128. formRef.value?.resetFields()
  129. }
  130. /** 全选/全不选 */
  131. const handleCheckedTreeNodeAll = () => {
  132. treeRef.value.setCheckedNodes(treeNodeAll.value ? menuOptions.value : [])
  133. }
  134. /** 展开/折叠全部 */
  135. const handleCheckedTreeExpand = () => {
  136. const nodes = treeRef.value?.store.nodesMap
  137. for (let node in nodes) {
  138. if (nodes[node].expanded === menuExpand.value) {
  139. continue
  140. }
  141. nodes[node].expanded = menuExpand.value
  142. }
  143. }
  144. </script>
  145. <style lang="scss" scoped>
  146. .cardHeight {
  147. width: 100%;
  148. max-height: 400px;
  149. overflow-y: scroll;
  150. }
  151. </style>