From d91161a3025214fde394251f463ef9411f9e2ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=B9=8F?= Date: Sat, 23 May 2026 16:09:44 +0800 Subject: [PATCH] Add app blueprint generation flow --- RuoYi-Vue/easycode-web/src/api/project.js | 9 + .../easycode-web/src/views/GenerateView.vue | 182 +++++++++++++- .../front/FrontProjectController.java | 8 + .../ruoyi/generator/domain/GenProject.java | 43 ++++ .../generator/domain/front/FrontProject.java | 3 + .../domain/front/dto/AppBlueprintDesign.java | 18 ++ .../domain/front/dto/AppMenuDesign.java | 27 ++ .../domain/front/dto/AppRoleDesign.java | 15 ++ .../dto/GenerateAppBlueprintRequest.java | 18 ++ .../front/dto/GenerateDatabaseRequest.java | 3 + .../service/front/AiGenerateServiceImpl.java | 235 +++++++++++++++++- .../service/front/FrontProjectConverter.java | 23 ++ .../service/front/IAiGenerateService.java | 4 + .../ruoyi/generator/util/VelocityUtils.java | 14 ++ .../mapper/front/FrontProjectMapper.xml | 6 +- .../service/GenProjectServiceImplTest.java | 17 ++ .../front/AiGenerateServiceImplTest.java | 79 ++++++ .../front/FrontProjectConverterTest.java | 18 ++ .../FrontProjectPreviewServiceImplTest.java | 22 ++ .../sql/business_blueprint_templates.sql | 182 +++++++++++++- RuoYi-Vue/sql/db.sql | 1 + RuoYi-Vue/sql/front_app_blueprint.sql | 17 ++ RuoYi-Vue/sql/front_workbench.sql | 1 + 23 files changed, 933 insertions(+), 12 deletions(-) create mode 100644 RuoYi-Vue/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/AppBlueprintDesign.java create mode 100644 RuoYi-Vue/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/AppMenuDesign.java create mode 100644 RuoYi-Vue/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/AppRoleDesign.java create mode 100644 RuoYi-Vue/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/GenerateAppBlueprintRequest.java create mode 100644 RuoYi-Vue/sql/front_app_blueprint.sql diff --git a/RuoYi-Vue/easycode-web/src/api/project.js b/RuoYi-Vue/easycode-web/src/api/project.js index 030571e..7dd10ff 100644 --- a/RuoYi-Vue/easycode-web/src/api/project.js +++ b/RuoYi-Vue/easycode-web/src/api/project.js @@ -43,6 +43,15 @@ export function generateDatabase(projectId, data) { }).then(unwrap) } +export function generateAppBlueprint(projectId, data) { + return request({ + url: `/front/project/${projectId}/generate-app-blueprint`, + method: 'post', + timeout: GENERATE_REQUEST_TIMEOUT, + data + }).then(unwrap) +} + export function getDatabase(projectId) { return request({ url: `/front/project/${projectId}/database`, diff --git a/RuoYi-Vue/easycode-web/src/views/GenerateView.vue b/RuoYi-Vue/easycode-web/src/views/GenerateView.vue index 165fe91..4b611e9 100644 --- a/RuoYi-Vue/easycode-web/src/views/GenerateView.vue +++ b/RuoYi-Vue/easycode-web/src/views/GenerateView.vue @@ -45,7 +45,10 @@ />
- + + 生成应用蓝图 + + 生成数据库 @@ -64,6 +67,44 @@
+
+
+

应用蓝图

+
+ 角色:{{ appBlueprint.roles.length }} + 前台菜单:{{ appBlueprint.frontendMenus.length }} + 后台菜单:{{ appBlueprint.adminMenus.length }} +
+
+
+
+
+

角色

+ + {{ role.name || role.code }} + +
+
+

前台菜单

+ + {{ menu.name || menu.code }} + +
+
+

后台菜单

+ + {{ menu.name || menu.code }} + +
+
+ +
+ 应用调整 +
+
+ +
+

数据库设计

@@ -131,24 +172,27 @@ ', 'admin', sysdate()); +INSERT INTO sys_template_file (template_file_id, template_id, file_name, module_id, file_path, file_content, create_by, create_time) VALUES +(910204, 9102, 'adminMenus.js.vm', NULL, 'adminMenus.js.vm', +'export const appRoles = [ +#foreach($role in $appRoles) + { code: "${role.code}", name: "${role.name}", description: "${role.description}" }#if($foreach.hasNext),#end +#end +] + +export const adminMenus = [ +#foreach($menu in $adminMenus) + { + code: "${menu.code}", + name: "${menu.name}", + path: "${menu.path}", + requiresLogin: ${menu.requiresLogin}, + visibleRoles: [ +#foreach($role in $menu.visibleRoles) + "${role}"#if($foreach.hasNext),#end +#end + ], + dataScope: "${menu.dataScope}" + }#if($foreach.hasNext),#end +#end +] + +export function requiresLogin(menu) { + return Boolean(menu && menu.requiresLogin) +} + +export function canShowMenu(menu, currentUser = {}) { + if (!menu) { + return false + } + if (menu.requiresLogin && !currentUser.id && !currentUser.userId) { + return false + } + const userRoles = Array.isArray(currentUser.roles) ? currentUser.roles : [] + if (!Array.isArray(menu.visibleRoles) || menu.visibleRoles.length === 0) { + return true + } + return menu.visibleRoles.some(role => userRoles.includes(role)) +} +', 'admin', sysdate()); + +INSERT INTO sys_template_file (template_file_id, template_id, file_name, module_id, file_path, file_content, create_by, create_time) VALUES +(910205, 9102, 'adminPermission.js.vm', NULL, 'adminPermission.js.vm', +'import { adminMenus, canShowMenu, requiresLogin } from "./config/adminMenus" + +function defaultCurrentUser() { + try { + return JSON.parse(localStorage.getItem("currentUser") || "{}") + } catch (error) { + return {} + } +} + +function isLoggedIn(user) { + return Boolean(user && (user.id || user.userId)) +} + +export function installAdminGuard(router, getCurrentUser = defaultCurrentUser) { + router.beforeEach((to, from, next) => { + const menu = adminMenus.find(item => item.path === to.path) + const user = getCurrentUser() || {} + if (menu && !canShowMenu(menu, user)) { + next(false) + return + } + if (menu && requiresLogin(menu) && !isLoggedIn(user)) { + next("/login") + return + } + next() + }) +} +', 'admin', sysdate()); + -- Portal frontend template files INSERT INTO sys_template_file (template_file_id, template_id, file_name, module_id, file_path, file_content, create_by, create_time) VALUES (910301, 9103, 'package.json.vm', NULL, 'package.json.vm', @@ -873,6 +950,9 @@ createApp(App).use(router).use(ElementPlus).mount("#app") ${projectName} 工作台 + + {{ menu.name }} + @@ -881,6 +961,22 @@ createApp(App).use(router).use(ElementPlus).mount("#app") + + ', 'admin', sysdate()); +INSERT INTO sys_template_file (template_file_id, template_id, file_name, module_id, file_path, file_content, create_by, create_time) VALUES +(910310, 9103, 'frontendMenus.js.vm', NULL, 'frontendMenus.js.vm', +'export const appRoles = [ +#foreach($role in $appRoles) + { code: "${role.code}", name: "${role.name}", description: "${role.description}" }#if($foreach.hasNext),#end +#end +] + +export const frontendMenus = [ +#foreach($menu in $frontendMenus) + { + code: "${menu.code}", + name: "${menu.name}", + path: "${menu.path}", + requiresLogin: ${menu.requiresLogin}, + visibleRoles: [ +#foreach($role in $menu.visibleRoles) + "${role}"#if($foreach.hasNext),#end +#end + ], + dataScope: "${menu.dataScope}" + }#if($foreach.hasNext),#end +#end +] + +export function requiresLogin(menu) { + return Boolean(menu && menu.requiresLogin) +} + +export function canShowMenu(menu, currentUser = {}) { + if (!menu) { + return false + } + if (menu.requiresLogin && !currentUser.id && !currentUser.userId) { + return false + } + const userRoles = Array.isArray(currentUser.roles) ? currentUser.roles : [] + if (!Array.isArray(menu.visibleRoles) || menu.visibleRoles.length === 0) { + return true + } + return menu.visibleRoles.some(role => userRoles.includes(role)) +} +', 'admin', sysdate()); + -- Backend project structure INSERT INTO sys_project_structure (node_id, parent_id, node_name, node_type, module, template_id, table_id, category, sort_order, status, create_by, create_time, update_by, update_time) VALUES (910100, 0, '{projectName}-backend', 'folder', NULL, 9101, NULL, NULL, 1, '0', 'admin', sysdate(), '', NULL), @@ -1184,6 +1353,13 @@ INSERT INTO sys_project_structure (node_id, parent_id, node_name, node_type, mod (910208, 910207, '{businessName}', 'folder', NULL, 9102, 0, NULL, 1, '0', 'admin', sysdate(), '', NULL), (910209, 910208, 'index.vue', 'file', NULL, 9102, 0, 'index.vue.vm', 1, '0', 'admin', sysdate(), '', NULL); +INSERT INTO sys_project_structure (node_id, parent_id, node_name, node_type, module, template_id, table_id, category, sort_order, status, create_by, create_time, update_by, update_time) VALUES +(910210, 910202, 'config', 'folder', NULL, 9102, NULL, NULL, 3, '0', 'admin', sysdate(), '', NULL), +(910211, 910210, 'adminMenus.js', 'file', NULL, 9102, -1, 'adminMenus.js.vm', 1, '0', 'admin', sysdate(), '', NULL); + +INSERT INTO sys_project_structure (node_id, parent_id, node_name, node_type, module, template_id, table_id, category, sort_order, status, create_by, create_time, update_by, update_time) VALUES +(910212, 910202, 'permission.js', 'file', NULL, 9102, -1, 'adminPermission.js.vm', 4, '0', 'admin', sysdate(), '', NULL); + -- Portal frontend project structure INSERT INTO sys_project_structure (node_id, parent_id, node_name, node_type, module, template_id, table_id, category, sort_order, status, create_by, create_time, update_by, update_time) VALUES (910300, 0, '{projectName}-portal', 'folder', NULL, 9103, NULL, NULL, 1, '0', 'admin', sysdate(), '', NULL), @@ -1202,4 +1378,8 @@ INSERT INTO sys_project_structure (node_id, parent_id, node_name, node_type, mod (910313, 910312, 'index.vue', 'file', NULL, 9103, 0, 'index.vue.vm', 1, '0', 'admin', sysdate(), '', NULL), (910314, 910312, 'detail.vue', 'file', NULL, 9103, 0, 'detail.vue.vm', 2, '0', 'admin', sysdate(), '', NULL); +INSERT INTO sys_project_structure (node_id, parent_id, node_name, node_type, module, template_id, table_id, category, sort_order, status, create_by, create_time, update_by, update_time) VALUES +(910315, 910303, 'config', 'folder', NULL, 9103, NULL, NULL, 6, '0', 'admin', sysdate(), '', NULL), +(910316, 910315, 'frontendMenus.js', 'file', NULL, 9103, -1, 'frontendMenus.js.vm', 1, '0', 'admin', sysdate(), '', NULL); + SET FOREIGN_KEY_CHECKS = 1; diff --git a/RuoYi-Vue/sql/db.sql b/RuoYi-Vue/sql/db.sql index 4aa622c..46470c4 100644 --- a/RuoYi-Vue/sql/db.sql +++ b/RuoYi-Vue/sql/db.sql @@ -1299,6 +1299,7 @@ create table front_project ( back_framework varchar(50) default 'Spring Boot + MyBatis' comment '后端框架', generate_status char(1) default '0' comment '数据库生成状态(0未生成 1生成中 2已生成 3失败)', preview_status char(1) default '0' comment '预览状态(0未预览 1已预览 2失败)', + app_blueprint longtext comment '应用蓝图草稿JSON', er_diagram longtext comment 'ER图草稿JSON', business_blueprint longtext comment '业务蓝图草稿JSON', status char(1) default '0' comment '状态(0正常 1停用)', diff --git a/RuoYi-Vue/sql/front_app_blueprint.sql b/RuoYi-Vue/sql/front_app_blueprint.sql new file mode 100644 index 0000000..0ac099e --- /dev/null +++ b/RuoYi-Vue/sql/front_app_blueprint.sql @@ -0,0 +1,17 @@ +set @front_app_blueprint_exists := ( + select count(1) + from information_schema.columns + where table_schema = database() + and table_name = 'front_project' + and column_name = 'app_blueprint' +); + +set @front_app_blueprint_sql := if( + @front_app_blueprint_exists = 0, + 'alter table front_project add column app_blueprint longtext comment ''应用蓝图草稿JSON'' after preview_status', + 'select ''front_project.app_blueprint already exists''' +); + +prepare front_app_blueprint_stmt from @front_app_blueprint_sql; +execute front_app_blueprint_stmt; +deallocate prepare front_app_blueprint_stmt; diff --git a/RuoYi-Vue/sql/front_workbench.sql b/RuoYi-Vue/sql/front_workbench.sql index 578d658..429f239 100644 --- a/RuoYi-Vue/sql/front_workbench.sql +++ b/RuoYi-Vue/sql/front_workbench.sql @@ -42,6 +42,7 @@ create table front_project ( back_framework varchar(50) default 'Spring Boot + MyBatis' comment '后端框架', generate_status char(1) default '0' comment '数据库生成状态(0未生成 1生成中 2已生成 3失败)', preview_status char(1) default '0' comment '预览状态(0未预览 1已预览 2失败)', + app_blueprint longtext comment '应用蓝图草稿JSON', er_diagram longtext comment 'ER图草稿JSON', business_blueprint longtext comment '业务蓝图草稿JSON', status char(1) default '0' comment '状态(0正常 1停用)',