From 5486f6e79d09a0813c69e8eef993ecbcffa52fcd Mon Sep 17 00:00:00 2001
From: liyongde <1419499670@qq.com>
Date: Thu, 9 Jul 2026 13:52:53 +0800
Subject: [PATCH] =?UTF-8?q?fix:=20=E5=88=A0=E9=99=A4=E8=8F=9C=E5=8D=95?=
=?UTF-8?q?=E5=8C=85=E6=8B=AC=E5=AD=90=E7=BA=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
nl-dependencies/pom.xml | 2 +-
.../src/main/resources/application-dev.yaml | 5 ++-
.../src/main/resources/application.yaml | 2 +-
.../admin/permission/MenuController.java | 5 +--
.../service/permission/MenuService.java | 5 +--
.../service/permission/MenuServiceImpl.java | 32 +++++++++++++++---
.../src/main/resources/application-dev.yaml | 3 ++
.../src/main/resources/application.yaml | 2 +-
.../src/main/resources/application-dev.yaml | 4 +++
.../src/api/system/menu/index.ts | 4 +--
.../src/views/system/menu/index.vue | 33 +++++++++++++++----
11 files changed, 75 insertions(+), 22 deletions(-)
diff --git a/nl-dependencies/pom.xml b/nl-dependencies/pom.xml
index 88efd25f..82657709 100644
--- a/nl-dependencies/pom.xml
+++ b/nl-dependencies/pom.xml
@@ -40,7 +40,7 @@
- 2.4.0
+ 2.4.2
2.2.7
diff --git a/nl-module-infra/nl-module-infra-server/src/main/resources/application-dev.yaml b/nl-module-infra/nl-module-infra-server/src/main/resources/application-dev.yaml
index 8a68ca23..6dabe13c 100644
--- a/nl-module-infra/nl-module-infra-server/src/main/resources/application-dev.yaml
+++ b/nl-module-infra/nl-module-infra-server/src/main/resources/application-dev.yaml
@@ -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
--- #################### 服务保障相关配置 ####################
diff --git a/nl-module-infra/nl-module-infra-server/src/main/resources/application.yaml b/nl-module-infra/nl-module-infra-server/src/main/resources/application.yaml
index 17979f30..36a7066f 100644
--- a/nl-module-infra/nl-module-infra-server/src/main/resources/application.yaml
+++ b/nl-module-infra/nl-module-infra-server/src/main/resources/application.yaml
@@ -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
--- #################### 芋道相关配置 ####################
diff --git a/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/controller/admin/permission/MenuController.java b/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/controller/admin/permission/MenuController.java
index 8e223d8d..34fcec2a 100644
--- a/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/controller/admin/permission/MenuController.java
+++ b/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/controller/admin/permission/MenuController.java
@@ -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 deleteMenu(@RequestParam("id") Long id) {
- menuService.deleteMenu(id);
+ public CommonResult deleteMenu(@RequestParam("id") Long id,
+ @RequestParam(value = "cascade", defaultValue = "false") boolean cascade) {
+ menuService.deleteMenu(id, cascade);
return success(true);
}
diff --git a/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/service/permission/MenuService.java b/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/service/permission/MenuService.java
index b684c183..543c4c02 100644
--- a/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/service/permission/MenuService.java
+++ b/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/service/permission/MenuService.java
@@ -32,9 +32,10 @@ public interface MenuService {
/**
* 删除菜单
*
- * @param id 菜单编号
+ * @param id 菜单编号
+ * @param cascade 是否级联删除子菜单
*/
- void deleteMenu(Long id);
+ void deleteMenu(Long id, boolean cascade);
/**
* 批量删除菜单
diff --git a/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/service/permission/MenuServiceImpl.java b/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/service/permission/MenuServiceImpl.java
index d3fc553a..70e22208 100644
--- a/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/service/permission/MenuServiceImpl.java
+++ b/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/service/permission/MenuServiceImpl.java
@@ -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 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 result) {
+ List 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,
diff --git a/nl-module-system/nl-module-system-server/src/main/resources/application-dev.yaml b/nl-module-system/nl-module-system-server/src/main/resources/application-dev.yaml
index 55f25a3f..8f34648a 100644
--- a/nl-module-system/nl-module-system-server/src/main/resources/application-dev.yaml
+++ b/nl-module-system/nl-module-system-server/src/main/resources/application-dev.yaml
@@ -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
--- #################### 服务保障相关配置 ####################
diff --git a/nl-module-system/nl-module-system-server/src/main/resources/application.yaml b/nl-module-system/nl-module-system-server/src/main/resources/application.yaml
index 32f1873e..2e123eff 100644
--- a/nl-module-system/nl-module-system-server/src/main/resources/application.yaml
+++ b/nl-module-system/nl-module-system-server/src/main/resources/application.yaml
@@ -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
--- #################### 验证码相关配置 ####################
diff --git a/nl-server/src/main/resources/application-dev.yaml b/nl-server/src/main/resources/application-dev.yaml
index a7c2ca9d..94b6b146 100644
--- a/nl-server/src/main/resources/application-dev.yaml
+++ b/nl-server/src/main/resources/application-dev.yaml
@@ -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
--- #################### 消息队列相关 ####################
diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/system/menu/index.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/system/menu/index.ts
index b296d815..cb1d5c7c 100644
--- a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/system/menu/index.ts
+++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/system/menu/index.ts
@@ -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}`);
}
/** 批量删除菜单 */
diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/system/menu/index.vue b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/system/menu/index.vue
index d01ec354..6395edc1 100644
--- a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/system/menu/index.vue
+++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/system/menu/index.vue
@@ -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),
},
]"
/>