diff --git a/RuoYi-Vue/easycode-web/src/utils/appModuleOutline.js b/RuoYi-Vue/easycode-web/src/utils/appModuleOutline.js index 93ce1fa..03eda74 100644 --- a/RuoYi-Vue/easycode-web/src/utils/appModuleOutline.js +++ b/RuoYi-Vue/easycode-web/src/utils/appModuleOutline.js @@ -11,8 +11,10 @@ function textFromFields(value, fallback = '') { return cleanText(value.title ?? value.name ?? value.code, fallback) } -function menuTitle(menu, index) { - return cleanText(menu?.name ?? menu?.title ?? menu?.code, `功能${index + 1}`) +function menuToItem(menu) { + if (!menu || typeof menu !== 'object') return null + const title = cleanText(menu.name ?? menu.title ?? menu.code) + return title ? { title } : null } function warning(code, line) { @@ -30,12 +32,15 @@ export function normalizeModuleOutline(outline = {}) { const groups = Array.isArray(outline.groups) ? outline.groups : [] return { title: textFromFields(outline), - groups: groups.map((group) => ({ - title: textFromFields(group), - items: (Array.isArray(group?.items) ? group.items : []).map((item) => ({ + groups: groups.map((group) => { + const items = (Array.isArray(group?.items) ? group.items : []).map((item) => ({ title: textFromFields(item) })).filter((item) => item.title) - })).filter((group) => group.title || group.items.length) + return { + title: textFromFields(group, items.length ? FALLBACK_GROUP_TITLE : ''), + items + } + }).filter((group) => group.title || group.items.length) } } @@ -94,15 +99,11 @@ export function blueprintToModuleOutline(blueprint = {}, options = {}) { const groups = [ { title: '管理员端', - items: (Array.isArray(blueprint.adminMenus) ? blueprint.adminMenus : []).map((menu, index) => ({ - title: menuTitle(menu, index) - })).filter((item) => item.title) + items: (Array.isArray(blueprint.adminMenus) ? blueprint.adminMenus : []).map(menuToItem).filter(Boolean) }, { title: '普通用户端', - items: (Array.isArray(blueprint.frontendMenus) ? blueprint.frontendMenus : []).map((menu, index) => ({ - title: menuTitle(menu, index) - })).filter((item) => item.title) + items: (Array.isArray(blueprint.frontendMenus) ? blueprint.frontendMenus : []).map(menuToItem).filter(Boolean) } ].filter((group) => group.items.length) diff --git a/RuoYi-Vue/easycode-web/src/utils/appModuleOutline.test.mjs b/RuoYi-Vue/easycode-web/src/utils/appModuleOutline.test.mjs index f47230b..73c327c 100644 --- a/RuoYi-Vue/easycode-web/src/utils/appModuleOutline.test.mjs +++ b/RuoYi-Vue/easycode-web/src/utils/appModuleOutline.test.mjs @@ -95,6 +95,39 @@ test('blueprintToModuleOutline maps project menus into standard groups', () => { assert.deepEqual(outline.groups[1].items.map((item) => item.title), ['社团浏览', 'profile']) }) +test('blueprintToModuleOutline skips invalid menus while preserving code-only menus', () => { + const outline = blueprintToModuleOutline({ + adminMenus: [ + null, + '菜单', + {}, + { name: ' ', title: '', code: '\t' }, + { code: 'users' } + ], + frontendMenus: [ + undefined, + { title: ' ' }, + { code: 'browse' } + ] + }) + + assert.deepEqual(outline.groups.map((group) => group.title), ['管理员端', '普通用户端']) + assert.deepEqual(outline.groups[0].items.map((item) => item.title), ['users']) + assert.deepEqual(outline.groups[1].items.map((item) => item.title), ['browse']) +}) + +test('normalizeModuleOutline gives untitled groups with items the fallback group title', () => { + const outline = normalizeModuleOutline({ + title: '客户管理系统', + groups: [ + { title: ' ', items: [{ title: '客户列表' }] } + ] + }) + + assert.equal(outline.groups[0].title, '未分组模块') + assert.equal(moduleOutlineToText(outline), '客户管理系统\n 未分组模块\n 客户列表') +}) + test('moduleOutlineToText serializes normalized outlines with two-space levels', () => { const outline = normalizeModuleOutline({ title: '学生社团管理系统',