fix: 删除菜单包括子级
This commit is contained in:
@@ -40,7 +40,7 @@
|
||||
<!-- RPC 相关 -->
|
||||
<!-- Config 配置中心相关 -->
|
||||
<!-- Job 定时任务相关 -->
|
||||
<xxl-job.version>2.4.0</xxl-job.version>
|
||||
<xxl-job.version>2.4.2</xxl-job.version>
|
||||
<!-- 服务保障相关 -->
|
||||
<lock4j.version>2.2.7</lock4j.version>
|
||||
<!-- 监控相关 -->
|
||||
|
||||
@@ -95,7 +95,10 @@ spring:
|
||||
xxl:
|
||||
job:
|
||||
admin:
|
||||
addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址
|
||||
addresses: http://192.168.10.14:8080/xxl-job-admin # 调度中心部署跟地址
|
||||
executor:
|
||||
ip: 192.168.10.14
|
||||
port: 9991
|
||||
|
||||
--- #################### 服务保障相关配置 ####################
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ xxl:
|
||||
executor:
|
||||
appname: ${spring.application.name} # 执行器 AppName
|
||||
logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径
|
||||
accessToken: default_token # 执行器通讯TOKEN
|
||||
accessToken: 123456 # 执行器通讯TOKEN
|
||||
|
||||
--- #################### 芋道相关配置 ####################
|
||||
|
||||
|
||||
@@ -52,8 +52,9 @@ public class MenuController {
|
||||
@Operation(summary = "删除菜单")
|
||||
@Parameter(name = "id", description = "菜单编号", required= true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:menu:delete')")
|
||||
public CommonResult<Boolean> deleteMenu(@RequestParam("id") Long id) {
|
||||
menuService.deleteMenu(id);
|
||||
public CommonResult<Boolean> deleteMenu(@RequestParam("id") Long id,
|
||||
@RequestParam(value = "cascade", defaultValue = "false") boolean cascade) {
|
||||
menuService.deleteMenu(id, cascade);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,9 @@ public interface MenuService {
|
||||
* 删除菜单
|
||||
*
|
||||
* @param id 菜单编号
|
||||
* @param cascade 是否级联删除子菜单
|
||||
*/
|
||||
void deleteMenu(Long id);
|
||||
void deleteMenu(Long id, boolean cascade);
|
||||
|
||||
/**
|
||||
* 批量删除菜单
|
||||
|
||||
@@ -89,21 +89,43 @@ public class MenuServiceImpl implements MenuService {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST,
|
||||
allEntries = true) // allEntries 清空所有缓存,因为此时不知道 id 对应的 permission 是多少。直接清理,简单有效
|
||||
public void deleteMenu(Long id) {
|
||||
// 校验是否还有子菜单
|
||||
if (menuMapper.selectCountByParentId(id) > 0) {
|
||||
throw exception(MENU_EXISTS_CHILDREN);
|
||||
}
|
||||
public void deleteMenu(Long id, boolean cascade) {
|
||||
// 校验删除的菜单是否存在
|
||||
if (menuMapper.selectById(id) == null) {
|
||||
throw exception(MENU_NOT_EXISTS);
|
||||
}
|
||||
// 校验是否还有子菜单
|
||||
if (menuMapper.selectCountByParentId(id) > 0) {
|
||||
if (!cascade) {
|
||||
throw exception(MENU_EXISTS_CHILDREN);
|
||||
}
|
||||
// 级联删除:递归收集所有子菜单 ID
|
||||
List<Long> childIds = new ArrayList<>();
|
||||
collectChildMenuIds(id, childIds);
|
||||
// 先删除子菜单,再删父菜单
|
||||
menuMapper.deleteByIds(childIds);
|
||||
childIds.forEach(childId -> permissionService.processMenuDeleted(childId));
|
||||
}
|
||||
// 标记删除
|
||||
menuMapper.deleteById(id);
|
||||
// 删除授予给角色的权限
|
||||
permissionService.processMenuDeleted(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归收集所有子菜单 ID
|
||||
*
|
||||
* @param parentId 父菜单 ID
|
||||
* @param result 收集结果
|
||||
*/
|
||||
private void collectChildMenuIds(Long parentId, List<Long> result) {
|
||||
List<MenuDO> children = menuMapper.selectList(MenuDO::getParentId, parentId);
|
||||
for (MenuDO child : children) {
|
||||
result.add(child.getId());
|
||||
collectChildMenuIds(child.getId(), result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST,
|
||||
|
||||
@@ -96,6 +96,9 @@ xxl:
|
||||
job:
|
||||
admin:
|
||||
addresses: http://192.168.10.14:8080/xxl-job-admin # 调度中心部署跟地址
|
||||
executor:
|
||||
ip: 192.168.10.14
|
||||
port: 9992
|
||||
|
||||
--- #################### 服务保障相关配置 ####################
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ xxl:
|
||||
executor:
|
||||
appname: ${spring.application.name} # 执行器 AppName
|
||||
logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径
|
||||
accessToken: default_token # 执行器通讯TOKEN
|
||||
accessToken: 123456 # 执行器通讯TOKEN
|
||||
|
||||
--- #################### 验证码相关配置 ####################
|
||||
|
||||
|
||||
@@ -71,6 +71,10 @@ xxl:
|
||||
enabled: false # 是否开启调度中心,默认为 true 开启
|
||||
admin:
|
||||
addresses: http://192.168.10.14:8080/xxl-job-admin # 调度中心部署跟地址
|
||||
executor:
|
||||
appname: nl-lms-server
|
||||
ip: 192.168.10.14
|
||||
port: 9992
|
||||
|
||||
--- #################### 消息队列相关 ####################
|
||||
|
||||
|
||||
@@ -49,8 +49,8 @@ export async function updateMenu(data: SystemMenuApi.Menu) {
|
||||
}
|
||||
|
||||
/** 删除菜单 */
|
||||
export async function deleteMenu(id: number) {
|
||||
return requestClient.delete(`/system/menu/delete?id=${id}`);
|
||||
export async function deleteMenu(id: number, cascade?: boolean) {
|
||||
return requestClient.delete(`/system/menu/delete?id=${id}&cascade=${cascade || false}`);
|
||||
}
|
||||
|
||||
/** 批量删除菜单 */
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Page, useVbenModal } from '@vben/common-ui';
|
||||
import { SystemMenuTypeEnum } from '@vben/constants';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { message } from 'antdv-next';
|
||||
import { message, Modal } from 'antdv-next';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { deleteMenu, getMenuList } from '#/api/system/menu';
|
||||
@@ -43,13 +43,35 @@ function handleEdit(row: SystemMenuApi.Menu) {
|
||||
}
|
||||
|
||||
/** 删除菜单 */
|
||||
async function handleDelete(row: SystemMenuApi.Menu) {
|
||||
function handleDelete(row: SystemMenuApi.Menu) {
|
||||
const hasChildren = (row as any).children?.length > 0;
|
||||
if (hasChildren) {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '该菜单存在子菜单,是否连子级一起删除?',
|
||||
okText: '是',
|
||||
cancelText: '否',
|
||||
onOk: () => doDelete(row, true),
|
||||
});
|
||||
} else {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: $t('ui.actionMessage.deleteConfirm', [row.name]),
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => doDelete(row, false),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** 执行菜单删除 */
|
||||
async function doDelete(row: SystemMenuApi.Menu, cascade: boolean) {
|
||||
const hideLoading = message.loading({
|
||||
content: $t('ui.actionMessage.deleting', [row.name]),
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await deleteMenu(row.id!);
|
||||
await deleteMenu(row.id!, cascade);
|
||||
message.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
handleRefresh();
|
||||
} finally {
|
||||
@@ -161,10 +183,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
danger: true,
|
||||
icon: ACTION_ICON.DELETE,
|
||||
auth: ['system:menu:delete'],
|
||||
popConfirm: {
|
||||
title: $t('ui.actionMessage.deleteConfirm', [row.name]),
|
||||
confirm: handleDelete.bind(null, row),
|
||||
},
|
||||
onClick: handleDelete.bind(null, row),
|
||||
},
|
||||
]"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user