Commit d123ed23119eddd5c9dde891f2b978e77c81df69
Merge branch 'ww' into 'main'
fix: BUG in teambition && perf code See merge request huang/yun-teng-iot-front!456
Showing
11 changed files
with
398 additions
and
198 deletions
... | ... | @@ -34,7 +34,7 @@ enum DeviceManagerApi { |
34 | 34 | } |
35 | 35 | |
36 | 36 | export const devicePage = (params: DeviceQueryParam) => { |
37 | - return defHttp.get<DeviceModel>({ | |
37 | + return defHttp.get<PaginationResult<DeviceModel>>({ | |
38 | 38 | url: DeviceManagerApi.DEVICE_URL, |
39 | 39 | params, |
40 | 40 | }); |
... | ... | @@ -80,10 +80,9 @@ export const deleteDevice = (ids: string[]) => { |
80 | 80 | * 查询设备配置 |
81 | 81 | * @param params pageSize page name |
82 | 82 | */ |
83 | -export const deviceProfile = (params) => { | |
84 | - return defHttp.get({ | |
83 | +export const deviceProfile = () => { | |
84 | + return defHttp.get<DeviceRecord[]>({ | |
85 | 85 | url: DeviceManagerApi.DEVICE_PROFILE_URL_ME, |
86 | - params, | |
87 | 86 | }); |
88 | 87 | }; |
89 | 88 | ... | ... |
... | ... | @@ -18,3 +18,32 @@ export interface RouteItem { |
18 | 18 | * @description: Get menu return value |
19 | 19 | */ |
20 | 20 | export type getMenuListResultModel = RouteItem[]; |
21 | + | |
22 | +export interface Meta { | |
23 | + title: string; | |
24 | + menuType: string; | |
25 | + status: string; | |
26 | + icon: string; | |
27 | + isLink: boolean; | |
28 | + ignoreKeepAlive: boolean; | |
29 | + hideMenu: boolean; | |
30 | +} | |
31 | + | |
32 | +export interface MenuRecord { | |
33 | + id: string; | |
34 | + createTime: string; | |
35 | + updateTime: string; | |
36 | + name: string; | |
37 | + children: MenuRecord[]; | |
38 | + path: string; | |
39 | + type: string; | |
40 | + permission: string; | |
41 | + sort: number; | |
42 | + component: string; | |
43 | + meta: Meta; | |
44 | + disabled?: boolean; | |
45 | + isDictCompareDisabled?: boolean; | |
46 | + icon?: string; | |
47 | + title?: string; | |
48 | + key?: string; | |
49 | +} | ... | ... |
... | ... | @@ -181,9 +181,9 @@ |
181 | 181 | const newItem = JSON.parse(getItem); |
182 | 182 | updataPersonlData.value = newItem; |
183 | 183 | }; |
184 | - | |
185 | - const [registerModal, { closeModal }] = useModalInner(async (data) => { | |
184 | + const [registerModal, { closeModal }] = useModalInner(async () => { | |
186 | 185 | refreshCacheGetData(); |
186 | + const userInfo = userStore.getUserInfo; | |
187 | 187 | try { |
188 | 188 | if (updataPersonlData.value != null) { |
189 | 189 | (peresonalPic.value = updataPersonlData.value.avatar), |
... | ... | @@ -194,13 +194,13 @@ |
194 | 194 | }); |
195 | 195 | getPersonalDetailValue.value = updataPersonlData.value; |
196 | 196 | } else { |
197 | - if (data.userInfo) { | |
198 | - getPersonalDetailValue.value = data.userInfo; | |
199 | - peresonalPic.value = data.userInfo.avatar; | |
197 | + if (userInfo) { | |
198 | + getPersonalDetailValue.value = userInfo; | |
199 | + peresonalPic.value = userInfo.avatar; | |
200 | 200 | setFieldsValue({ |
201 | - realName: data.userInfo.realName, | |
202 | - phoneNumber: data.userInfo.phoneNumber, | |
203 | - email: data.userInfo.email, | |
201 | + realName: userInfo.realName, | |
202 | + phoneNumber: userInfo.phoneNumber, | |
203 | + email: userInfo.email, | |
204 | 204 | }); |
205 | 205 | } |
206 | 206 | } | ... | ... |
... | ... | @@ -62,10 +62,18 @@ export const step1Schemas: FormSchema[] = [ |
62 | 62 | label: '所属产品', |
63 | 63 | required: true, |
64 | 64 | component: 'ApiSelect', |
65 | - componentProps: ({ formActionType }) => { | |
65 | + componentProps: ({ formActionType, formModel }) => { | |
66 | 66 | const { setFieldsValue } = formActionType; |
67 | 67 | return { |
68 | - api: deviceProfile, | |
68 | + api: async () => { | |
69 | + const options = await deviceProfile(); | |
70 | + const { profileId } = formModel; | |
71 | + if (profileId) { | |
72 | + const selectRecord = options.find((item) => item.tbProfileId === profileId); | |
73 | + selectRecord && setFieldsValue({ transportType: selectRecord!.transportType }); | |
74 | + } | |
75 | + return options; | |
76 | + }, | |
69 | 77 | labelField: 'name', |
70 | 78 | valueField: 'tbProfileId', |
71 | 79 | onChange( |
... | ... | @@ -148,6 +156,7 @@ export const step1Schemas: FormSchema[] = [ |
148 | 156 | ifShow: ({ values }) => values.deviceType === 'SENSOR' && values.organizationId, |
149 | 157 | componentProps: ({ formModel }) => { |
150 | 158 | const { organizationId, transportType } = formModel; |
159 | + if (![organizationId, transportType].every(Boolean)) return {}; | |
151 | 160 | return { |
152 | 161 | api: getGatewayDevice, |
153 | 162 | showSearch: true, | ... | ... |
... | ... | @@ -224,31 +224,33 @@ |
224 | 224 | const [registerTbDetailDrawer, { openDrawer: openTbDeviceDrawer }] = useDrawer(); |
225 | 225 | const [registerGatewayDetailDrawer, { openDrawer: openGatewayDetailDrawer }] = useDrawer(); |
226 | 226 | |
227 | - const [registerTable, { reload, setSelectedRowKeys, setProps, setTableData, getForm }] = | |
228 | - useTable({ | |
229 | - title: '设备列表', | |
230 | - api: devicePage, | |
231 | - immediate: immediateStatus.value, | |
232 | - columns, | |
233 | - formConfig: { | |
234 | - labelWidth: 100, | |
235 | - schemas: searchFormSchema, | |
236 | - resetFunc: resetFn, | |
237 | - }, | |
238 | - useSearchForm: true, | |
239 | - showTableSetting: true, | |
240 | - bordered: true, | |
241 | - showIndexColumn: false, | |
242 | - rowKey: 'id', | |
243 | - searchInfo: searchInfo, | |
244 | - clickToRowSelect: false, | |
245 | - actionColumn: { | |
246 | - width: 200, | |
247 | - title: '操作', | |
248 | - slots: { customRender: 'action' }, | |
249 | - fixed: 'right', | |
250 | - }, | |
251 | - }); | |
227 | + const [ | |
228 | + registerTable, | |
229 | + { reload, setSelectedRowKeys, setProps, setTableData, getForm, setPagination }, | |
230 | + ] = useTable({ | |
231 | + title: '设备列表', | |
232 | + api: devicePage, | |
233 | + immediate: immediateStatus.value, | |
234 | + columns, | |
235 | + formConfig: { | |
236 | + labelWidth: 100, | |
237 | + schemas: searchFormSchema, | |
238 | + resetFunc: resetFn, | |
239 | + }, | |
240 | + useSearchForm: true, | |
241 | + showTableSetting: true, | |
242 | + bordered: true, | |
243 | + showIndexColumn: false, | |
244 | + rowKey: 'id', | |
245 | + searchInfo: searchInfo, | |
246 | + clickToRowSelect: false, | |
247 | + actionColumn: { | |
248 | + width: 200, | |
249 | + title: '操作', | |
250 | + slots: { customRender: 'action' }, | |
251 | + fixed: 'right', | |
252 | + }, | |
253 | + }); | |
252 | 254 | const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } = |
253 | 255 | useBatchDelete(deleteDevice, handleSuccess, setProps); |
254 | 256 | selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => { |
... | ... | @@ -275,14 +277,15 @@ |
275 | 277 | const deviceProfileId = ref(''); |
276 | 278 | count.value = Number(getParams('count')); |
277 | 279 | deviceProfileId.value = getParams('deviceProfileId') || ''; |
278 | - console.log(deviceProfileId.value); | |
280 | + | |
279 | 281 | const setRowClassName = async () => { |
280 | 282 | if (deviceProfileId.value !== undefined) { |
281 | - const { items } = await devicePage({ | |
283 | + const { items, total } = await devicePage({ | |
282 | 284 | page: 1, |
283 | 285 | pageSize: count.value === 0 ? 10 : count.value, |
284 | 286 | deviceProfileId: deviceProfileId.value, |
285 | 287 | }); |
288 | + setPagination({ total }); | |
286 | 289 | nextTick(() => { |
287 | 290 | setTableData(items); |
288 | 291 | const { setFieldsValue, resetFields } = getForm(); | ... | ... |
... | ... | @@ -9,18 +9,20 @@ |
9 | 9 | > |
10 | 10 | <BasicForm @register="registerForm"> |
11 | 11 | <template #menu> |
12 | - <BasicTree | |
13 | - v-if="treeData.length" | |
14 | - checkable | |
15 | - toolbar | |
16 | - :expandedKeys="treeExpandData" | |
17 | - ref="treeRef" | |
18 | - :treeData="treeData" | |
19 | - :replaceFields="{ title: 'menuName' }" | |
20 | - :checkedKeys="roleMenus" | |
21 | - @check="handleCheckClick" | |
22 | - title="菜单分配" | |
23 | - /> | |
12 | + <Spin :spinning="spinning"> | |
13 | + <BasicTree | |
14 | + v-if="treeData.length" | |
15 | + checkable | |
16 | + toolbar | |
17 | + :expandedKeys="treeExpandData" | |
18 | + ref="treeRef" | |
19 | + :treeData="treeData" | |
20 | + :replace-fields="{ title: 'name', key: 'id' }" | |
21 | + :checkedKeys="roleMenus" | |
22 | + @check="handleCheckClick" | |
23 | + title="菜单分配" | |
24 | + /> | |
25 | + </Spin> | |
24 | 26 | </template> |
25 | 27 | </BasicForm> |
26 | 28 | </BasicDrawer> |
... | ... | @@ -28,7 +30,7 @@ |
28 | 30 | <script lang="ts"> |
29 | 31 | import { defineComponent, ref, computed, unref, nextTick } from 'vue'; |
30 | 32 | import { BasicForm, useForm } from '/@/components/Form/index'; |
31 | - import { formSchema } from './role.data'; | |
33 | + import { formSchema, KeysTypeEnum, RoleMenuDictEnum } from './role.data'; | |
32 | 34 | import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; |
33 | 35 | import { BasicTree, TreeItem } from '/@/components/Tree'; |
34 | 36 | import { useMessage } from '/@/hooks/web/useMessage'; |
... | ... | @@ -36,22 +38,29 @@ |
36 | 38 | // 加载菜单数据 |
37 | 39 | import { getMenuList, getMenusIdsByRoleId } from '/@/api/sys/menu'; |
38 | 40 | import { useI18n } from '/@/hooks/web/useI18n'; |
39 | - import { RouteItem } from '/@/api/sys/model/menuModel'; | |
41 | + import { MenuRecord } from '/@/api/sys/model/menuModel'; | |
40 | 42 | import { saveOrUpdateRoleInfoWithMenu } from '/@/api/system/system'; |
43 | + import { findDictItemByCode } from '/@/api/system/dict'; | |
44 | + import { RoleEnum } from '/@/enums/roleEnum'; | |
45 | + import { Spin } from 'ant-design-vue'; | |
46 | + import { useUserStore } from '/@/store/modules/user'; | |
47 | + | |
48 | + type TreeData = MenuRecord & TreeItem; | |
49 | + | |
41 | 50 | export default defineComponent({ |
42 | 51 | name: 'RoleDrawer', |
43 | - components: { BasicDrawer, BasicForm, BasicTree }, | |
52 | + components: { BasicDrawer, BasicForm, BasicTree, Spin }, | |
44 | 53 | emits: ['success', 'register'], |
45 | 54 | setup(_, { emit }) { |
46 | - const treeExpandData = ref([]); | |
55 | + const treeExpandData = ref<string[]>([]); | |
47 | 56 | const isUpdate = ref<boolean>(true); |
48 | - const treeData = ref<TreeItem[]>([]); | |
57 | + const treeData = ref<TreeData[]>([]); | |
49 | 58 | const roleMenus = ref<string[]>([]); |
50 | 59 | const allCheckedKeys = ref<string[]>([]); |
51 | 60 | const roleId = ref<string>(''); |
52 | 61 | const treeRef = ref(); |
53 | - const checked: any = ref([]); //需要选中的节点 | |
54 | - const pidArr: any = ref([]); //获取父节点 | |
62 | + const checked = ref<string[]>([]); //需要选中的节点 | |
63 | + const spinning = ref(false); | |
55 | 64 | |
56 | 65 | const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({ |
57 | 66 | labelWidth: 100, |
... | ... | @@ -59,24 +68,19 @@ |
59 | 68 | showActionButtonGroup: false, |
60 | 69 | }); |
61 | 70 | |
62 | - // 递归函数,将RouteItem里面的字段换名称 | |
63 | - function processChildren(items: RouteItem[]) { | |
64 | - items.forEach((item) => { | |
65 | - item.menuName = t(item.meta.title); | |
66 | - item.icon = item.meta.icon; | |
67 | - item.key = item.id; | |
68 | - if (item.children) { | |
69 | - processChildren(item.children); | |
71 | + const originMenus = ref(); | |
72 | + | |
73 | + const transformName = (data: TreeData[]) => { | |
74 | + return data.map((item) => { | |
75 | + item.name = t(item.name); | |
76 | + if (item.children && item.children.length) { | |
77 | + item.children = transformName(item.children as unknown as TreeData[]); | |
70 | 78 | } |
79 | + return item; | |
71 | 80 | }); |
72 | - } | |
73 | - function lookForAllId(data = [], arr = []) { | |
74 | - for (const item of data) { | |
75 | - arr.push(item.id); | |
76 | - } | |
77 | - return arr; | |
78 | - } | |
79 | - const originMenus = ref(); | |
81 | + }; | |
82 | + | |
83 | + const userStore = useUserStore(); | |
80 | 84 | const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => { |
81 | 85 | allCheckedKeys.value = []; |
82 | 86 | originMenus.value = []; |
... | ... | @@ -84,53 +88,53 @@ |
84 | 88 | resetFields(); |
85 | 89 | roleId.value = ''; |
86 | 90 | // 在打开弹窗时清除所有选择的菜单 |
87 | - treeRef.value && treeRef.value.checkAll(false); | |
91 | + treeRef.value && treeRef.value?.setCheckedKeys([]); | |
88 | 92 | isUpdate.value = data.isUpdate; |
89 | - // 需要在setFieldsValue之前先填充treeData,否则Tree组件可能会报key not exist警告 | |
90 | - if (!unref(treeData).length) { | |
91 | - // 获取全部的菜单 | |
92 | - const menuListModel = await getMenuList(); | |
93 | - processChildren(menuListModel); | |
94 | - treeData.value = menuListModel; | |
95 | - //修复角色菜单新增-全部展开问题-只展开第一级即可 | |
96 | - nextTick(() => { | |
97 | - const getAllIds = lookForAllId(treeData.value, []); | |
98 | - treeExpandData.value = getAllIds; | |
99 | - }); | |
100 | - } | |
101 | - // 更新 | |
102 | - if (unref(isUpdate)) { | |
103 | - allCheckedKeys.value = []; | |
104 | - checked.value = []; | |
105 | - //通过角色id去获取角色对应的菜单的ids | |
106 | - roleMenus.value = await getMenusIdsByRoleId(data.record.id); | |
107 | - originMenus.value = [...roleMenus.value]; | |
108 | - | |
109 | - const getAllIds = lookForAllId(treeData.value, []); | |
110 | - treeExpandData.value = getAllIds; | |
111 | - for (let item of treeData.value) { | |
112 | - if (item?.children != 0) { | |
113 | - pidArr.value.push(item.key); | |
114 | - } | |
115 | - for (let item1 of item?.children) { | |
116 | - if (item1?.children != 0) { | |
117 | - pidArr.value.push(item1.key); | |
118 | - } | |
119 | - } | |
93 | + const roleType = data?.record?.roleType || userStore.getRoleList.at(0); | |
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 getMenuList(); | |
102 | + treeData.value = transformName(menuListModel as unknown as TreeData[]); | |
103 | + //修复角色菜单新增-全部展开问题-只展开第一级即可 | |
104 | + await nextTick(); | |
105 | + const getExpandKeys = unref(treeData).map((item) => item.id); | |
106 | + treeExpandData.value = getExpandKeys; | |
120 | 107 | } |
121 | - for (let item of roleMenus.value) { | |
122 | - let isP = pidArr.value.includes(item); | |
123 | - if (!isP) { | |
124 | - checked.value.push(item); | |
125 | - } | |
108 | + | |
109 | + const keys = await getPermissionByRole(roleType); | |
110 | + const { keyType } = RoleMenuDictEnum[roleType]; | |
111 | + treeData.value = getPermissionTreeData( | |
112 | + unref(treeData) as unknown as TreeData[], | |
113 | + keys, | |
114 | + keyType | |
115 | + ); | |
116 | + | |
117 | + // 更新 | |
118 | + if (unref(isUpdate)) { | |
119 | + allCheckedKeys.value = []; | |
120 | + checked.value = []; | |
121 | + roleId.value = data.record.id; | |
122 | + | |
123 | + //通过角色id去获取角色对应的菜单的ids | |
124 | + originMenus.value = roleMenus.value = await getMenusIdsByRoleId(data.record.id); | |
125 | + | |
126 | + const getExpandKeys = unref(treeData).map((item) => item.id); | |
127 | + treeExpandData.value = getExpandKeys; | |
128 | + | |
129 | + await nextTick(); | |
130 | + treeRef.value.setCheckedKeys(roleMenus.value); | |
131 | + setFieldsValue(data.record); | |
132 | + } else { | |
126 | 133 | } |
127 | - nextTick(() => { | |
128 | - treeRef.value.setCheckedKeys(checked.value); | |
129 | - // const expandTreeIds = lookForAllId(treeData.value); | |
130 | - // treeRef.value.setExpandedKeys(expandTreeIds); | |
131 | - }); | |
132 | - roleId.value = data.record.id; | |
133 | - setFieldsValue(data.record); | |
134 | + } catch (error) { | |
135 | + throw error; | |
136 | + } finally { | |
137 | + spinning.value = false; | |
134 | 138 | } |
135 | 139 | }); |
136 | 140 | |
... | ... | @@ -146,7 +150,7 @@ |
146 | 150 | name: values.name, |
147 | 151 | remark: values.remark, |
148 | 152 | status: values.status, |
149 | - menu: allCheckedKeys.value.length ? allCheckedKeys.value : originMenus.value, | |
153 | + menu: unref(treeRef).getCheckedKeys() || [], | |
150 | 154 | }; |
151 | 155 | if (req.menu == undefined) return createMessage.error('请勾选权限菜单'); |
152 | 156 | saveOrUpdateRoleInfoWithMenu(req).then(() => { |
... | ... | @@ -165,7 +169,74 @@ |
165 | 169 | allCheckedKeys.value = [...checkedNodes, ...halfCheckedKeys]; |
166 | 170 | }; |
167 | 171 | |
172 | + const getPermissionByRole = async (roleType: RoleEnum) => { | |
173 | + try { | |
174 | + const { key } = RoleMenuDictEnum[roleType]; | |
175 | + const res = await findDictItemByCode({ dictCode: key }); | |
176 | + return res.map((item) => item.itemValue); | |
177 | + } catch (error) {} | |
178 | + return []; | |
179 | + }; | |
180 | + | |
181 | + const getPermissionTreeData = ( | |
182 | + data: MenuRecord[], | |
183 | + permissionKeys: string[], | |
184 | + keysType: KeysTypeEnum | |
185 | + ) => { | |
186 | + const setDisabled = (data: MenuRecord[], flag: boolean) => { | |
187 | + return data.map((item) => { | |
188 | + item.name = t(item.name); | |
189 | + if (item.children && item.children.length) { | |
190 | + item.children = setDisabled(item.children, flag); | |
191 | + } | |
192 | + return { | |
193 | + ...item, | |
194 | + disabled: flag, | |
195 | + icon: item.meta.icon, | |
196 | + } as TreeData; | |
197 | + }); | |
198 | + }; | |
199 | + | |
200 | + const permissionCompare = ( | |
201 | + data: MenuRecord[], | |
202 | + permissionKeys: string[], | |
203 | + keysType: KeysTypeEnum | |
204 | + ) => { | |
205 | + return data.map((item) => { | |
206 | + item.name = t(item.name); | |
207 | + const findFlag = permissionKeys.includes(item.permission); | |
208 | + if (findFlag) item.isDictCompareDisabled = true; | |
209 | + const disabledFlag = keysType === KeysTypeEnum.DISABLED ? findFlag : !findFlag; | |
210 | + item.disabled = disabledFlag; | |
211 | + | |
212 | + if (item.isDictCompareDisabled && item.children && item.children.length) { | |
213 | + setDisabled(item.children, disabledFlag); | |
214 | + } else { | |
215 | + if (item.children && item.children.length) { | |
216 | + item.children = permissionCompare(item.children, permissionKeys, keysType); | |
217 | + item.disabled = item.children.every((temp) => temp.disabled); | |
218 | + } | |
219 | + } | |
220 | + return { | |
221 | + ...item, | |
222 | + icon: item.meta.icon, | |
223 | + } as TreeData; | |
224 | + }); | |
225 | + }; | |
226 | + | |
227 | + const result = permissionCompare(data, permissionKeys, keysType).map((item) => { | |
228 | + if (item.children && item.children.length) { | |
229 | + const rootDisabledFlag = item.children.every((temp) => temp.disabled); | |
230 | + item.disabled = rootDisabledFlag; | |
231 | + } | |
232 | + return item; | |
233 | + }); | |
234 | + | |
235 | + return result; | |
236 | + }; | |
237 | + | |
168 | 238 | return { |
239 | + spinning, | |
169 | 240 | registerDrawer, |
170 | 241 | registerForm, |
171 | 242 | getTitle, |
... | ... | @@ -185,9 +256,11 @@ |
185 | 256 | :deep(.vben-basic-tree) { |
186 | 257 | width: 100% !important; |
187 | 258 | } |
259 | + | |
188 | 260 | :deep(.is-unflod) { |
189 | 261 | display: none !important; |
190 | 262 | } |
263 | + | |
191 | 264 | :deep(.is-flod) { |
192 | 265 | display: none !important; |
193 | 266 | } | ... | ... |
1 | 1 | import { BasicColumn } from '/@/components/Table'; |
2 | 2 | import { FormSchema } from '/@/components/Table'; |
3 | +import { RoleEnum } from '/@/enums/roleEnum'; | |
4 | + | |
5 | +export enum KeysTypeEnum { | |
6 | + DISABLED = 'disabled', | |
7 | + ENABLED = 'enabled', | |
8 | +} | |
9 | + | |
10 | +export const RoleMenuDictEnum: Recordable<{ key: string; keyType: KeysTypeEnum }> = { | |
11 | + [RoleEnum.PLATFORM_ADMIN]: { key: 'enabled_platform_admin_auth', keyType: KeysTypeEnum.ENABLED }, | |
12 | + [RoleEnum.SYS_ADMIN]: { key: 'enabled_sysadmin_auth', keyType: KeysTypeEnum.ENABLED }, | |
13 | + [RoleEnum.TENANT_ADMIN]: { key: 'disabled_tenant_auth', keyType: KeysTypeEnum.DISABLED }, | |
14 | + [RoleEnum.CUSTOMER_USER]: { key: 'disabled_tenant_auth', keyType: KeysTypeEnum.DISABLED }, | |
15 | +}; | |
3 | 16 | |
4 | 17 | export const columns: BasicColumn[] = [ |
5 | 18 | { | ... | ... |
... | ... | @@ -244,6 +244,7 @@ |
244 | 244 | permissionStore.setPermCodeList(permissionList); |
245 | 245 | userStore.setUserInfo(userInfo); |
246 | 246 | userStore.setRoleList(userInfo.roles as RoleEnum[]); |
247 | + permissionStore.buildRoutesAction(); | |
247 | 248 | go(PageEnum.BASE_HOME); |
248 | 249 | } catch (error) { |
249 | 250 | } finally { | ... | ... |
... | ... | @@ -9,19 +9,21 @@ |
9 | 9 | > |
10 | 10 | <BasicForm @register="registerForm"> |
11 | 11 | <template #menu> |
12 | - <BasicTree | |
13 | - v-if="treeData.length > 0" | |
14 | - :treeData="treeData" | |
15 | - :expandedKeys="treeExpandData" | |
16 | - :replaceFields="{ title: 'menuName' }" | |
17 | - :checkedKeys="roleMenus" | |
18 | - @check="handleCheckClick" | |
19 | - checkable | |
20 | - toolbar | |
21 | - ref="treeRef" | |
22 | - title="权限分配" | |
23 | - :defaultExpandAll="true" | |
24 | - /> | |
12 | + <Spin :spinning="spinning"> | |
13 | + <BasicTree | |
14 | + v-if="treeData.length" | |
15 | + :treeData="treeData" | |
16 | + :expandedKeys="treeExpandData" | |
17 | + :replaceFields="{ title: 'name', key: 'id' }" | |
18 | + :checkedKeys="roleMenus" | |
19 | + @check="handleCheckClick" | |
20 | + checkable | |
21 | + toolbar | |
22 | + ref="treeRef" | |
23 | + title="权限分配" | |
24 | + :defaultExpandAll="true" | |
25 | + /> | |
26 | + </Spin> | |
25 | 27 | </template> |
26 | 28 | </BasicForm> |
27 | 29 | </BasicDrawer> |
... | ... | @@ -36,17 +38,22 @@ |
36 | 38 | // 加载菜单数据 |
37 | 39 | import { getMenuList, getMenusIdsByRoleId } from '/@/api/sys/menu'; |
38 | 40 | import { useI18n } from '/@/hooks/web/useI18n'; |
39 | - import { RouteItem } from '/@/api/sys/model/menuModel'; | |
41 | + import { MenuRecord } from '/@/api/sys/model/menuModel'; | |
40 | 42 | import { saveOrUpdateRoleInfoWithMenu } from '/@/api/system/system'; |
41 | 43 | import { RoleEnum } from '/@/enums/roleEnum'; |
42 | 44 | import { useMessage } from '/@/hooks/web/useMessage'; |
45 | + import { KeysTypeEnum, RoleMenuDictEnum } from '../../system/role/role.data'; | |
46 | + import { findDictItemByCode } from '/@/api/system/dict'; | |
47 | + import { Spin } from 'ant-design-vue'; | |
48 | + | |
49 | + type TreeData = MenuRecord & TreeItem; | |
43 | 50 | |
44 | 51 | export default defineComponent({ |
45 | 52 | name: 'RoleDrawer', |
46 | - components: { BasicDrawer, BasicForm, BasicTree }, | |
53 | + components: { BasicDrawer, BasicForm, BasicTree, Spin }, | |
47 | 54 | emits: ['success', 'register'], |
48 | 55 | setup(_, { emit }) { |
49 | - const treeExpandData = ref([]); | |
56 | + const treeExpandData = ref<string[]>([]); | |
50 | 57 | |
51 | 58 | const isUpdate = ref(true); |
52 | 59 | const treeData = ref<TreeItem[]>([]); |
... | ... | @@ -54,8 +61,8 @@ |
54 | 61 | const allCheckedKeys = ref<string[]>([]); |
55 | 62 | const roleId = ref(''); |
56 | 63 | const treeRef = ref(); |
57 | - const checked: any = ref([]); //需要选中的节点 | |
58 | - const pidArr: any = ref([]); //获取父节点 | |
64 | + const checked = ref<string[]>([]); //需要选中的节点 | |
65 | + const spinning = ref(false); | |
59 | 66 | |
60 | 67 | const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({ |
61 | 68 | labelWidth: 90, |
... | ... | @@ -63,77 +70,71 @@ |
63 | 70 | showActionButtonGroup: false, |
64 | 71 | }); |
65 | 72 | |
66 | - function processChildren(items: RouteItem[]) { | |
67 | - items.map((item) => { | |
68 | - item.menuName = t(item.meta.title); | |
69 | - item.icon = item.meta.icon; | |
70 | - item.key = item.id; | |
71 | - if (item.children) { | |
72 | - processChildren(item.children); | |
73 | + const originMenus = ref(); | |
74 | + | |
75 | + const transformName = (data: TreeData[]) => { | |
76 | + return data.map((item) => { | |
77 | + item.name = t(item.name); | |
78 | + if (item.children && item.children.length) { | |
79 | + item.children = transformName(item.children as unknown as TreeData[]); | |
73 | 80 | } |
81 | + return item; | |
74 | 82 | }); |
75 | - } | |
76 | - function lookForAllId(data = [], arr = []) { | |
77 | - for (const item of data) { | |
78 | - arr.push(item.id); | |
79 | - } | |
80 | - return arr; | |
81 | - } | |
83 | + }; | |
82 | 84 | |
83 | - const originMenus = ref(); | |
84 | 85 | const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => { |
85 | - setDrawerProps({ confirmLoading: false }); | |
86 | 86 | allCheckedKeys.value = []; |
87 | 87 | originMenus.value = []; |
88 | - treeExpandData.value; | |
89 | 88 | allCheckedKeys.value.length = 0; |
90 | 89 | resetFields(); |
91 | 90 | roleId.value = ''; |
92 | 91 | // 在打开弹窗时清除所有选择的菜单 |
93 | - treeRef.value && treeRef.value.checkAll(false); | |
92 | + treeRef.value && treeRef.value?.setCheckedKeys([]); | |
94 | 93 | isUpdate.value = data.isUpdate; |
95 | - // 需要在setFieldsValue之前先填充treeData,否则Tree组件可能会报key not exist警告 | |
96 | - if (!unref(treeData).length) { | |
97 | - // 获取全部的菜单 | |
98 | - const menuListModel = await getMenuList(); | |
99 | - processChildren(menuListModel); | |
100 | - treeData.value = menuListModel; | |
101 | - //修复角色菜单新增-全部展开问题-只展开第一级即可 | |
102 | - nextTick(() => { | |
103 | - const getAllIds = lookForAllId(treeData.value, []); | |
104 | - treeExpandData.value = getAllIds; | |
105 | - }); | |
106 | - } | |
107 | - // 更新 | |
108 | - if (unref(isUpdate)) { | |
109 | - allCheckedKeys.value = []; | |
110 | - checked.value = []; | |
111 | - //通过角色id去获取角色对应的菜单的ids | |
112 | - roleMenus.value = await getMenusIdsByRoleId(data.record.id); | |
113 | - originMenus.value = [...roleMenus.value]; | |
114 | - const getAllIds = lookForAllId(treeData.value, []); | |
115 | - treeExpandData.value = getAllIds; | |
116 | - for (let item of treeData.value) { | |
117 | - if (item?.children != 0) { | |
118 | - pidArr.value.push(item.key); | |
119 | - } | |
120 | - for (let item1 of item?.children) { | |
121 | - if (item1?.children != 0) { | |
122 | - pidArr.value.push(item1.key); | |
123 | - } | |
124 | - } | |
94 | + const roleType = data?.record?.roleType || RoleEnum.TENANT_ADMIN; | |
95 | + try { | |
96 | + spinning.value = true; | |
97 | + // 需要在setFieldsValue之前先填充treeData,否则Tree组件可能会报key not exist警告 | |
98 | + | |
99 | + if (!unref(treeData).length) { | |
100 | + // 获取全部的菜单 | |
101 | + const menuListModel = await getMenuList(); | |
102 | + treeData.value = transformName(menuListModel as unknown as TreeData[]); | |
103 | + //修复角色菜单新增-全部展开问题-只展开第一级即可 | |
104 | + await nextTick(); | |
105 | + const getExpandKeys = unref(treeData).map((item) => item.id); | |
106 | + treeExpandData.value = getExpandKeys; | |
125 | 107 | } |
126 | - for (let item of roleMenus.value) { | |
127 | - let isP = pidArr.value.includes(item); | |
128 | - if (!isP) { | |
129 | - checked.value.push(item); | |
130 | - } | |
108 | + | |
109 | + const keys = await getPermissionByRole(roleType); | |
110 | + const { keyType } = RoleMenuDictEnum[roleType]; | |
111 | + treeData.value = getPermissionTreeData( | |
112 | + unref(treeData) as unknown as TreeData[], | |
113 | + keys, | |
114 | + keyType | |
115 | + ); | |
116 | + | |
117 | + // 更新 | |
118 | + if (unref(isUpdate)) { | |
119 | + allCheckedKeys.value = []; | |
120 | + checked.value = []; | |
121 | + roleId.value = data.record.id; | |
122 | + | |
123 | + //通过角色id去获取角色对应的菜单的ids | |
124 | + originMenus.value = roleMenus.value = await getMenusIdsByRoleId(data.record.id); | |
125 | + | |
126 | + const getExpandKeys = unref(treeData).map((item) => item.id); | |
127 | + treeExpandData.value = getExpandKeys; | |
128 | + | |
129 | + await nextTick(); | |
130 | + treeRef.value.setCheckedKeys(roleMenus.value); | |
131 | + setFieldsValue(data.record); | |
132 | + } else { | |
131 | 133 | } |
132 | - nextTick(() => { | |
133 | - treeRef.value.setCheckedKeys(checked.value); | |
134 | - }); | |
135 | - roleId.value = data.record.id; | |
136 | - setFieldsValue(data.record); | |
134 | + } catch (error) { | |
135 | + throw error; | |
136 | + } finally { | |
137 | + spinning.value = false; | |
137 | 138 | } |
138 | 139 | }); |
139 | 140 | const getTitle = computed(() => (!unref(isUpdate) ? '新增角色' : '编辑角色')); |
... | ... | @@ -150,7 +151,7 @@ |
150 | 151 | remark: values.remark, |
151 | 152 | status: values.status, |
152 | 153 | roleType: RoleEnum.TENANT_ADMIN, |
153 | - menu: allCheckedKeys.value.length ? allCheckedKeys.value : originMenus.value, | |
154 | + menu: unref(treeRef).getCheckedKeys() || [], | |
154 | 155 | }; |
155 | 156 | if (req.menu == undefined) return createMessage.error('请勾选权限菜单'); |
156 | 157 | const res = await saveOrUpdateRoleInfoWithMenu(req); |
... | ... | @@ -173,7 +174,74 @@ |
173 | 174 | allCheckedKeys.value = [...checkedNodes, ...halfCheckedKeys]; |
174 | 175 | }; |
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 getPermissionTreeData = ( | |
187 | + data: MenuRecord[], | |
188 | + permissionKeys: string[], | |
189 | + keysType: KeysTypeEnum | |
190 | + ) => { | |
191 | + const setDisabled = (data: MenuRecord[], flag: boolean) => { | |
192 | + return data.map((item) => { | |
193 | + item.name = t(item.name); | |
194 | + if (item.children && item.children.length) { | |
195 | + item.children = setDisabled(item.children, flag); | |
196 | + } | |
197 | + return { | |
198 | + ...item, | |
199 | + disabled: flag, | |
200 | + icon: item.meta.icon, | |
201 | + } as TreeData; | |
202 | + }); | |
203 | + }; | |
204 | + | |
205 | + const permissionCompare = ( | |
206 | + data: MenuRecord[], | |
207 | + permissionKeys: string[], | |
208 | + keysType: KeysTypeEnum | |
209 | + ) => { | |
210 | + return data.map((item) => { | |
211 | + item.name = t(item.name); | |
212 | + const findFlag = permissionKeys.includes(item.permission); | |
213 | + if (findFlag) item.isDictCompareDisabled = true; | |
214 | + const disabledFlag = keysType === KeysTypeEnum.DISABLED ? findFlag : !findFlag; | |
215 | + item.disabled = disabledFlag; | |
216 | + | |
217 | + if (item.isDictCompareDisabled && item.children && item.children.length) { | |
218 | + setDisabled(item.children, disabledFlag); | |
219 | + } else { | |
220 | + if (item.children && item.children.length) { | |
221 | + item.children = permissionCompare(item.children, permissionKeys, keysType); | |
222 | + item.disabled = item.children.every((temp) => temp.disabled); | |
223 | + } | |
224 | + } | |
225 | + return { | |
226 | + ...item, | |
227 | + icon: item.meta.icon, | |
228 | + } as TreeData; | |
229 | + }); | |
230 | + }; | |
231 | + | |
232 | + const result = permissionCompare(data, permissionKeys, keysType).map((item) => { | |
233 | + if (item.children && item.children.length) { | |
234 | + const rootDisabledFlag = item.children.every((temp) => temp.disabled); | |
235 | + item.disabled = rootDisabledFlag; | |
236 | + } | |
237 | + return item; | |
238 | + }); | |
239 | + | |
240 | + return result; | |
241 | + }; | |
242 | + | |
176 | 243 | return { |
244 | + spinning, | |
177 | 245 | registerDrawer, |
178 | 246 | registerForm, |
179 | 247 | getTitle, |
... | ... | @@ -192,9 +260,11 @@ |
192 | 260 | :deep(.vben-basic-tree) { |
193 | 261 | width: 100% !important; |
194 | 262 | } |
263 | + | |
195 | 264 | :deep(.is-unflod) { |
196 | 265 | display: none !important; |
197 | 266 | } |
267 | + | |
198 | 268 | :deep(.is-flod) { |
199 | 269 | display: none !important; |
200 | 270 | } | ... | ... |