后台菜单重构:菜单类型分组排序(软件在前/后台在后)、新增同类型末尾排序;任务中心分组移除,视频任务记录归入记录与版本、店铺数据记录归入店铺管理;界面名词优化(菜单权限配置/去重数据汇总/无效ASIN数据/视频任务记录/店铺数据记录/生成记录)
Build Backend JAR / build (push) Has been cancelled
Build Backend JAR / build (push) Has been cancelled
This commit is contained in:
+5
-5
@@ -49,15 +49,15 @@ public class PermissionMenuSchemaInitializer {
|
||||
|
||||
private static final List<DefaultAdminMenu> DEFAULT_ADMIN_MENUS = List.of(
|
||||
new DefaultAdminMenu("用户管理", "admin_users", "users", 10),
|
||||
new DefaultAdminMenu("栏目权限配置", "admin_columns", "columns", 20),
|
||||
new DefaultAdminMenu("数据去重总数据", "admin_dedupe_total_data", "dedupe-total-data", 30),
|
||||
new DefaultAdminMenu("不符合ASIN数据", "admin_invalid_asin_data", "invalid-asin-data", 35),
|
||||
new DefaultAdminMenu("菜单权限配置", "admin_columns", "columns", 20),
|
||||
new DefaultAdminMenu("去重数据汇总", "admin_dedupe_total_data", "dedupe-total-data", 30),
|
||||
new DefaultAdminMenu("无效ASIN数据", "admin_invalid_asin_data", "invalid-asin-data", 35),
|
||||
new DefaultAdminMenu("店铺密钥管理", "admin_shop_keys", "shop-keys", 40),
|
||||
new DefaultAdminMenu("店铺管理", "admin_shop_manage", "shop-manage", 50),
|
||||
new DefaultAdminMenu("跳过跟价ASIN", "admin_skip_price_asin", "skip-price-asin", 60),
|
||||
new DefaultAdminMenu("查询ASIN", "admin_query_asin", "query-asin", 65),
|
||||
new DefaultAdminMenu("商品类目", "admin_product_categories", "product-categories", 66),
|
||||
new DefaultAdminMenu("查看生成记录", "admin_history", "history", 70),
|
||||
new DefaultAdminMenu("生成记录", "admin_history", "history", 70),
|
||||
new DefaultAdminMenu("软件版本管理", "admin_version", "version", 80),
|
||||
new DefaultAdminMenu("数字人版本管理", "digital_human_version", "digital-human-version", 81)
|
||||
);
|
||||
@@ -179,7 +179,7 @@ public class PermissionMenuSchemaInitializer {
|
||||
private boolean ensureShopDataCrawlAdminDefaults() {
|
||||
executeQuietly("""
|
||||
INSERT INTO columns (name, column_key, menu_type, route_path, sort_order)
|
||||
SELECT '店铺数据任务管理', 'admin_shop_data_crawl_tasks', 'admin', 'shop-data-crawl-tasks', 82
|
||||
SELECT '店铺数据记录', 'admin_shop_data_crawl_tasks', 'admin', 'shop-data-crawl-tasks', 82
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM columns WHERE column_key = 'admin_shop_data_crawl_tasks'
|
||||
)
|
||||
|
||||
+3
-3
@@ -73,7 +73,7 @@ public class PermissionMenuService {
|
||||
String name = normalizeRequired(request.getName(), "菜单名称不能为空");
|
||||
String columnKey = normalizeRequired(request.getColumnKey(), "菜单标识不能为空");
|
||||
String menuType = normalizeMenuTypeRequired(request.getMenuType());
|
||||
String routePath = normalizeRequired(request.getRoutePath(), "菜单路由不能为空");
|
||||
String routePath = normalizeRequired(request.getRoutePath(), "页面路径不能为空");
|
||||
Long parentId = normalizeParentId(request.getParentId());
|
||||
ensureParentValid(parentId, null, menuType);
|
||||
ensureUniqueColumnKey(columnKey, null);
|
||||
@@ -106,7 +106,7 @@ public class PermissionMenuService {
|
||||
String name = normalizeRequired(request.getName(), "菜单名称不能为空");
|
||||
String columnKey = normalizeRequired(request.getColumnKey(), "菜单标识不能为空");
|
||||
String menuType = normalizeMenuTypeRequired(request.getMenuType());
|
||||
String routePath = normalizeRequired(request.getRoutePath(), "菜单路由不能为空");
|
||||
String routePath = normalizeRequired(request.getRoutePath(), "页面路径不能为空");
|
||||
Long parentId = normalizeParentId(request.getParentId());
|
||||
ensureParentValid(parentId, id, menuType);
|
||||
ensureMenuTypeChangeAllowed(entity, menuType);
|
||||
@@ -706,7 +706,7 @@ public class PermissionMenuService {
|
||||
.eq(PermissionMenuEntity::getRoutePath, routePath)
|
||||
.last("LIMIT 1"));
|
||||
if (exists != null && (excludeId == null || !excludeId.equals(exists.getId()))) {
|
||||
throw new BusinessException("同一菜单类型下的菜单路由已存在");
|
||||
throw new BusinessException("同一菜单类型下的页面路径已存在");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
-- V97: 后台管理菜单显示名改为用户易理解的命名
|
||||
-- 只更新 admin 类型菜单的 name 显示名,column_key / route_path 保持不变,
|
||||
-- 所有权限校验、前端分组路由、面板加载逻辑均按 route_path 匹配,不受影响。
|
||||
-- 对应前端静态文案见 backend/static/admin.js 与 backend/web_source/admin.html。
|
||||
|
||||
-- 栏目权限配置 -> 菜单权限配置
|
||||
UPDATE `columns` SET `name` = '菜单权限配置'
|
||||
WHERE `menu_type` = 'admin' AND `column_key` = 'admin_columns';
|
||||
|
||||
-- 数据去重总数据 -> 去重数据汇总
|
||||
UPDATE `columns` SET `name` = '去重数据汇总'
|
||||
WHERE `menu_type` = 'admin' AND `column_key` = 'admin_dedupe_total_data';
|
||||
|
||||
-- 不符合ASIN数据 -> 无效ASIN数据
|
||||
UPDATE `columns` SET `name` = '无效ASIN数据'
|
||||
WHERE `menu_type` = 'admin' AND `column_key` = 'admin_invalid_asin_data';
|
||||
|
||||
-- 视频任务管理 -> 视频任务记录
|
||||
UPDATE `columns` SET `name` = '视频任务记录'
|
||||
WHERE `menu_type` = 'admin' AND `column_key` = 'admin_image_video_tasks';
|
||||
|
||||
-- 店铺数据任务管理 -> 店铺数据记录
|
||||
UPDATE `columns` SET `name` = '店铺数据记录'
|
||||
WHERE `menu_type` = 'admin' AND `column_key` = 'admin_shop_data_crawl_tasks';
|
||||
|
||||
-- 查看生成记录 -> 生成记录
|
||||
UPDATE `columns` SET `name` = '生成记录'
|
||||
WHERE `menu_type` = 'admin' AND `column_key` = 'admin_history';
|
||||
+49
@@ -584,6 +584,55 @@ class PermissionMenuServiceTest {
|
||||
assertThat(inserted.getValue().getColumnId()).isEqualTo(76L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void fullCatalogOrdersAppMenusBeforeAdminMenus() {
|
||||
PermissionMenuMapper menuMapper = mock(PermissionMenuMapper.class);
|
||||
UserColumnPermissionMapper permissionMapper = mock(UserColumnPermissionMapper.class);
|
||||
AdminUserMapper userMapper = mock(AdminUserMapper.class);
|
||||
PermissionMenuService service = new PermissionMenuService(menuMapper, permissionMapper, userMapper);
|
||||
|
||||
// 全量目录:app/admin 交错出现,且各自 sort_order 交叉。期望先按类型分组
|
||||
// (app 在 admin 之前),组内再按 sort_order 升序。
|
||||
when(menuMapper.selectList(any())).thenReturn(List.of(
|
||||
menu(11L, null, "admin", 20),
|
||||
menu(21L, null, "app", 120),
|
||||
menu(12L, null, "admin", 10),
|
||||
menu(22L, null, "app", 110)));
|
||||
|
||||
List<PermissionMenuItemVo> result = service.list(null);
|
||||
|
||||
assertThat(result).extracting(PermissionMenuItemVo::getId)
|
||||
.containsExactly(22L, 21L, 12L, 11L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWithoutSortOrderAppendsWithinSameMenuType() {
|
||||
PermissionMenuMapper menuMapper = mock(PermissionMenuMapper.class);
|
||||
UserColumnPermissionMapper permissionMapper = mock(UserColumnPermissionMapper.class);
|
||||
AdminUserMapper userMapper = mock(AdminUserMapper.class);
|
||||
PermissionMenuService service = new PermissionMenuService(menuMapper, permissionMapper, userMapper);
|
||||
|
||||
// create 内部依次用 selectOne 做唯一性校验(column_key、route_path),
|
||||
// 最后 resolveSortOrder 取同类型尾项(admin 最后一个 sort_order = 134)。
|
||||
PermissionMenuEntity adminTail = menu(9L, null, "admin", 134);
|
||||
adminTail.setName("admin tail");
|
||||
when(menuMapper.selectOne(any())).thenReturn(null, null, adminTail);
|
||||
// create 成功后 getMenuById(insert 未回填的 id) 会走 selectById
|
||||
when(menuMapper.selectById(any())).thenReturn(adminTail);
|
||||
|
||||
PermissionMenuCreateRequest request = createRequest(null, "admin");
|
||||
request.setName("新菜单");
|
||||
request.setColumnKey("new_admin_menu");
|
||||
request.setRoutePath("new-admin-menu");
|
||||
|
||||
service.create(request);
|
||||
|
||||
ArgumentCaptor<PermissionMenuEntity> inserted = ArgumentCaptor.forClass(PermissionMenuEntity.class);
|
||||
verify(menuMapper).insert(inserted.capture());
|
||||
assertThat(inserted.getValue().getSortOrder()).isEqualTo(135);
|
||||
assertThat(inserted.getValue().getMenuType()).isEqualTo("admin");
|
||||
}
|
||||
|
||||
private PermissionMenuCreateRequest createRequest(Long parentId, String menuType) {
|
||||
PermissionMenuCreateRequest request = new PermissionMenuCreateRequest();
|
||||
request.setName("child");
|
||||
|
||||
Reference in New Issue
Block a user