Commit d123ed23119eddd5c9dde891f2b978e77c81df69

Authored by xp.Huang
2 parents 195ab9cb 1a768272

Merge branch 'ww' into 'main'

fix: BUG in teambition && perf code

See merge request huang/yun-teng-iot-front!456
@@ -14,6 +14,7 @@ @@ -14,6 +14,7 @@
14 "PROTOBUF", 14 "PROTOBUF",
15 "SNMP", 15 "SNMP",
16 "unref", 16 "unref",
  17 + "vben",
17 "VITE" 18 "VITE"
18 ] 19 ]
19 } 20 }
@@ -34,7 +34,7 @@ enum DeviceManagerApi { @@ -34,7 +34,7 @@ enum DeviceManagerApi {
34 } 34 }
35 35
36 export const devicePage = (params: DeviceQueryParam) => { 36 export const devicePage = (params: DeviceQueryParam) => {
37 - return defHttp.get<DeviceModel>({ 37 + return defHttp.get<PaginationResult<DeviceModel>>({
38 url: DeviceManagerApi.DEVICE_URL, 38 url: DeviceManagerApi.DEVICE_URL,
39 params, 39 params,
40 }); 40 });
@@ -80,10 +80,9 @@ export const deleteDevice = (ids: string[]) => { @@ -80,10 +80,9 @@ export const deleteDevice = (ids: string[]) => {
80 * 查询设备配置 80 * 查询设备配置
81 * @param params pageSize page name 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 url: DeviceManagerApi.DEVICE_PROFILE_URL_ME, 85 url: DeviceManagerApi.DEVICE_PROFILE_URL_ME,
86 - params,  
87 }); 86 });
88 }; 87 };
89 88
@@ -18,3 +18,32 @@ export interface RouteItem { @@ -18,3 +18,32 @@ export interface RouteItem {
18 * @description: Get menu return value 18 * @description: Get menu return value
19 */ 19 */
20 export type getMenuListResultModel = RouteItem[]; 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,9 +181,9 @@
181 const newItem = JSON.parse(getItem); 181 const newItem = JSON.parse(getItem);
182 updataPersonlData.value = newItem; 182 updataPersonlData.value = newItem;
183 }; 183 };
184 -  
185 - const [registerModal, { closeModal }] = useModalInner(async (data) => { 184 + const [registerModal, { closeModal }] = useModalInner(async () => {
186 refreshCacheGetData(); 185 refreshCacheGetData();
  186 + const userInfo = userStore.getUserInfo;
187 try { 187 try {
188 if (updataPersonlData.value != null) { 188 if (updataPersonlData.value != null) {
189 (peresonalPic.value = updataPersonlData.value.avatar), 189 (peresonalPic.value = updataPersonlData.value.avatar),
@@ -194,13 +194,13 @@ @@ -194,13 +194,13 @@
194 }); 194 });
195 getPersonalDetailValue.value = updataPersonlData.value; 195 getPersonalDetailValue.value = updataPersonlData.value;
196 } else { 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 setFieldsValue({ 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,10 +62,18 @@ export const step1Schemas: FormSchema[] = [
62 label: '所属产品', 62 label: '所属产品',
63 required: true, 63 required: true,
64 component: 'ApiSelect', 64 component: 'ApiSelect',
65 - componentProps: ({ formActionType }) => { 65 + componentProps: ({ formActionType, formModel }) => {
66 const { setFieldsValue } = formActionType; 66 const { setFieldsValue } = formActionType;
67 return { 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 labelField: 'name', 77 labelField: 'name',
70 valueField: 'tbProfileId', 78 valueField: 'tbProfileId',
71 onChange( 79 onChange(
@@ -148,6 +156,7 @@ export const step1Schemas: FormSchema[] = [ @@ -148,6 +156,7 @@ export const step1Schemas: FormSchema[] = [
148 ifShow: ({ values }) => values.deviceType === 'SENSOR' && values.organizationId, 156 ifShow: ({ values }) => values.deviceType === 'SENSOR' && values.organizationId,
149 componentProps: ({ formModel }) => { 157 componentProps: ({ formModel }) => {
150 const { organizationId, transportType } = formModel; 158 const { organizationId, transportType } = formModel;
  159 + if (![organizationId, transportType].every(Boolean)) return {};
151 return { 160 return {
152 api: getGatewayDevice, 161 api: getGatewayDevice,
153 showSearch: true, 162 showSearch: true,
@@ -224,31 +224,33 @@ @@ -224,31 +224,33 @@
224 const [registerTbDetailDrawer, { openDrawer: openTbDeviceDrawer }] = useDrawer(); 224 const [registerTbDetailDrawer, { openDrawer: openTbDeviceDrawer }] = useDrawer();
225 const [registerGatewayDetailDrawer, { openDrawer: openGatewayDetailDrawer }] = useDrawer(); 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 const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } = 254 const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } =
253 useBatchDelete(deleteDevice, handleSuccess, setProps); 255 useBatchDelete(deleteDevice, handleSuccess, setProps);
254 selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => { 256 selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
@@ -275,14 +277,15 @@ @@ -275,14 +277,15 @@
275 const deviceProfileId = ref(''); 277 const deviceProfileId = ref('');
276 count.value = Number(getParams('count')); 278 count.value = Number(getParams('count'));
277 deviceProfileId.value = getParams('deviceProfileId') || ''; 279 deviceProfileId.value = getParams('deviceProfileId') || '';
278 - console.log(deviceProfileId.value); 280 +
279 const setRowClassName = async () => { 281 const setRowClassName = async () => {
280 if (deviceProfileId.value !== undefined) { 282 if (deviceProfileId.value !== undefined) {
281 - const { items } = await devicePage({ 283 + const { items, total } = await devicePage({
282 page: 1, 284 page: 1,
283 pageSize: count.value === 0 ? 10 : count.value, 285 pageSize: count.value === 0 ? 10 : count.value,
284 deviceProfileId: deviceProfileId.value, 286 deviceProfileId: deviceProfileId.value,
285 }); 287 });
  288 + setPagination({ total });
286 nextTick(() => { 289 nextTick(() => {
287 setTableData(items); 290 setTableData(items);
288 const { setFieldsValue, resetFields } = getForm(); 291 const { setFieldsValue, resetFields } = getForm();
@@ -9,18 +9,20 @@ @@ -9,18 +9,20 @@
9 > 9 >
10 <BasicForm @register="registerForm"> 10 <BasicForm @register="registerForm">
11 <template #menu> 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 </template> 26 </template>
25 </BasicForm> 27 </BasicForm>
26 </BasicDrawer> 28 </BasicDrawer>
@@ -28,7 +30,7 @@ @@ -28,7 +30,7 @@
28 <script lang="ts"> 30 <script lang="ts">
29 import { defineComponent, ref, computed, unref, nextTick } from 'vue'; 31 import { defineComponent, ref, computed, unref, nextTick } from 'vue';
30 import { BasicForm, useForm } from '/@/components/Form/index'; 32 import { BasicForm, useForm } from '/@/components/Form/index';
31 - import { formSchema } from './role.data'; 33 + import { formSchema, KeysTypeEnum, RoleMenuDictEnum } from './role.data';
32 import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; 34 import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
33 import { BasicTree, TreeItem } from '/@/components/Tree'; 35 import { BasicTree, TreeItem } from '/@/components/Tree';
34 import { useMessage } from '/@/hooks/web/useMessage'; 36 import { useMessage } from '/@/hooks/web/useMessage';
@@ -36,22 +38,29 @@ @@ -36,22 +38,29 @@
36 // 加载菜单数据 38 // 加载菜单数据
37 import { getMenuList, getMenusIdsByRoleId } from '/@/api/sys/menu'; 39 import { getMenuList, getMenusIdsByRoleId } from '/@/api/sys/menu';
38 import { useI18n } from '/@/hooks/web/useI18n'; 40 import { useI18n } from '/@/hooks/web/useI18n';
39 - import { RouteItem } from '/@/api/sys/model/menuModel'; 41 + import { MenuRecord } from '/@/api/sys/model/menuModel';
40 import { saveOrUpdateRoleInfoWithMenu } from '/@/api/system/system'; 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 export default defineComponent({ 50 export default defineComponent({
42 name: 'RoleDrawer', 51 name: 'RoleDrawer',
43 - components: { BasicDrawer, BasicForm, BasicTree }, 52 + components: { BasicDrawer, BasicForm, BasicTree, Spin },
44 emits: ['success', 'register'], 53 emits: ['success', 'register'],
45 setup(_, { emit }) { 54 setup(_, { emit }) {
46 - const treeExpandData = ref([]); 55 + const treeExpandData = ref<string[]>([]);
47 const isUpdate = ref<boolean>(true); 56 const isUpdate = ref<boolean>(true);
48 - const treeData = ref<TreeItem[]>([]); 57 + const treeData = ref<TreeData[]>([]);
49 const roleMenus = ref<string[]>([]); 58 const roleMenus = ref<string[]>([]);
50 const allCheckedKeys = ref<string[]>([]); 59 const allCheckedKeys = ref<string[]>([]);
51 const roleId = ref<string>(''); 60 const roleId = ref<string>('');
52 const treeRef = ref(); 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 const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({ 65 const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
57 labelWidth: 100, 66 labelWidth: 100,
@@ -59,24 +68,19 @@ @@ -59,24 +68,19 @@
59 showActionButtonGroup: false, 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 const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => { 84 const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
81 allCheckedKeys.value = []; 85 allCheckedKeys.value = [];
82 originMenus.value = []; 86 originMenus.value = [];
@@ -84,53 +88,53 @@ @@ -84,53 +88,53 @@
84 resetFields(); 88 resetFields();
85 roleId.value = ''; 89 roleId.value = '';
86 // 在打开弹窗时清除所有选择的菜单 90 // 在打开弹窗时清除所有选择的菜单
87 - treeRef.value && treeRef.value.checkAll(false); 91 + treeRef.value && treeRef.value?.setCheckedKeys([]);
88 isUpdate.value = data.isUpdate; 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,7 +150,7 @@
146 name: values.name, 150 name: values.name,
147 remark: values.remark, 151 remark: values.remark,
148 status: values.status, 152 status: values.status,
149 - menu: allCheckedKeys.value.length ? allCheckedKeys.value : originMenus.value, 153 + menu: unref(treeRef).getCheckedKeys() || [],
150 }; 154 };
151 if (req.menu == undefined) return createMessage.error('请勾选权限菜单'); 155 if (req.menu == undefined) return createMessage.error('请勾选权限菜单');
152 saveOrUpdateRoleInfoWithMenu(req).then(() => { 156 saveOrUpdateRoleInfoWithMenu(req).then(() => {
@@ -165,7 +169,74 @@ @@ -165,7 +169,74 @@
165 allCheckedKeys.value = [...checkedNodes, ...halfCheckedKeys]; 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 return { 238 return {
  239 + spinning,
169 registerDrawer, 240 registerDrawer,
170 registerForm, 241 registerForm,
171 getTitle, 242 getTitle,
@@ -185,9 +256,11 @@ @@ -185,9 +256,11 @@
185 :deep(.vben-basic-tree) { 256 :deep(.vben-basic-tree) {
186 width: 100% !important; 257 width: 100% !important;
187 } 258 }
  259 +
188 :deep(.is-unflod) { 260 :deep(.is-unflod) {
189 display: none !important; 261 display: none !important;
190 } 262 }
  263 +
191 :deep(.is-flod) { 264 :deep(.is-flod) {
192 display: none !important; 265 display: none !important;
193 } 266 }
1 import { BasicColumn } from '/@/components/Table'; 1 import { BasicColumn } from '/@/components/Table';
2 import { FormSchema } from '/@/components/Table'; 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 export const columns: BasicColumn[] = [ 17 export const columns: BasicColumn[] = [
5 { 18 {
@@ -244,6 +244,7 @@ @@ -244,6 +244,7 @@
244 permissionStore.setPermCodeList(permissionList); 244 permissionStore.setPermCodeList(permissionList);
245 userStore.setUserInfo(userInfo); 245 userStore.setUserInfo(userInfo);
246 userStore.setRoleList(userInfo.roles as RoleEnum[]); 246 userStore.setRoleList(userInfo.roles as RoleEnum[]);
  247 + permissionStore.buildRoutesAction();
247 go(PageEnum.BASE_HOME); 248 go(PageEnum.BASE_HOME);
248 } catch (error) { 249 } catch (error) {
249 } finally { 250 } finally {
@@ -9,19 +9,21 @@ @@ -9,19 +9,21 @@
9 > 9 >
10 <BasicForm @register="registerForm"> 10 <BasicForm @register="registerForm">
11 <template #menu> 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 </template> 27 </template>
26 </BasicForm> 28 </BasicForm>
27 </BasicDrawer> 29 </BasicDrawer>
@@ -36,17 +38,22 @@ @@ -36,17 +38,22 @@
36 // 加载菜单数据 38 // 加载菜单数据
37 import { getMenuList, getMenusIdsByRoleId } from '/@/api/sys/menu'; 39 import { getMenuList, getMenusIdsByRoleId } from '/@/api/sys/menu';
38 import { useI18n } from '/@/hooks/web/useI18n'; 40 import { useI18n } from '/@/hooks/web/useI18n';
39 - import { RouteItem } from '/@/api/sys/model/menuModel'; 41 + import { MenuRecord } from '/@/api/sys/model/menuModel';
40 import { saveOrUpdateRoleInfoWithMenu } from '/@/api/system/system'; 42 import { saveOrUpdateRoleInfoWithMenu } from '/@/api/system/system';
41 import { RoleEnum } from '/@/enums/roleEnum'; 43 import { RoleEnum } from '/@/enums/roleEnum';
42 import { useMessage } from '/@/hooks/web/useMessage'; 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 export default defineComponent({ 51 export default defineComponent({
45 name: 'RoleDrawer', 52 name: 'RoleDrawer',
46 - components: { BasicDrawer, BasicForm, BasicTree }, 53 + components: { BasicDrawer, BasicForm, BasicTree, Spin },
47 emits: ['success', 'register'], 54 emits: ['success', 'register'],
48 setup(_, { emit }) { 55 setup(_, { emit }) {
49 - const treeExpandData = ref([]); 56 + const treeExpandData = ref<string[]>([]);
50 57
51 const isUpdate = ref(true); 58 const isUpdate = ref(true);
52 const treeData = ref<TreeItem[]>([]); 59 const treeData = ref<TreeItem[]>([]);
@@ -54,8 +61,8 @@ @@ -54,8 +61,8 @@
54 const allCheckedKeys = ref<string[]>([]); 61 const allCheckedKeys = ref<string[]>([]);
55 const roleId = ref(''); 62 const roleId = ref('');
56 const treeRef = ref(); 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 const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({ 67 const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
61 labelWidth: 90, 68 labelWidth: 90,
@@ -63,77 +70,71 @@ @@ -63,77 +70,71 @@
63 showActionButtonGroup: false, 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 const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => { 85 const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
85 - setDrawerProps({ confirmLoading: false });  
86 allCheckedKeys.value = []; 86 allCheckedKeys.value = [];
87 originMenus.value = []; 87 originMenus.value = [];
88 - treeExpandData.value;  
89 allCheckedKeys.value.length = 0; 88 allCheckedKeys.value.length = 0;
90 resetFields(); 89 resetFields();
91 roleId.value = ''; 90 roleId.value = '';
92 // 在打开弹窗时清除所有选择的菜单 91 // 在打开弹窗时清除所有选择的菜单
93 - treeRef.value && treeRef.value.checkAll(false); 92 + treeRef.value && treeRef.value?.setCheckedKeys([]);
94 isUpdate.value = data.isUpdate; 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 const getTitle = computed(() => (!unref(isUpdate) ? '新增角色' : '编辑角色')); 140 const getTitle = computed(() => (!unref(isUpdate) ? '新增角色' : '编辑角色'));
@@ -150,7 +151,7 @@ @@ -150,7 +151,7 @@
150 remark: values.remark, 151 remark: values.remark,
151 status: values.status, 152 status: values.status,
152 roleType: RoleEnum.TENANT_ADMIN, 153 roleType: RoleEnum.TENANT_ADMIN,
153 - menu: allCheckedKeys.value.length ? allCheckedKeys.value : originMenus.value, 154 + menu: unref(treeRef).getCheckedKeys() || [],
154 }; 155 };
155 if (req.menu == undefined) return createMessage.error('请勾选权限菜单'); 156 if (req.menu == undefined) return createMessage.error('请勾选权限菜单');
156 const res = await saveOrUpdateRoleInfoWithMenu(req); 157 const res = await saveOrUpdateRoleInfoWithMenu(req);
@@ -173,7 +174,74 @@ @@ -173,7 +174,74 @@
173 allCheckedKeys.value = [...checkedNodes, ...halfCheckedKeys]; 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 return { 243 return {
  244 + spinning,
177 registerDrawer, 245 registerDrawer,
178 registerForm, 246 registerForm,
179 getTitle, 247 getTitle,
@@ -192,9 +260,11 @@ @@ -192,9 +260,11 @@
192 :deep(.vben-basic-tree) { 260 :deep(.vben-basic-tree) {
193 width: 100% !important; 261 width: 100% !important;
194 } 262 }
  263 +
195 :deep(.is-unflod) { 264 :deep(.is-unflod) {
196 display: none !important; 265 display: none !important;
197 } 266 }
  267 +
198 :deep(.is-flod) { 268 :deep(.is-flod) {
199 display: none !important; 269 display: none !important;
200 } 270 }
@@ -40,6 +40,8 @@ export interface UserInfo { @@ -40,6 +40,8 @@ export interface UserInfo {
40 tenantName?: string; 40 tenantName?: string;
41 roles?: string[]; 41 roles?: string[];
42 plainRoles?: PlainRoleInfo[]; 42 plainRoles?: PlainRoleInfo[];
  43 + phoneNumber?: string;
  44 + email?: string;
43 } 45 }
44 46
45 export interface BeforeMiniState { 47 export interface BeforeMiniState {