refactor: 优化代码

This commit is contained in:
dap 2025-01-04 19:13:54 +08:00
parent e838537356
commit a48a7a9444
3 changed files with 133 additions and 92 deletions

View File

@ -21,6 +21,11 @@ const menuTypes = {
M: { icon: markRaw(FolderIcon), value: '目录' }, M: { icon: markRaw(FolderIcon), value: '目录' },
}; };
export const nodeOptions = [
{ label: '节点关联', value: true },
{ label: '节点独立', value: false },
];
export const columns: VxeGridProps['columns'] = [ export const columns: VxeGridProps['columns'] = [
{ {
type: 'checkbox', type: 'checkbox',

View File

@ -0,0 +1,74 @@
import type { MenuOption } from '#/api/system/menu/model';
import type { MenuPermissionOption } from './data';
import { eachTree } from '@vben/utils';
import { difference } from 'lodash-es';
/**
*
* @param record
* @param checked
*/
export function setPermissionsChecked(
record: MenuPermissionOption,
checked: boolean,
) {
if (record?.permissions?.length > 0) {
// 全部设置为选中
record.permissions.forEach((permission) => {
permission.checked = checked;
});
}
}
/**
* &
* @param record
* @param checked
*/
export function rowAndChildrenChecked(
record: MenuPermissionOption,
checked: boolean,
) {
// 当前行选中
setPermissionsChecked(record, checked);
// 所有子节点选中
record?.children?.forEach?.((permission) => {
rowAndChildrenChecked(permission as MenuPermissionOption, checked);
});
}
/**
* void方法
* tree+permissions结构
* @param menus menu
*/
export function menusWithPermissions(menus: MenuOption[]) {
eachTree(menus, (item: MenuPermissionOption) => {
if (item.children && item.children.length > 0) {
/**
*
* item.menuType !== 'M'
* children添加而非加到permissions
*/
const permissions = item.children.filter(
(child: MenuOption) => child.menuType === 'F' && item.menuType !== 'M',
);
// 取差集
const diffCollection = difference(item.children, permissions);
// 更新后的children 即去除按钮
item.children = diffCollection;
// permissions作为字段添加到item
const permissionsArr = permissions.map((permission) => {
return {
id: permission.id,
label: permission.label,
checked: false,
};
});
item.permissions = permissionsArr;
}
});
}

View File

@ -2,15 +2,16 @@
import type { VxeGridProps } from '#/adapter/vxe-table'; import type { VxeGridProps } from '#/adapter/vxe-table';
import type { MenuOption } from '#/api/system/menu/model'; import type { MenuOption } from '#/api/system/menu/model';
import type { MenuPermissionOption, Permission } from './data'; import type { MenuPermissionOption } from './data';
import { useVbenVxeGrid } from '#/adapter/vxe-table'; import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { cloneDeep, eachTree, findGroupParentIds } from '@vben/utils'; import { cloneDeep, findGroupParentIds } from '@vben/utils';
import { Alert, Checkbox, RadioGroup, Space } from 'ant-design-vue'; import { Alert, Checkbox, RadioGroup, Space } from 'ant-design-vue';
import { difference, uniq } from 'lodash-es'; import { uniq } from 'lodash-es';
import { nextTick, onMounted, ref, watch } from 'vue'; import { nextTick, onMounted, ref, watch } from 'vue';
import { columns } from './data'; import { columns, nodeOptions } from './data';
import { menusWithPermissions, rowAndChildrenChecked } from './helper';
defineOptions({ defineOptions({
name: 'MenuSelectTable', name: 'MenuSelectTable',
@ -87,31 +88,10 @@ const gridOptions: VxeGridProps = {
rowField: 'id', rowField: 'id',
transform: false, transform: false,
}, },
//
showOverflow: false, showOverflow: false,
}; };
/**
* 设置是否全选
* @param record 行记录
* @param checked 是否选中
*/
function setPermissionsChecked(record: MenuPermissionOption, checked: boolean) {
if (record?.permissions?.length > 0) {
//
record.permissions.forEach((permission: Permission) => {
permission.checked = checked;
});
}
}
//
function allChecked(record: MenuPermissionOption, checked: boolean) {
setPermissionsChecked(record, checked);
record.children?.forEach((permission) => {
allChecked(permission as MenuPermissionOption, checked);
});
}
/** /**
* 用于界面显示选中的数量 * 用于界面显示选中的数量
*/ */
@ -126,6 +106,7 @@ function updateCheckedLength() {
const [BasicTable, tableApi] = useVbenVxeGrid({ const [BasicTable, tableApi] = useVbenVxeGrid({
gridOptions, gridOptions,
gridEvents: { gridEvents: {
//
checkboxChange: (params) => { checkboxChange: (params) => {
// //
if (!association.value) { if (!association.value) {
@ -137,63 +118,30 @@ const [BasicTable, tableApi] = useVbenVxeGrid({
// //
const record = params.row; const record = params.row;
// //
allChecked(record, checked); rowAndChildrenChecked(record, checked);
updateCheckedLength(); updateCheckedLength();
}, },
//
checkboxAll: (params) => { checkboxAll: (params) => {
const records = params.$grid.getData(); const records = params.$grid.getData();
records.forEach((item) => { records.forEach((item) => {
allChecked(item, params.checked); rowAndChildrenChecked(item, params.checked);
}); });
updateCheckedLength(); updateCheckedLength();
}, },
}, },
}); });
/**
* void方法 会直接修改原始数据
* 将树结构转为 tree+permissions结构
* @param menus 后台返回的menu
*/
function menusWithPermissions(menus: MenuOption[]) {
eachTree(menus, (item: MenuPermissionOption) => {
if (item.children && item.children.length > 0) {
/**
* 所有为按钮的节点提取出来
* 需要注意 这里需要过滤目录下直接是按钮的情况item.menuType !== 'M'
* 将按钮往children添加而非加到permissions
*/
const permissions = item.children.filter(
(child: MenuOption) => child.menuType === 'F' && item.menuType !== 'M',
);
//
const diffCollection = difference(item.children, permissions);
// children
item.children = diffCollection;
// permissionsitem
const permissionsArr = permissions.map((permission) => {
return {
id: permission.id,
label: permission.label,
checked: false,
};
});
item.permissions = permissionsArr;
}
});
}
/** /**
* 设置表格选中 * 设置表格选中
* @param menus menu * @param menus menu
* @param keys 选中的key * @param keys 选中的key
* @param handleChildren 节点独立情况 不需要处理children * @param triggerOnchange 节点独立情况 不需要触发onChange(false)
*/ */
function setCheckedByKeys( function setCheckedByKeys(
menus: MenuPermissionOption[], menus: MenuPermissionOption[],
keys: (number | string)[], keys: (number | string)[],
handleChildren: boolean, triggerOnchange: boolean,
) { ) {
menus.forEach((item) => { menus.forEach((item) => {
// //
@ -202,24 +150,25 @@ function setCheckedByKeys(
} }
// columns // columns
if (item.permissions && item.permissions.length > 0) { if (item.permissions && item.permissions.length > 0) {
//
item.permissions.forEach((permission) => { item.permissions.forEach((permission) => {
if (keys.includes(permission.id)) { if (keys.includes(permission.id)) {
permission.checked = true; permission.checked = true;
// onChange // onChange
handleChildren && handlePermissionChange(item); triggerOnchange && handlePermissionChange(item);
} }
}); });
} }
// children // children
if (item.children && item.children.length > 0) { if (item.children && item.children.length > 0) {
setCheckedByKeys(item.children as any, keys, handleChildren); setCheckedByKeys(item.children as any, keys, triggerOnchange);
} }
}); });
} }
onMounted(() => { onMounted(() => {
/** /**
* 加载表格数据 * 加载表格数据 转为指定结构
*/ */
watch( watch(
() => props.menus, () => props.menus,
@ -228,15 +177,16 @@ onMounted(() => {
menusWithPermissions(clonedMenus); menusWithPermissions(clonedMenus);
console.log(clonedMenus); console.log(clonedMenus);
await tableApi.grid.loadData(clonedMenus); await tableApi.grid.loadData(clonedMenus);
await nextTick(); // true
if (props.defaultExpandAll) { if (props.defaultExpandAll) {
await nextTick();
setExpandOrCollapse(true); setExpandOrCollapse(true);
} }
}, },
); );
/** /**
* 节点关联设置表格勾选效果 * 节点关联变动 更新表格勾选效果
*/ */
watch(association, (value) => { watch(association, (value) => {
tableApi.setGridOptions({ tableApi.setGridOptions({
@ -247,33 +197,35 @@ onMounted(() => {
}); });
/** /**
* checkedKeys依赖menus 要在外部确保menus先加载 * checkedKeys依赖menus
* 要注意加载顺序
* !!!要在外部确保menus先加载!!!
*/ */
watch( watch(
() => props.checkedKeys, () => props.checkedKeys,
(value) => { (value) => {
const allCheckedKeys = uniq([...value]); const allCheckedKeys = uniq([...value]);
// // data checkedKeysmenuswatch
const records = tableApi.grid.getData(); const records = tableApi.grid.getData();
setCheckedByKeys(records, allCheckedKeys, association.value); setCheckedByKeys(records, allCheckedKeys, association.value);
}, },
); );
}); });
const options = [ /**
{ label: '节点关联', value: true }, * 节点关联变动 事件
{ label: '节点独立', value: false }, */
];
async function handleAssociationChange() { async function handleAssociationChange() {
// permissions // permissions
const records = tableApi.grid.getData(); const records = tableApi.grid.getData();
records.forEach((item) => { records.forEach((item) => {
allChecked(item, false); rowAndChildrenChecked(item, false);
}); });
// //
await tableApi.grid.clearCheckboxRow(); await tableApi.grid.clearCheckboxRow();
updateCheckedLength(); updateCheckedLength();
//
await tableApi.grid.scrollTo(0, 0);
} }
/** /**
@ -284,6 +236,10 @@ function setExpandOrCollapse(expand: boolean) {
tableApi.grid?.setAllTreeExpand(expand); tableApi.grid?.setAllTreeExpand(expand);
} }
/**
* 权限列表 checkbox勾选的事件
* @param row
*/
function handlePermissionChange(row: any) { function handlePermissionChange(row: any) {
// //
if (association.value) { if (association.value) {
@ -305,21 +261,20 @@ function handlePermissionChange(row: any) {
/** /**
* 获取勾选的key * 获取勾选的key
* @param records 行记录 * @param records 行记录列表
* @param addCurrent 是否添加当前行的id
*/ */
function getKeys(records: MenuPermissionOption[], handleChildren: boolean) { function getKeys(records: MenuPermissionOption[], addCurrent: boolean) {
const allKeys: (number | string)[] = []; const allKeys: (number | string)[] = [];
records.forEach((item) => { records.forEach((item) => {
// children
if (item.children && item.children.length > 0) { if (item.children && item.children.length > 0) {
const keys = getKeys( const keys = getKeys(item.children as MenuPermissionOption[], addCurrent);
item.children as MenuPermissionOption[],
handleChildren,
);
allKeys.push(...keys); allKeys.push(...keys);
} else { } else {
// id // id
handleChildren && allKeys.push(item.id); addCurrent && allKeys.push(item.id);
// id // id
if (item.permissions && item.permissions.length > 0) { if (item.permissions && item.permissions.length > 0) {
const ids = item.permissions const ids = item.permissions
.filter((m) => m.checked === true) .filter((m) => m.checked === true)
@ -340,8 +295,9 @@ function getCheckedKeys() {
const records = tableApi?.grid?.getCheckboxRecords?.() ?? []; const records = tableApi?.grid?.getCheckboxRecords?.() ?? [];
// //
const nodeKeys = getKeys(records, true); const nodeKeys = getKeys(records, true);
// //
const parentIds = findGroupParentIds(props.menus, nodeKeys as number[]); const parentIds = findGroupParentIds(props.menus, nodeKeys as number[]);
//
const realKeys = uniq([...parentIds, ...nodeKeys]); const realKeys = uniq([...parentIds, ...nodeKeys]);
return realKeys; return realKeys;
} }
@ -351,12 +307,18 @@ function getCheckedKeys() {
const records = tableApi?.grid?.getCheckboxRecords?.() ?? []; const records = tableApi?.grid?.getCheckboxRecords?.() ?? [];
// permissions // permissions
const allRecords = tableApi?.grid?.getData?.() ?? []; const allRecords = tableApi?.grid?.getData?.() ?? [];
const ids = records.map((item) => item.id); // ids
const permissions = getKeys(allRecords, false); const checkedIds = records.map((item) => item.id);
const allIds = uniq([...ids, ...permissions]); // ids
const permissionIds = getKeys(allRecords, false);
//
const allIds = uniq([...checkedIds, ...permissionIds]);
return allIds; return allIds;
} }
/**
* 暴露给外部使用 获取已选中的key
*/
defineExpose({ defineExpose({
getCheckedKeys, getCheckedKeys,
}); });
@ -369,12 +331,12 @@ defineExpose({
<template #toolbar-actions> <template #toolbar-actions>
<RadioGroup <RadioGroup
v-model:value="association" v-model:value="association"
:options="options" :options="nodeOptions"
button-style="solid" button-style="solid"
option-type="button" option-type="button"
@change="handleAssociationChange" @change="handleAssociationChange"
/> />
<Alert class="mx-2" type="info" show-icon> <Alert class="mx-2" type="info">
<template #message> <template #message>
<div v-if="tableApi?.grid"> <div v-if="tableApi?.grid">
已选中 已选中