fix: 删除菜单包括子级
This commit is contained in:
@@ -40,7 +40,7 @@
|
|||||||
<!-- RPC 相关 -->
|
<!-- RPC 相关 -->
|
||||||
<!-- Config 配置中心相关 -->
|
<!-- Config 配置中心相关 -->
|
||||||
<!-- Job 定时任务相关 -->
|
<!-- 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>
|
<lock4j.version>2.2.7</lock4j.version>
|
||||||
<!-- 监控相关 -->
|
<!-- 监控相关 -->
|
||||||
|
|||||||
@@ -95,7 +95,10 @@ spring:
|
|||||||
xxl:
|
xxl:
|
||||||
job:
|
job:
|
||||||
admin:
|
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:
|
executor:
|
||||||
appname: ${spring.application.name} # 执行器 AppName
|
appname: ${spring.application.name} # 执行器 AppName
|
||||||
logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径
|
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 = "删除菜单")
|
@Operation(summary = "删除菜单")
|
||||||
@Parameter(name = "id", description = "菜单编号", required= true, example = "1024")
|
@Parameter(name = "id", description = "菜单编号", required= true, example = "1024")
|
||||||
@PreAuthorize("@ss.hasPermission('system:menu:delete')")
|
@PreAuthorize("@ss.hasPermission('system:menu:delete')")
|
||||||
public CommonResult<Boolean> deleteMenu(@RequestParam("id") Long id) {
|
public CommonResult<Boolean> deleteMenu(@RequestParam("id") Long id,
|
||||||
menuService.deleteMenu(id);
|
@RequestParam(value = "cascade", defaultValue = "false") boolean cascade) {
|
||||||
|
menuService.deleteMenu(id, cascade);
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,10 @@ public interface MenuService {
|
|||||||
/**
|
/**
|
||||||
* 删除菜单
|
* 删除菜单
|
||||||
*
|
*
|
||||||
* @param id 菜单编号
|
* @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)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST,
|
@CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST,
|
||||||
allEntries = true) // allEntries 清空所有缓存,因为此时不知道 id 对应的 permission 是多少。直接清理,简单有效
|
allEntries = true) // allEntries 清空所有缓存,因为此时不知道 id 对应的 permission 是多少。直接清理,简单有效
|
||||||
public void deleteMenu(Long id) {
|
public void deleteMenu(Long id, boolean cascade) {
|
||||||
// 校验是否还有子菜单
|
|
||||||
if (menuMapper.selectCountByParentId(id) > 0) {
|
|
||||||
throw exception(MENU_EXISTS_CHILDREN);
|
|
||||||
}
|
|
||||||
// 校验删除的菜单是否存在
|
// 校验删除的菜单是否存在
|
||||||
if (menuMapper.selectById(id) == null) {
|
if (menuMapper.selectById(id) == null) {
|
||||||
throw exception(MENU_NOT_EXISTS);
|
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);
|
menuMapper.deleteById(id);
|
||||||
// 删除授予给角色的权限
|
// 删除授予给角色的权限
|
||||||
permissionService.processMenuDeleted(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
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST,
|
@CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST,
|
||||||
|
|||||||
@@ -96,6 +96,9 @@ xxl:
|
|||||||
job:
|
job:
|
||||||
admin:
|
admin:
|
||||||
addresses: http://192.168.10.14:8080/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:
|
executor:
|
||||||
appname: ${spring.application.name} # 执行器 AppName
|
appname: ${spring.application.name} # 执行器 AppName
|
||||||
logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径
|
logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径
|
||||||
accessToken: default_token # 执行器通讯TOKEN
|
accessToken: 123456 # 执行器通讯TOKEN
|
||||||
|
|
||||||
--- #################### 验证码相关配置 ####################
|
--- #################### 验证码相关配置 ####################
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,10 @@ xxl:
|
|||||||
enabled: false # 是否开启调度中心,默认为 true 开启
|
enabled: false # 是否开启调度中心,默认为 true 开启
|
||||||
admin:
|
admin:
|
||||||
addresses: http://192.168.10.14:8080/xxl-job-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) {
|
export async function deleteMenu(id: number, cascade?: boolean) {
|
||||||
return requestClient.delete(`/system/menu/delete?id=${id}`);
|
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 { SystemMenuTypeEnum } from '@vben/constants';
|
||||||
import { IconifyIcon } from '@vben/icons';
|
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 { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||||
import { deleteMenu, getMenuList } from '#/api/system/menu';
|
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({
|
const hideLoading = message.loading({
|
||||||
content: $t('ui.actionMessage.deleting', [row.name]),
|
content: $t('ui.actionMessage.deleting', [row.name]),
|
||||||
duration: 0,
|
duration: 0,
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteMenu(row.id!);
|
await deleteMenu(row.id!, cascade);
|
||||||
message.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
message.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||||
handleRefresh();
|
handleRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
@@ -161,10 +183,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
danger: true,
|
danger: true,
|
||||||
icon: ACTION_ICON.DELETE,
|
icon: ACTION_ICON.DELETE,
|
||||||
auth: ['system:menu:delete'],
|
auth: ['system:menu:delete'],
|
||||||
popConfirm: {
|
onClick: handleDelete.bind(null, row),
|
||||||
title: $t('ui.actionMessage.deleteConfirm', [row.name]),
|
|
||||||
confirm: handleDelete.bind(null, row),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user