Showing
3 changed files
with
283 additions
and
2 deletions
... | ... | @@ -72,7 +72,7 @@ |
72 | 72 | import { TOption } from '/@/views/rule/linkedge/config/config.data'; |
73 | 73 | import { PlusOutlined } from '@ant-design/icons-vue'; |
74 | 74 | import { useDrawer } from '/@/components/Drawer'; |
75 | - import RoleDrawer from '../../role/RoleDrawer.vue'; | |
75 | + import RoleDrawer from '../../role/CustomRoleDrawer.vue'; | |
76 | 76 | import OrganizationDrawer from '/@/views/system/organization/OrganizationDrawer.vue'; |
77 | 77 | |
78 | 78 | export default defineComponent({ | ... | ... |
src/views/system/role/CustomRoleDrawer.vue
0 → 100644
1 | +<template> | |
2 | + <BasicDrawer | |
3 | + v-bind="$attrs" | |
4 | + @register="registerDrawer" | |
5 | + showFooter | |
6 | + :title="getTitle" | |
7 | + width="500px" | |
8 | + @ok="handleSubmit" | |
9 | + > | |
10 | + <BasicForm @register="registerForm"> | |
11 | + <template #menu> | |
12 | + <Spin :spinning="spinning"> | |
13 | + <BasicTree | |
14 | + v-if="treeData.length" | |
15 | + checkable | |
16 | + toolbar | |
17 | + ref="treeRef" | |
18 | + :treeData="treeData" | |
19 | + @check="handleCheckClick" | |
20 | + :replace-fields="{ title: 'name', key: 'id' }" | |
21 | + :checkedKeys="roleMenus" | |
22 | + title="菜单分配" | |
23 | + /> | |
24 | + </Spin> | |
25 | + </template> | |
26 | + </BasicForm> | |
27 | + </BasicDrawer> | |
28 | +</template> | |
29 | +<script lang="ts"> | |
30 | + import { defineComponent, ref, computed, unref, nextTick } from 'vue'; | |
31 | + import { BasicForm, useForm } from '/@/components/Form/index'; | |
32 | + import { formSchema, KeysTypeEnum, RoleMenuDictEnum } from './role.data'; | |
33 | + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | |
34 | + import { BasicTree, TreeActionType, TreeItem } from '/@/components/Tree'; | |
35 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
36 | + const { t } = useI18n(); // 加载国际化 | |
37 | + // 加载菜单数据 | |
38 | + import { getMeMenuList, getMenusIdsByRoleId } from '/@/api/sys/menu'; | |
39 | + import { useI18n } from '/@/hooks/web/useI18n'; | |
40 | + import { MenuRecord } from '/@/api/sys/model/menuModel'; | |
41 | + import { saveOrUpdateRoleInfoWithMenu } from '/@/api/system/system'; | |
42 | + import { findDictItemByCode } from '/@/api/system/dict'; | |
43 | + import { RoleEnum } from '/@/enums/roleEnum'; | |
44 | + import { Spin } from 'ant-design-vue'; | |
45 | + import { useRole } from '/@/hooks/business/useRole'; | |
46 | + import { RoleListItem } from '/@/api/system/model/systemModel'; | |
47 | + | |
48 | + type TreeData = MenuRecord & TreeItem; | |
49 | + | |
50 | + export default defineComponent({ | |
51 | + name: 'RoleDrawer', | |
52 | + components: { BasicDrawer, BasicForm, BasicTree, Spin }, | |
53 | + emits: ['success', 'register'], | |
54 | + setup(_, { emit }) { | |
55 | + const isUpdate = ref<boolean>(true); | |
56 | + const treeData = ref<TreeData[]>([]); | |
57 | + const roleMenus = ref<string[]>([]); | |
58 | + const roleId = ref<string>(''); | |
59 | + const treeRef = ref<Nullable<TreeActionType>>(); | |
60 | + const checked = ref<string[]>([]); //需要选中的节点 | |
61 | + const spinning = ref(false); | |
62 | + const checkedKeysWithHalfChecked = ref<string[]>([]); | |
63 | + | |
64 | + const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({ | |
65 | + labelWidth: 100, | |
66 | + schemas: formSchema, | |
67 | + showActionButtonGroup: false, | |
68 | + }); | |
69 | + | |
70 | + const transformName = (data: TreeData[]) => { | |
71 | + return data.map((item) => { | |
72 | + item.name = t(item.name); | |
73 | + if (item.children && item.children.length) { | |
74 | + item.children = transformName(item.children as unknown as TreeData[]); | |
75 | + } | |
76 | + return item; | |
77 | + }); | |
78 | + }; | |
79 | + | |
80 | + const { isTenantAdmin, isSysadmin, getRole } = useRole(); | |
81 | + const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner( | |
82 | + async (data: { isUpdate: boolean; record: RoleListItem }) => { | |
83 | + resetFields(); | |
84 | + roleId.value = ''; | |
85 | + // 在打开弹窗时清除所有选择的菜单 | |
86 | + treeRef.value && treeRef.value?.setCheckedKeys([]); | |
87 | + isUpdate.value = data.isUpdate; | |
88 | + let roleType = unref(getRole) || RoleEnum.SYS_ADMIN; | |
89 | + | |
90 | + // 租户管理员创建角色时 菜单分配为客户菜单 | |
91 | + if (unref(isTenantAdmin)) { | |
92 | + roleType = RoleEnum.CUSTOMER_USER; | |
93 | + } | |
94 | + | |
95 | + try { | |
96 | + spinning.value = true; | |
97 | + // 需要在setFieldsValue之前先填充treeData,否则Tree组件可能会报key not exist警告 | |
98 | + | |
99 | + // if (!unref(treeData).length) { | |
100 | + // 获取全部的菜单 | |
101 | + const menuListModel = await getMeMenuList(); | |
102 | + treeData.value = transformName(menuListModel as unknown as TreeData[]); | |
103 | + // } | |
104 | + | |
105 | + const keys = await getPermissionByRole(roleType); | |
106 | + const { keyType } = RoleMenuDictEnum[roleType]; | |
107 | + treeData.value = filterPermissionTreeData( | |
108 | + unref(treeData) as unknown as TreeData[], | |
109 | + keys, | |
110 | + keyType | |
111 | + ); | |
112 | + | |
113 | + // 如果编辑的是超级管理员 则不再过滤平台管理员禁用的权限 | |
114 | + // 如果是超级管理员创建角色 创建角色属于平台管理员 因此过滤平台管理员禁用的权限 | |
115 | + if (data?.record?.roleType !== RoleEnum.SYS_ADMIN && unref(isSysadmin)) { | |
116 | + const keys = await getPermissionByRole(RoleEnum.PLATFORM_ADMIN); | |
117 | + const { keyType } = RoleMenuDictEnum[RoleEnum.PLATFORM_ADMIN]; | |
118 | + treeData.value = filterPermissionTreeData( | |
119 | + unref(treeData) as unknown as TreeData[], | |
120 | + keys, | |
121 | + keyType | |
122 | + ); | |
123 | + } | |
124 | + | |
125 | + // 更新 | |
126 | + if (unref(isUpdate)) { | |
127 | + checked.value = []; | |
128 | + roleId.value = data.record.id; | |
129 | + | |
130 | + //通过角色id去获取角色对应的菜单的ids | |
131 | + checkedKeysWithHalfChecked.value = roleMenus.value = await getMenusIdsByRoleId( | |
132 | + data.record.id | |
133 | + ); | |
134 | + excludeHalfCheckedKeys(unref(treeData)); | |
135 | + await nextTick(); | |
136 | + unref(treeRef)?.setCheckedKeys(roleMenus.value); | |
137 | + setFieldsValue(data.record); | |
138 | + } else { | |
139 | + } | |
140 | + } catch (error) { | |
141 | + throw error; | |
142 | + } finally { | |
143 | + spinning.value = false; | |
144 | + } | |
145 | + } | |
146 | + ); | |
147 | + | |
148 | + const getTitle = computed(() => (!unref(isUpdate) ? '新增角色' : '编辑角色')); | |
149 | + | |
150 | + async function handleSubmit() { | |
151 | + setDrawerProps({ confirmLoading: true }); | |
152 | + const { createMessage } = useMessage(); | |
153 | + try { | |
154 | + const values = await validate(); | |
155 | + const treeCheckedKeys: string[] = (unref(treeRef)?.getCheckedKeys() as string[]) || []; | |
156 | + const menu = [...new Set([...unref(checkedKeysWithHalfChecked), ...treeCheckedKeys])]; | |
157 | + const req = { | |
158 | + id: roleId.value, | |
159 | + name: values.name, | |
160 | + remark: values.remark, | |
161 | + status: values.status, | |
162 | + menu, | |
163 | + }; | |
164 | + if (req.menu == undefined) return createMessage.error('请勾选权限菜单'); | |
165 | + saveOrUpdateRoleInfoWithMenu(req).then(() => { | |
166 | + closeDrawer(); | |
167 | + emit('success'); | |
168 | + createMessage.success(`${unref(isUpdate) ? '编辑' : '新增'}成功`); | |
169 | + }); | |
170 | + } finally { | |
171 | + setTimeout(() => { | |
172 | + setDrawerProps({ confirmLoading: false }); | |
173 | + }, 300); | |
174 | + } | |
175 | + } | |
176 | + | |
177 | + const getPermissionByRole = async (roleType: RoleEnum) => { | |
178 | + try { | |
179 | + const { key } = RoleMenuDictEnum[roleType]; | |
180 | + const res = await findDictItemByCode({ dictCode: key }); | |
181 | + return res.map((item) => item.itemValue); | |
182 | + } catch (error) {} | |
183 | + return []; | |
184 | + }; | |
185 | + | |
186 | + const filterPermissionTreeData = ( | |
187 | + data: MenuRecord[], | |
188 | + permissionKeys: string[], | |
189 | + keysType: KeysTypeEnum | |
190 | + ): TreeData[] => { | |
191 | + const permissionCompare = ( | |
192 | + data: MenuRecord[], | |
193 | + permissionKeys: string[], | |
194 | + keysType: KeysTypeEnum | |
195 | + ): TreeData[] => { | |
196 | + return data.filter((item) => { | |
197 | + item.name = t(item.name); | |
198 | + const findFlag = permissionKeys.includes(item.permission); | |
199 | + | |
200 | + item.show = findFlag ? keysType === KeysTypeEnum.ENABLED : undefined; | |
201 | + | |
202 | + if (item.children && item.children.length) { | |
203 | + if (item.show) return true; | |
204 | + if (item.show === undefined) { | |
205 | + item.children = permissionCompare(item.children, permissionKeys, keysType); | |
206 | + item.show = item.children.some((item) => | |
207 | + keysType === KeysTypeEnum.ENABLED | |
208 | + ? item.show | |
209 | + : item.show === undefined | |
210 | + ? true | |
211 | + : item.show | |
212 | + ); | |
213 | + return item.show; | |
214 | + } | |
215 | + } | |
216 | + | |
217 | + return keysType === KeysTypeEnum.ENABLED | |
218 | + ? item.show | |
219 | + : item.show === undefined | |
220 | + ? true | |
221 | + : item.show; | |
222 | + }) as unknown as TreeData[]; | |
223 | + }; | |
224 | + | |
225 | + return permissionCompare(data, permissionKeys, keysType); | |
226 | + }; | |
227 | + | |
228 | + const excludeHalfCheckedKeys = (treeData: MenuRecord[]) => { | |
229 | + const needExcludeKeys: string[] = []; | |
230 | + const query = (data: MenuRecord[]) => { | |
231 | + data.forEach((item) => { | |
232 | + item.checked = roleMenus.value.includes(item.id); | |
233 | + if (item.children && item.children.length) { | |
234 | + query(item.children); | |
235 | + item.checked = item.children.every((item) => item.checked); | |
236 | + } | |
237 | + if (!item.checked) { | |
238 | + needExcludeKeys.push(item.id); | |
239 | + } | |
240 | + }); | |
241 | + }; | |
242 | + query(treeData); | |
243 | + roleMenus.value = unref(roleMenus).filter((key) => !needExcludeKeys.includes(key)); | |
244 | + return needExcludeKeys; | |
245 | + }; | |
246 | + | |
247 | + const handleCheckClick = (selectedKeys: string[], event: CheckEvent) => { | |
248 | + checkedKeysWithHalfChecked.value = [ | |
249 | + ...selectedKeys, | |
250 | + ...(event.halfCheckedKeys as string[]), | |
251 | + ]; | |
252 | + }; | |
253 | + | |
254 | + return { | |
255 | + spinning, | |
256 | + registerDrawer, | |
257 | + registerForm, | |
258 | + getTitle, | |
259 | + handleSubmit, | |
260 | + treeData, | |
261 | + roleMenus, | |
262 | + treeRef, | |
263 | + handleCheckClick, | |
264 | + }; | |
265 | + }, | |
266 | + }); | |
267 | +</script> | |
268 | + | |
269 | +<style scoped lang="less"> | |
270 | + :deep(.vben-basic-tree) { | |
271 | + width: 100% !important; | |
272 | + } | |
273 | + | |
274 | + :deep(.is-unflod) { | |
275 | + display: none !important; | |
276 | + } | |
277 | + | |
278 | + :deep(.is-flod) { | |
279 | + display: none !important; | |
280 | + } | |
281 | +</style> | ... | ... |