From ca0e59e087685df4bd3dc117101ddbf85c53eed0 Mon Sep 17 00:00:00 2001 From: 潘志宝 <979469083@qq.com> Date: 星期三, 18 九月 2024 12:01:00 +0800 Subject: [PATCH] Merge branch 'master' of ssh://172.16.8.100:29418/iailab-plat --- iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MpkFileServiceImpl.java | 77 + iailab-module-model/iailab-module-model-biz/src/main/resources/mapper/mpk/MpkFileDao.xml | 74 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenController.java | 28 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/MethodSettingService.java | 14 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppGroupService.java | 31 iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/AppApi.java | 31 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppGroupController.java | 83 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/oauth2/OAuth2OpenConvert.java | 1 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppController.java | 20 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuListReqVO.java | 16 iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/dto/AppMenuRespDTO.java | 80 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/app/AppGroupDO.java | 57 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/tenant/TenantServiceImpl.java | 6 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/user/AdminUserServiceImpl.java | 5 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/SettingSelectServiceImpl.java | 37 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuService.java | 17 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/permission/MenuDO.java | 11 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/app/AppGroupMapper.java | 24 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java | 96 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppGroupServiceImpl.java | 72 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java | 9 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/app/AppConvert.java | 60 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuSimpleRespVO.java | 22 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppRespVO.java | 26 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppSaveReqVO.java | 11 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppServiceImpl.java | 216 ++++ iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/vo/menu/MenuRespVO.java | 3 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/ModelMethodEntity.java | 4 iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/dto/AppRespDTO.java | 75 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/RoleServiceImpl.java | 8 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppMenuService.java | 118 ++ iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/ModelMethodDTO.java | 7 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/vo/menu/MenuSaveVO.java | 3 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/tenant/TenantService.java | 7 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/permission/MenuMapper.java | 12 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppGroupPageReqVO.java | 23 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/app/AppDO.java | 28 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MethodSettingDTO.java | 64 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/app/AppMenuMapper.java | 37 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/user/AdminUserMapper.java | 3 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/MpkFileService.java | 2 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MethodSettingServiceImpl.java | 22 iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/AppMenuApi.java | 32 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dao/SettingSelectDao.java | 14 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/app/AppMenuDO.java | 114 ++ iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppMenuController.java | 87 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionService.java | 26 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/RoleService.java | 2 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/SettingSelectDTO.java | 36 iailab-module-model/iailab-module-model-biz/db/mysql.sql | 106 + iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/SettingSelectEntity.java | 38 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionServiceImpl.java | 74 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java | 35 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppGroupRespVO.java | 48 iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/dto/AppMenuSimpleRespDTO.java | 22 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuRespVO.java | 69 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/PermissionController.java | 17 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MpkFileDTO.java | 10 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/MpkFileEntity.java | 20 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppGroupSaveReqVO.java | 36 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/controller/admin/MpkFileController.java | 26 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/MenuController.java | 53 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuServiceImpl.java | 65 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/tenant/TenantController.java | 8 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/api/app/AppMenuApiImpl.java | 59 + iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/MethodSettingEntity.java | 64 + iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/SettingSelectService.java | 16 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/ProjectServiceImpl.java | 19 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuSaveVO.java | 65 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenLoginReqVO.java | 54 + iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppMenuServiceImpl.java | 281 +++++ iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppService.java | 9 iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dao/MethodSettingDao.java | 14 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/api/app/AppApiImpl.java | 55 + 74 files changed, 3,003 insertions(+), 111 deletions(-) diff --git a/iailab-module-model/iailab-module-model-biz/db/mysql.sql b/iailab-module-model/iailab-module-model-biz/db/mysql.sql index 8b33e9b..c8e5d06 100644 --- a/iailab-module-model/iailab-module-model-biz/db/mysql.sql +++ b/iailab-module-model/iailab-module-model-biz/db/mysql.sql @@ -419,18 +419,43 @@ -- config INSERT INTO `iailab_plat_system`.`infra_config` (`id`, `category`, `type`, `name`, `config_key`, `value`, `visible`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (13, 'model', 2, 'model文件备份路径', 'mpkBakFilePath', 'C:\\DLUT\\mpkBakFile', b'1', 'model文件备份路径', '1', '2024-09-12 11:10:25', '1', '2024-09-12 11:10:25', b'0'); --- ---------------------------- --- Table structure for t_mpk_file --- ---------------------------- +-- dist +INSERT INTO `iailab_plat_system`.`system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (618, '模型方法', 'model_method', 0, '', '1', '2024-09-09 16:11:55', '1', '2024-09-09 16:11:55', b'0', '1970-01-01 00:00:00'); +INSERT INTO `iailab_plat_system`.`system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (619, '模型类型', 'model_type', 0, '', '1', '2024-09-13 14:14:26', '1', '2024-09-13 14:14:26', b'0', '1970-01-01 00:00:00'); +INSERT INTO `iailab_plat_system`.`system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (620, '模型方法输入类型', 'model_method_setting_type', 0, '', '1', '2024-09-13 15:41:38', '1', '2024-09-13 15:41:38', b'0', '1970-01-01 00:00:00'); +INSERT INTO `iailab_plat_system`.`system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (621, '模型方法参数类型', 'model_method_setting_value_type', 0, '', '1', '2024-09-13 15:42:27', '1', '2024-09-13 15:42:27', b'0', '1970-01-01 00:00:00'); + + +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1536, 1, 'train', 'train', 'model_method', 0, '', '', '', '1', '2024-09-09 16:12:42', '1', '2024-09-09 16:12:42', b'0'); +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1537, 3, 'control', 'control', 'model_method', 0, '', '', '', '1', '2024-09-09 16:12:54', '1', '2024-09-09 16:13:10', b'0'); +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1538, 2, 'predict', 'predict', 'model_method', 0, '', '', '', '1', '2024-09-09 16:13:05', '1', '2024-09-09 16:13:05', b'0'); +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1539, 1, '预测模型', 'predict', 'model_type', 0, '', '', '', '1', '2024-09-13 14:14:58', '1', '2024-09-13 14:14:58', b'0'); +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1540, 2, '调度模型', 'schedul', 'model_type', 0, '', '', '', '1', '2024-09-13 14:17:53', '1', '2024-09-13 14:17:53', b'0'); +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1541, 1, 'input', 'input', 'model_method_setting_type', 0, '', '', '', '1', '2024-09-13 15:44:08', '1', '2024-09-13 15:44:08', b'0'); +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1542, 2, 'select', 'select', 'model_method_setting_type', 0, '', '', '', '1', '2024-09-13 15:44:17', '1', '2024-09-13 15:44:17', b'0'); +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1543, 3, 'file', 'file', 'model_method_setting_type', 0, '', '', '', '1', '2024-09-13 15:44:24', '1', '2024-09-13 15:44:24', b'0'); +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1544, 1, 'int', 'int', 'model_method_setting_value_type', 0, '', '', '', '1', '2024-09-13 15:44:42', '1', '2024-09-13 15:44:42', b'0'); +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1545, 5, 'file', 'file', 'model_method_setting_value_type', 0, '', '', '', '1', '2024-09-13 15:44:57', '1', '2024-09-14 14:16:24', b'0'); +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1546, 3, 'decimal', 'decimal', 'model_method_setting_value_type', 0, '', '', '', '1', '2024-09-13 15:45:21', '1', '2024-09-13 15:45:21', b'0'); +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1547, 4, 'decimalArray', 'decimalArray', 'model_method_setting_value_type', 0, '', '', '', '1', '2024-09-13 15:45:26', '1', '2024-09-13 15:45:26', b'0'); +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1548, 2, 'string', 'string', 'model_method_setting_value_type', 0, '', '', '', '1', '2024-09-13 15:45:36', '1', '2024-09-14 14:16:30', b'0'); +INSERT INTO `iailab_plat_system`.`system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1549, 4, 'schedul', 'schedul', 'model_method', 0, '', '', '', '1', '2024-09-14 14:56:44', '1', '2024-09-14 14:56:44', b'0'); + + +-- 业务表 DROP TABLE IF EXISTS `t_mpk_file`; CREATE TABLE `t_mpk_file` ( `id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'id', `py_name` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型名称', + `py_chinese_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型中文名称', `file_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '源文件保存路径', `py_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型类型', `pkg_name` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '包名', `class_name` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '类名', `py_module` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型路径', + `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'icon图片名', + `menu_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所属菜单', + `group_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所属组', `remark` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注', `creator` bigint NULL DEFAULT NULL COMMENT '创建者', `create_date` datetime NULL DEFAULT NULL COMMENT '创建时间', @@ -441,20 +466,41 @@ INDEX `idx_create_date`(`create_date` ASC) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'MDK模型文件' ROW_FORMAT = DYNAMIC; - -- ---------------------------- -- Table structure for t_mpk_generator_code_history -- ---------------------------- DROP TABLE IF EXISTS `t_mpk_generator_code_history`; CREATE TABLE `t_mpk_generator_code_history` ( `id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'id', - `mdk_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'mdk_id', + `mdk_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'mdk_id', `file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文件名', `file_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文件保存路径', `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注', `create_time` timestamp NULL DEFAULT NULL COMMENT '生成时间', - PRIMARY KEY (`id`) USING BTREE + PRIMARY KEY (`id`, `mdk_id`) USING BTREE, + INDEX `del_code_history`(`mdk_id` ASC) USING BTREE, + CONSTRAINT `del_code_history` FOREIGN KEY (`mdk_id`) REFERENCES `t_mpk_file` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '生成代码记录表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for t_mpk_method_setting +-- ---------------------------- +DROP TABLE IF EXISTS `t_mpk_method_setting`; +CREATE TABLE `t_mpk_method_setting` ( + `id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'id', + `method_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '方法id', + `setting_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'key', + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '参数名称', + `value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '参数默认值', + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '输入类型', + `value_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '参数类型', + `max` int NULL DEFAULT NULL COMMENT '最大值', + `min` int NULL DEFAULT NULL COMMENT '最小值', + PRIMARY KEY (`id`, `method_id`) USING BTREE, + INDEX `del_setting`(`method_id` ASC) USING BTREE, + INDEX `id`(`id` ASC) USING BTREE, + CONSTRAINT `del_setting` FOREIGN KEY (`method_id`) REFERENCES `t_mpk_model_method` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '方法参数关联表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for t_mpk_model_method @@ -462,11 +508,15 @@ DROP TABLE IF EXISTS `t_mpk_model_method`; CREATE TABLE `t_mpk_model_method` ( `id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'id', - `mpk_file_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型文件id', + `mpk_file_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '模型文件id', `method_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型方法名', `data_length` int NULL DEFAULT 1 COMMENT '输入个数', `model` int NULL DEFAULT 0 COMMENT '是否有model(0:否,1:是)', - PRIMARY KEY (`id`) USING BTREE + `result_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '结果key', + PRIMARY KEY (`id`, `mpk_file_id`) USING BTREE, + INDEX `id`(`id` ASC) USING BTREE, + INDEX `del_method`(`mpk_file_id` ASC) USING BTREE, + CONSTRAINT `del_method` FOREIGN KEY (`mpk_file_id`) REFERENCES `t_mpk_file` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; -- ---------------------------- @@ -488,9 +538,13 @@ DROP TABLE IF EXISTS `t_mpk_project_model`; CREATE TABLE `t_mpk_project_model` ( `id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'id', - `project_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '项目id', - `model_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型id', - PRIMARY KEY (`id`) USING BTREE + `project_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '项目id', + `model_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '模型id', + PRIMARY KEY (`id`, `project_id`, `model_id`) USING BTREE, + INDEX `del_p`(`project_id` ASC) USING BTREE, + INDEX `del_m`(`model_id` ASC) USING BTREE, + CONSTRAINT `del_m` FOREIGN KEY (`model_id`) REFERENCES `t_mpk_file` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT, + CONSTRAINT `del_p` FOREIGN KEY (`project_id`) REFERENCES `t_mpk_project` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '项目模型关联表' ROW_FORMAT = DYNAMIC; -- ---------------------------- @@ -499,14 +553,16 @@ DROP TABLE IF EXISTS `t_mpk_project_package_history`; CREATE TABLE `t_mpk_project_package_history` ( `id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'id', - `project_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '项目id', + `project_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '项目id', `file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文件名', `file_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文件路径', `version` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '版本号', `log` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新日志', `model_names` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '打包模型名称(“,”分割)', `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间', - PRIMARY KEY (`id`) USING BTREE + PRIMARY KEY (`id`, `project_id`) USING BTREE, + INDEX `del_package_history`(`project_id` ASC) USING BTREE, + CONSTRAINT `del_package_history` FOREIGN KEY (`project_id`) REFERENCES `t_mpk_project` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '项目打包历史记录表' ROW_FORMAT = DYNAMIC; -- ---------------------------- @@ -515,12 +571,28 @@ DROP TABLE IF EXISTS `t_mpk_project_package_history_model`; CREATE TABLE `t_mpk_project_package_history_model` ( `id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'id', - `project_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '项目id', + `project_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '项目id', `package_history_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '打包历史id', `py_name` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型名称', `pkg_name` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '包名', `py_module` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型路径', `remark` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型备注', - `method_info` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型方法信息', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '打包历史模型关联表' ROW_FORMAT = Dynamic; \ No newline at end of file + `method_info` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '模型方法信息', + PRIMARY KEY (`id`, `project_id`) USING BTREE, + INDEX `del_package_model`(`project_id` ASC) USING BTREE, + CONSTRAINT `del_package_model` FOREIGN KEY (`project_id`) REFERENCES `t_mpk_project` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '打包历史模型关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for t_mpk_setting_select +-- ---------------------------- +DROP TABLE IF EXISTS `t_mpk_setting_select`; +CREATE TABLE `t_mpk_setting_select` ( + `id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'id', + `setting_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '参数id', + `select_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'key', + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '名称', + PRIMARY KEY (`id`, `setting_id`) USING BTREE, + INDEX `del_select`(`setting_id` ASC) USING BTREE, + CONSTRAINT `del_select` FOREIGN KEY (`setting_id`) REFERENCES `t_mpk_method_setting` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '参数选项关联表' ROW_FORMAT = Dynamic; \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/controller/admin/MpkFileController.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/controller/admin/MpkFileController.java index bba6bb7..ad7352f 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/controller/admin/MpkFileController.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/controller/admin/MpkFileController.java @@ -1,16 +1,12 @@ package com.iailab.module.model.mpk.controller.admin; -import com.alibaba.fastjson.JSON; import com.iailab.framework.common.page.PageData; import com.iailab.framework.common.pojo.CommonResult; -import com.iailab.framework.common.util.date.DateUtils; -import com.iailab.module.model.mpk.common.utils.Readtxt; import com.iailab.module.model.mpk.dto.MpkFileDTO; -import com.iailab.module.model.mpk.service.MdkFileService; +import com.iailab.module.model.mpk.service.MpkFileService; import io.swagger.v3.oas.annotations.Operation; import org.apache.commons.io.IOUtils; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -30,51 +26,51 @@ @RequestMapping("/model/mpk/file") public class MpkFileController { @Autowired - private MdkFileService mdkFileService; + private MpkFileService mpkFileService; @GetMapping("page") @Operation(summary = "分页") public CommonResult<PageData<MpkFileDTO>> page(@RequestParam Map<String, Object> params) { - PageData<MpkFileDTO> page = mdkFileService.page(params); + PageData<MpkFileDTO> page = mpkFileService.page(params); return success(page); } @GetMapping("{id}") public CommonResult<MpkFileDTO> info(@PathVariable("id") String id) { - MpkFileDTO schedule = mdkFileService.get(id); + MpkFileDTO schedule = mpkFileService.get(id); return success(schedule); } @GetMapping("list") public CommonResult<List<MpkFileDTO>> list() { - List<MpkFileDTO> list = mdkFileService.list(new HashMap<>()); + List<MpkFileDTO> list = mpkFileService.list(new HashMap<>()); return success(list); } @PostMapping public CommonResult save(@RequestBody MpkFileDTO dto) { - mdkFileService.save(dto); + mpkFileService.save(dto); return CommonResult.success(); } @DeleteMapping public CommonResult delete(String id) { - mdkFileService.delete(id); + mpkFileService.delete(id); return CommonResult.success(); } @PutMapping public CommonResult update(@RequestBody MpkFileDTO dto) { - mdkFileService.update(dto); + mpkFileService.update(dto); return CommonResult.success(); } @GetMapping("generat") public void generat(String id, String remark,String zipFileName, HttpServletResponse response) throws IOException { - byte[] data = mdkFileService.generatorCode(id, remark,zipFileName); + byte[] data = mpkFileService.generatorCode(id, remark,zipFileName); response.reset(); response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(zipFileName, "UTF-8") + "\""); @@ -88,7 +84,7 @@ public void packageModel(String ids ,String projectId,String log ,String projectName,String version,String zipFileName,HttpServletResponse response) throws IOException { byte[] data; try { - data = mdkFileService.packageModel(Arrays.asList(ids.split(",")),projectId,projectName,zipFileName,log,version); + data = mpkFileService.packageModel(Arrays.asList(ids.split(",")),projectId,projectName,zipFileName,log,version); } catch (InterruptedException e) { throw new RuntimeException("模型打包失败",e); } @@ -104,7 +100,7 @@ @PostMapping("/upload") @Operation(summary = "python文件上传") public CommonResult<Map<String,String>> importExcel(@RequestParam("file") MultipartFile file) throws Exception { - Map<String,String> result = mdkFileService.savePyFile(file); + Map<String,String> result = mpkFileService.savePyFile(file); return success(result); } } \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dao/MethodSettingDao.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dao/MethodSettingDao.java new file mode 100644 index 0000000..69421f8 --- /dev/null +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dao/MethodSettingDao.java @@ -0,0 +1,14 @@ +package com.iailab.module.model.mpk.dao; + +import com.iailab.framework.common.dao.BaseDao; +import com.iailab.module.model.mpk.entity.MethodSettingEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * @description: + * @author: dzd + * @date: 2024/9/14 15:11 + **/ +@Mapper +public interface MethodSettingDao extends BaseDao<MethodSettingEntity> { +} diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dao/SettingSelectDao.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dao/SettingSelectDao.java new file mode 100644 index 0000000..731ce69 --- /dev/null +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dao/SettingSelectDao.java @@ -0,0 +1,14 @@ +package com.iailab.module.model.mpk.dao; + +import com.iailab.framework.common.dao.BaseDao; +import com.iailab.module.model.mpk.entity.SettingSelectEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * @description: + * @author: dzd + * @date: 2024/9/14 15:11 + **/ +@Mapper +public interface SettingSelectDao extends BaseDao<SettingSelectEntity> { +} diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MethodSettingDTO.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MethodSettingDTO.java new file mode 100644 index 0000000..fce3f21 --- /dev/null +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MethodSettingDTO.java @@ -0,0 +1,64 @@ +package com.iailab.module.model.mpk.dto; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * @description: 方法参数关联表 + * @author: dzd + * @date: 2024/9/13 15:49 + **/ +@Data +public class MethodSettingDTO implements Serializable { + + /** + * id + */ + private String id; + + /** + * '方法id' + */ + private String methodId; + + /** + * key + */ + private String settingKey; + + /** + * 参数名称 + */ + private String name; + + /** + * 参数默认值 + */ + private String value; + + /** + * 输入类型 + */ + private String type; + + /** + * 参数类型 + */ + private String valueType; + + /** + * 最大值 + */ + private Integer max; + + /** + * 最小值 + */ + private Integer min; + + private List<SettingSelectDTO> settingSelects; +} \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/ModelMethodDTO.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/ModelMethodDTO.java index 44681c3..84df9c0 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/ModelMethodDTO.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/ModelMethodDTO.java @@ -1,10 +1,9 @@ package com.iailab.module.model.mpk.dto; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.io.Serializable; +import java.util.List; /** * @description: MPK模型方法 @@ -24,4 +23,8 @@ private Integer dataLength; private Integer model; + + private String resultKey; + + private List<MethodSettingDTO> methodSettings; } \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MpkFileDTO.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MpkFileDTO.java index 815a5ad..e47d22f 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MpkFileDTO.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/MpkFileDTO.java @@ -20,6 +20,8 @@ private String pyName; + private String pyChineseName; + private String filePath; private String pyType; @@ -29,6 +31,12 @@ private String className; private String pyModule; + + private String icon; + + private String menuName; + + private String groupName; private String remark; @@ -40,5 +48,5 @@ private Date createDate; - private List<ModelMethodEntity> modelMethods; + private List<ModelMethodDTO> modelMethods; } \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/SettingSelectDTO.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/SettingSelectDTO.java new file mode 100644 index 0000000..d9e69af --- /dev/null +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/dto/SettingSelectDTO.java @@ -0,0 +1,36 @@ +package com.iailab.module.model.mpk.dto; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * @description: 参数选项关联表 + * @author: dzd + * @date: 2024/9/13 15:49 + **/ +@Data +public class SettingSelectDTO implements Serializable { + + /** + * id + */ + private String id; + + /** + * '参数id' + */ + private String settingId; + + /** + * key + */ + private String selectKey; + + /** + * 名称 + */ + private String name; +} \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/MethodSettingEntity.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/MethodSettingEntity.java new file mode 100644 index 0000000..2a7b1e6 --- /dev/null +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/MethodSettingEntity.java @@ -0,0 +1,64 @@ +package com.iailab.module.model.mpk.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import org.checkerframework.checker.units.qual.min; + +import java.io.Serializable; + +/** + * @description: 方法参数关联表 + * @author: dzd + * @date: 2024/9/13 15:49 + **/ +@Data +@TableName("t_mpk_method_setting") +public class MethodSettingEntity implements Serializable { + + /** + * id + */ + @TableId + private String id; + + /** + * 方法id + */ + private String methodId; + + /** + * key + */ + private String settingKey; + + /** + * 参数名称 + */ + private String name; + + /** + * 参数默认值 + */ + private String value; + + /** + * 输入类型 + */ + private String type; + + /** + * 参数类型 + */ + private String valueType; + + /** + * 最大值 + */ + private Integer max; + + /** + * 最小值 + */ + private Integer min; +} \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/ModelMethodEntity.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/ModelMethodEntity.java index 117b220..5b9b24d 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/ModelMethodEntity.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/ModelMethodEntity.java @@ -43,4 +43,8 @@ * 是否有model(0:否,1:是) */ private Integer model; + /** + * 结果key + */ + private String resultKey; } \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/MpkFileEntity.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/MpkFileEntity.java index 146a966..29a1770 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/MpkFileEntity.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/MpkFileEntity.java @@ -32,6 +32,11 @@ private String pyName; /** + * 模型中文名称 + */ + private String pyChineseName; + + /** * 源文件保存路径 */ private String filePath; @@ -57,6 +62,21 @@ private String pyModule; /** + * icon图片名 + */ + private String icon; + + /** + * 所属菜单 + */ + private String menuName; + + /** + * 所属组 + */ + private String groupName; + + /** * 备注 */ private String remark; diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/SettingSelectEntity.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/SettingSelectEntity.java new file mode 100644 index 0000000..e636a46 --- /dev/null +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/entity/SettingSelectEntity.java @@ -0,0 +1,38 @@ +package com.iailab.module.model.mpk.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * @description: 参数选项关联表 + * @author: dzd + * @date: 2024/9/13 15:49 + **/ +@Data +@TableName("t_mpk_setting_select") +public class SettingSelectEntity implements Serializable { + + /** + * id + */ + @TableId + private String id; + + /** + * '参数id' + */ + private String settingId; + + /** + * key + */ + private String selectKey; + + /** + * 名称 + */ + private String name; +} \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/MethodSettingService.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/MethodSettingService.java new file mode 100644 index 0000000..cce6830 --- /dev/null +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/MethodSettingService.java @@ -0,0 +1,14 @@ +package com.iailab.module.model.mpk.service; + +import com.iailab.framework.common.service.BaseService; +import com.iailab.module.model.mpk.entity.MethodSettingEntity; + +import java.util.Map; + +/** + * @description: + * @author: dzd + * @date: 2024/9/14 15:10 + **/ +public interface MethodSettingService extends BaseService<MethodSettingEntity> { +} \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/MdkFileService.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/MpkFileService.java similarity index 94% rename from iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/MdkFileService.java rename to iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/MpkFileService.java index 9f684a4..53da080 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/MdkFileService.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/MpkFileService.java @@ -15,7 +15,7 @@ * @Description * @createTime 2024年08月14日 */ -public interface MdkFileService extends BaseService<MpkFileEntity> { +public interface MpkFileService extends BaseService<MpkFileEntity> { PageData<MpkFileDTO> page(Map<String, Object> params); diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/SettingSelectService.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/SettingSelectService.java new file mode 100644 index 0000000..d29955b --- /dev/null +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/SettingSelectService.java @@ -0,0 +1,16 @@ +package com.iailab.module.model.mpk.service; + +import com.iailab.framework.common.service.BaseService; +import com.iailab.module.model.mpk.entity.SettingSelectEntity; + +import java.util.Map; + +/** + * @description: + * @author: dzd + * @date: 2024/9/14 15:10 + **/ +public interface SettingSelectService extends BaseService<SettingSelectEntity> { + + void deleteByMap(Map<String, Object> map); +} \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MethodSettingServiceImpl.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MethodSettingServiceImpl.java new file mode 100644 index 0000000..1010171 --- /dev/null +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MethodSettingServiceImpl.java @@ -0,0 +1,22 @@ +package com.iailab.module.model.mpk.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.iailab.framework.common.service.impl.BaseServiceImpl; +import com.iailab.module.model.mpk.dao.MethodSettingDao; +import com.iailab.module.model.mpk.entity.MethodSettingEntity; +import com.iailab.module.model.mpk.service.MethodSettingService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Map; + +/** + * @description: + * @author: dzd + * @date: 2024/9/14 15:12 + **/ +@Slf4j +@Service +public class MethodSettingServiceImpl extends BaseServiceImpl<MethodSettingDao, MethodSettingEntity> implements MethodSettingService { +} \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MdkFileServiceImpl.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MpkFileServiceImpl.java similarity index 88% rename from iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MdkFileServiceImpl.java rename to iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MpkFileServiceImpl.java index b37817a..d0bb2f8 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MdkFileServiceImpl.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/MpkFileServiceImpl.java @@ -15,13 +15,8 @@ import com.iailab.module.model.mpk.common.MdkConstant; import com.iailab.module.model.mpk.common.utils.GenUtils; import com.iailab.module.model.mpk.dao.MpkFileDao; -import com.iailab.module.model.mpk.dto.GeneratorCodeHistoryDTO; -import com.iailab.module.model.mpk.dto.MpkFileDTO; -import com.iailab.module.model.mpk.dto.ProjectPackageHistoryDTO; -import com.iailab.module.model.mpk.entity.GeneratorCodeHistoryEntity; -import com.iailab.module.model.mpk.entity.ModelMethodEntity; -import com.iailab.module.model.mpk.entity.MpkFileEntity; -import com.iailab.module.model.mpk.entity.ProjectPackageHistoryModelEntity; +import com.iailab.module.model.mpk.dto.*; +import com.iailab.module.model.mpk.entity.*; import com.iailab.module.model.mpk.service.*; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; @@ -36,7 +31,6 @@ import org.springframework.web.multipart.MultipartFile; import javax.annotation.PostConstruct; -import javax.annotation.Resource; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; @@ -53,7 +47,7 @@ */ @Slf4j @Service -public class MdkFileServiceImpl extends BaseServiceImpl<MpkFileDao, MpkFileEntity> implements MdkFileService { +public class MpkFileServiceImpl extends BaseServiceImpl<MpkFileDao, MpkFileEntity> implements MpkFileService { @Autowired private GeneratorCodeHistoryService generatorCodeHistoryService; @@ -63,6 +57,10 @@ private ProjectPackageHistoryService projectPackageHistoryService; @Autowired private ModelMethodService modelMethodService; + @Autowired + private MethodSettingService methodSettingService; + @Autowired + private SettingSelectService settingSelectService; @Autowired private ProjectPackageHistoryModelService projectPackageHistoryModelService; @@ -135,22 +133,56 @@ updateById(entity); String mpkId = dto.getId(); - // 删除模型方法 + // 删除模型方法 会级联删除setting和select deleteModelMethod(mpkId); // 添加模型方法 insertModelMethod(dto.getModelMethods(),mpkId); } - private void insertModelMethod(List<ModelMethodEntity> modelMethods,String mpkId) { + private void insertModelMethod(List<ModelMethodDTO> modelMethods, String mpkId) { + List<MethodSettingDTO> methodSettingList = new ArrayList<>(); if (!CollectionUtils.isEmpty(modelMethods)) { modelMethods.forEach(e -> { - e.setId(UUID.randomUUID().toString()); + String methodId = UUID.randomUUID().toString(); + e.setId(methodId); e.setMpkFileId(mpkId); + + e.getMethodSettings().forEach(s -> { + s.setId(UUID.randomUUID().toString()); + s.setMethodId(methodId); + methodSettingList.add(s); + }); + }); - modelMethodService.insertBatch(modelMethods); + modelMethodService.insertBatch(ConvertUtils.sourceToTarget(modelMethods, ModelMethodEntity.class)); + + //添加setting + insertMethodSetting(methodSettingList); } } + + private void insertMethodSetting(List<MethodSettingDTO> methodSettings) { + List<SettingSelectEntity> settingSelectList = new ArrayList<>(); + if (!CollectionUtils.isEmpty(methodSettings)) { + methodSettings.forEach(e -> { + String settingId = UUID.randomUUID().toString(); + e.setId(settingId); + + e.getSettingSelects().forEach(s -> { + s.setId(UUID.randomUUID().toString()); + s.setSettingId(settingId); + settingSelectList.add(ConvertUtils.sourceToTarget(s,SettingSelectEntity.class)); + }); + + }); + methodSettingService.insertBatch(ConvertUtils.sourceToTarget(methodSettings, MethodSettingEntity.class)); + + //添加select + settingSelectService.insertBatch(settingSelectList); + } + } + private void deleteModelMethod(String mpkId) { Map<String,Object> map = new HashMap<>(); map.put("mpkFileId", mpkId); @@ -171,9 +203,6 @@ } } - //删除 - deleteById(id); - //删除备份文件 Map<String,Object> map1 = new HashMap<>(); map1.put("mdkId",id); @@ -186,17 +215,19 @@ } }); - //删除生成历史 + //删除 会级联删除掉关联表 + deleteById(id); - generatorCodeHistoryService.deleteByMap(map1); + //删除生成历史 +// generatorCodeHistoryService.deleteByMap(map1); //删除关联项目 - Map<String,Object> map = new HashMap<>(); - map.put("modelId",id); - projectModelService.deleteByMap(map); +// Map<String,Object> map = new HashMap<>(); +// map.put("modelId",id); +// projectModelService.deleteByMap(map); //删除模型方法 - deleteModelMethod(id); +// deleteModelMethod(id); } @@ -354,7 +385,7 @@ entity.setPkgName(e.getPkgName()); entity.setPyModule(e.getPyModule()); entity.setRemark(e.getRemark()); - List<ModelMethodEntity> methods = e.getModelMethods(); + List<ModelMethodDTO> methods = e.getModelMethods(); if (!CollectionUtils.isEmpty(methods)) { entity.setMethodInfo(JSON.toJSONString(methods)); } diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/ProjectServiceImpl.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/ProjectServiceImpl.java index 5e45ff9..dc0a2fb 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/ProjectServiceImpl.java +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/ProjectServiceImpl.java @@ -137,16 +137,9 @@ @Override @Transactional(rollbackFor = Exception.class) public void delete(String id) { - - //删除 - baseDao.deleteById(id); - - //删除模型关联 + //删除备份文件 Map<String,Object> map = new HashMap<>(); map.put("projectId",id); - projectModelService.deleteByMap(map); - - //删除备份文件 List<ProjectPackageHistoryDTO> list = projectPackageHistoryService.list(map); list.forEach(e -> { File file = new File(e.getFilePath()); @@ -156,11 +149,17 @@ } }); + //删除 (级联删除) + baseDao.deleteById(id); + + //删除模型关联 +// projectModelService.deleteByMap(map); + //删除打包历史 - projectPackageHistoryService.deleteByMap(map); +// projectPackageHistoryService.deleteByMap(map); //删除打包历史模型关联 - projectPackageHistoryModelService.deleteByMap(map); +// projectPackageHistoryModelService.deleteByMap(map); } @Override diff --git a/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/SettingSelectServiceImpl.java b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/SettingSelectServiceImpl.java new file mode 100644 index 0000000..1bfba31 --- /dev/null +++ b/iailab-module-model/iailab-module-model-biz/src/main/java/com/iailab/module/model/mpk/service/impl/SettingSelectServiceImpl.java @@ -0,0 +1,37 @@ +package com.iailab.module.model.mpk.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.iailab.framework.common.service.impl.BaseServiceImpl; +import com.iailab.module.model.mpk.dao.SettingSelectDao; +import com.iailab.module.model.mpk.entity.SettingSelectEntity; +import com.iailab.module.model.mpk.service.SettingSelectService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Map; + +/** + * @description: + * @author: dzd + * @date: 2024/9/14 15:13 + **/ +@Slf4j +@Service +public class SettingSelectServiceImpl extends BaseServiceImpl<SettingSelectDao, SettingSelectEntity> implements SettingSelectService { + + + @Override + public void deleteByMap(Map<String, Object> map) { + baseDao.delete(getWrapper(map)); + } + + private QueryWrapper<SettingSelectEntity> getWrapper(Map<String, Object> params) { + String settingId = (String) params.get("settingId"); + + QueryWrapper<SettingSelectEntity> wrapper = new QueryWrapper<>(); + wrapper.eq(StringUtils.isNotBlank(settingId), "setting_id", settingId); + + return wrapper; + } +} \ No newline at end of file diff --git a/iailab-module-model/iailab-module-model-biz/src/main/resources/mapper/mpk/MpkFileDao.xml b/iailab-module-model/iailab-module-model-biz/src/main/resources/mapper/mpk/MpkFileDao.xml index 32ca7eb..3451506 100644 --- a/iailab-module-model/iailab-module-model-biz/src/main/resources/mapper/mpk/MpkFileDao.xml +++ b/iailab-module-model/iailab-module-model-biz/src/main/resources/mapper/mpk/MpkFileDao.xml @@ -5,20 +5,41 @@ <resultMap id="mpkFile" type="com.iailab.module.model.mpk.dto.MpkFileDTO"> <id property="id" column="id"/> <result property="pyName" column="py_name"/> + <result property="pyChineseName" column="py_chinese_name"/> <result property="filePath" column="file_path"/> + <result property="pyType" column="py_type"/> <result property="pkgName" column="pkg_name"/> <result property="className" column="class_name"/> <result property="pyModule" column="py_module"/> + <result property="icon" column="icon"/> + <result property="menuName" column="menu_name"/> + <result property="groupName" column="group_name"/> <result property="remark" column="remark"/> <result property="creator" column="creator"/> <result property="createDate" column="create_date"/> <result property="updater" column="updater"/> <result property="updateDate" column="update_date"/> - <collection property="modelMethods" ofType="com.iailab.module.model.mpk.entity.ModelMethodEntity"> + <collection property="modelMethods" ofType="com.iailab.module.model.mpk.dto.ModelMethodDTO"> <id property="id" column="method_id"/> <result property="methodName" column="method_name"/> <result property="dataLength" column="data_length"/> <result property="model" column="model"/> + <result property="resultKey" column="result_key"/> + <collection property="methodSettings" ofType="com.iailab.module.model.mpk.dto.MethodSettingDTO"> + <id property="id" column="setting_id"/> + <result property="settingKey" column="setting_key"/> + <result property="name" column="setting_name"/> + <result property="value" column="value"/> + <result property="type" column="type"/> + <result property="valueType" column="value_type"/> + <result property="max" column="max"/> + <result property="min" column="min"/> + <collection property="settingSelects" ofType="com.iailab.module.model.mpk.dto.SettingSelectDTO"> + <id property="id" column="select_id"/> + <result property="selectKey" column="select_key"/> + <result property="name" column="select_name"/> + </collection> + </collection> </collection> </resultMap> @@ -28,10 +49,24 @@ b.id method_id, b.method_name, b.data_length, - b.model + b.model, + b.result_key, + c.id setting_id, + c.setting_key, + c.name setting_name, + c.value, + c.type, + c.value_type, + c.max, + c.min, + d.id select_id, + d.select_key, + d.name select_name FROM t_mpk_file a LEFT JOIN t_mpk_model_method b ON a.id = b.mpk_file_id + LEFT JOIN t_mpk_method_setting c ON b.id = c.method_id + LEFT JOIN t_mpk_setting_select d ON c.id = d.setting_id WHERE a.id = #{id} </select> <select id="selectByIds" resultMap="mpkFile"> @@ -40,10 +75,24 @@ b.id method_id, b.method_name, b.data_length, - b.model + b.model, + b.result_key, + c.id setting_id, + c.setting_key, + c.name setting_name, + c.value, + c.type, + c.value_type, + c.max, + c.min, + d.id select_id, + d.select_key, + d.name select_name FROM t_mpk_file a LEFT JOIN t_mpk_model_method b ON a.id = b.mpk_file_id + LEFT JOIN t_mpk_method_setting c ON b.id = c.method_id + LEFT JOIN t_mpk_setting_select d ON c.id = d.setting_id WHERE a.id in <foreach collection="ids" item="item" open="(" close=")" separator=","> #{item} @@ -59,7 +108,22 @@ </select> <select id="getProjectModel" resultMap="mpkFile"> SELECT - t3.*,t4.method_name,t4.data_length,t4.model + t3.*, + t4.method_name, + t4.data_length, + t4.model, + t4.result_key, + t5.id setting_id, + t5.setting_key, + t5.name setting_name, + t5.value, + t5.type, + t5.value_type, + t5.max, + t5.min, + t6.id select_id, + t6.select_key, + t6.name select_name FROM ( SELECT @@ -82,5 +146,7 @@ LIMIT #{params.offset},#{params.pageSize} ) t3 LEFT JOIN t_mpk_model_method t4 ON t3.id = t4.mpk_file_id + LEFT JOIN t_mpk_method_setting t5 ON t4.id = t5.method_id + LEFT JOIN t_mpk_setting_select t6 ON t5.id = t6.setting_id </select> </mapper> \ No newline at end of file diff --git a/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/AppApi.java b/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/AppApi.java new file mode 100644 index 0000000..ff3c870 --- /dev/null +++ b/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/AppApi.java @@ -0,0 +1,31 @@ +package com.iailab.module.system.api.app; + +import com.iailab.framework.common.pojo.CommonResult; +import com.iailab.module.system.api.app.dto.AppMenuRespDTO; +import com.iailab.module.system.api.app.dto.AppRespDTO; +import com.iailab.module.system.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +@FeignClient(name = ApiConstants.NAME) +@Tag(name = "RPC 服务 - 应用菜单") +public interface AppApi { + + String PREFIX = ApiConstants.PREFIX + "/app"; + +// @GetMapping(PREFIX + "/get-menu") +// @Operation(summary = "获得应用信息") +// @Parameter(name = "id", description = "应用编号", example = "1024", required = true) +// CommonResult<List<AppMenuRespDTO>> getAppMenuList(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/list") + @Operation(summary = "获得应用菜单列表") + CommonResult<List<AppRespDTO>> getAppList(); + +} diff --git a/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/AppMenuApi.java b/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/AppMenuApi.java new file mode 100644 index 0000000..66adc90 --- /dev/null +++ b/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/AppMenuApi.java @@ -0,0 +1,32 @@ +package com.iailab.module.system.api.app; + +import com.iailab.framework.common.pojo.CommonResult; +import com.iailab.module.system.api.app.dto.AppMenuRespDTO; +import com.iailab.module.system.api.app.dto.AppRespDTO; +import com.iailab.module.system.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +@FeignClient(name = ApiConstants.NAME) +@Tag(name = "RPC 服务 - 应用菜单") +public interface AppMenuApi { + + String PREFIX = ApiConstants.PREFIX + "/app-menu"; + + @GetMapping(PREFIX + "/get-menu") + @Operation(summary = "获得应用信息") + @Parameter(name = "id", description = "应用编号", example = "1024", required = true) + CommonResult<List<AppMenuRespDTO>> getAppMenuList(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/list") + @Operation(summary = "获得应用菜单列表") + CommonResult<List<AppRespDTO>> getAppList(); + +} diff --git a/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/dto/AppMenuRespDTO.java b/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/dto/AppMenuRespDTO.java new file mode 100644 index 0000000..855e543 --- /dev/null +++ b/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/dto/AppMenuRespDTO.java @@ -0,0 +1,80 @@ +package com.iailab.module.system.api.app.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "RPC 服务 - 应用菜单 Response DTO") +@Data +public class AppMenuRespDTO { + + @Schema(description = "菜单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "平台") + @NotBlank(message = "菜单名称不能为空") + @Size(max = 50, message = "菜单名称长度不能超过50个字符") + private String name; + + @Schema(description = "权限标识,仅菜单类型为按钮时,才需要传递", example = "sys:menu:add") + @Size(max = 100) + private String permission; + + @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "菜单类型不能为空") + private Integer type; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "父菜单 ID 不能为空") + private Long parentId; + + @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post") + @Size(max = 200, message = "路由地址不能超过200个字符") + private String path; + + @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list") + private String icon; + + @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index") + @Size(max = 200, message = "组件路径不能超过255个字符") + private String component; + + @Schema(description = "组件名", example = "SystemUser") + private String componentName; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "是否可见", example = "false") + private Boolean visible; + + @Schema(description = "是否缓存", example = "false") + private Boolean keepAlive; + + @Schema(description = "是否总是显示", example = "false") + private Boolean alwaysShow; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + + /** + * 应用类型(1-系统菜单, 2-应用菜单) + */ + private Integer appType; + + /** + * 子路由 + */ + private List<AppMenuRespDTO> children; + +} diff --git a/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/dto/AppMenuSimpleRespDTO.java b/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/dto/AppMenuSimpleRespDTO.java new file mode 100644 index 0000000..91f8b0f --- /dev/null +++ b/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/dto/AppMenuSimpleRespDTO.java @@ -0,0 +1,22 @@ +package com.iailab.module.system.api.app.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "应用菜单精简信息 Response VO") +@Data +public class AppMenuSimpleRespDTO { + + @Schema(description = "菜单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "平台") + private String name; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long parentId; + + @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + +} diff --git a/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/dto/AppRespDTO.java b/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/dto/AppRespDTO.java new file mode 100644 index 0000000..88a7a23 --- /dev/null +++ b/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/app/dto/AppRespDTO.java @@ -0,0 +1,75 @@ +package com.iailab.module.system.api.app.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * @author PanZhibao + * @Description + * @createTime 2024年08月18日 + */ +@Schema(description = "管理后台 - 应用 Response VO") +@Data +public class AppRespDTO { + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用编号") + private String appCode; + + @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用名称") + private String appName; + + @Schema(description = "应用域名", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用域名") + private String appDomain; + + @Schema(description = "接口域名", requiredMode = Schema.RequiredMode.REQUIRED, example = "接口域名") + private String apiDomain; + + @Schema(description = "应用账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用账号") + private String appKey; + + @Schema(description = "应用密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用密码") + private String appSecret; + + @Schema(description = "应用分组", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用分组") + private String appGroup; + + @Schema(description = "应用加载类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用加载类型") + private Integer loadType; + + @Schema(description = "应用图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用图标") + private String icon; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "排序") + private Integer orderNum; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "状态") + private Integer status; + + @Schema(description = "开发者ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "开发者ID") + private String devId; + + @Schema(description = "开发者名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "开发者名称") + private String devName; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "租户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "租户ID") + private Long tenantId; + + @Schema(description = "应用菜单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用菜单ID") + private Long appMenuId; + + /** + * 应用类型(1-系统菜单, 2-应用菜单) + */ + private Integer appType; +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/api/app/AppApiImpl.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/api/app/AppApiImpl.java new file mode 100644 index 0000000..d66168a --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/api/app/AppApiImpl.java @@ -0,0 +1,55 @@ +package com.iailab.module.system.api.app; + +import cn.hutool.core.collection.CollUtil; +import com.iailab.framework.common.pojo.CommonResult; +import com.iailab.framework.common.util.object.BeanUtils; +import com.iailab.module.system.api.app.dto.AppMenuRespDTO; +import com.iailab.module.system.api.app.dto.AppRespDTO; +import com.iailab.module.system.convert.app.AppConvert; +import com.iailab.module.system.dal.dataobject.app.AppDO; +import com.iailab.module.system.dal.dataobject.app.AppMenuDO; +import com.iailab.module.system.service.app.AppMenuService; +import com.iailab.module.system.service.app.AppService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.*; + +import static com.iailab.framework.common.pojo.CommonResult.success; +import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class AppApiImpl implements AppApi { + + @Resource + private AppService appService; + +// @Override +// public CommonResult<List<AppMenuRespDTO>> getAppMenuList(Long id) { +// List<AppMenuDO> children = new LinkedList<>(); +// // 遍历每一层 +// Collection<Long> parentIds = Collections.singleton(id); +// for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 +// // 查询当前层,所有的子应用菜单 +// List<AppMenuDO> menus = appMenuService.selectListByParentId(parentIds); +// // 1. 如果没有子菜单,则结束遍历 +// if (CollUtil.isEmpty(menus)) { +// break; +// } +// // 2. 如果有子应用菜单,继续遍历 +// children.addAll(menus); +// parentIds = convertSet(menus, AppMenuDO::getId); +// } +//// children = appMenuService.filterDisableMenus(children); +// return success(AppConvert.INSTANCE.buildMenuTree(id, children)); +// } + + @Override + public CommonResult<List<AppRespDTO>> getAppList() { + List<AppDO> list = appService.getList(); + list.sort(Comparator.comparing(AppDO::getOrderNum)); + return success(BeanUtils.toBean(list, AppRespDTO.class)); + } +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/api/app/AppMenuApiImpl.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/api/app/AppMenuApiImpl.java new file mode 100644 index 0000000..0b103b2 --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/api/app/AppMenuApiImpl.java @@ -0,0 +1,59 @@ +package com.iailab.module.system.api.app; + +import cn.hutool.core.collection.CollUtil; +import com.iailab.framework.common.pojo.CommonResult; +import com.iailab.framework.common.util.object.BeanUtils; +import com.iailab.module.system.api.app.dto.AppMenuRespDTO; +import com.iailab.module.system.api.app.dto.AppRespDTO; +import com.iailab.module.system.controller.admin.app.vo.AppRespVO; +import com.iailab.module.system.convert.app.AppConvert; +import com.iailab.module.system.dal.dataobject.app.AppDO; +import com.iailab.module.system.dal.dataobject.app.AppMenuDO; +import com.iailab.module.system.service.app.AppMenuService; +import com.iailab.module.system.service.app.AppService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.*; + +import static com.iailab.framework.common.pojo.CommonResult.success; +import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class AppMenuApiImpl implements AppMenuApi { + + @Resource + private AppMenuService appMenuService; + + @Resource + private AppService appService; + + @Override + public CommonResult<List<AppMenuRespDTO>> getAppMenuList(Long id) { + List<AppMenuDO> children = new LinkedList<>(); + // 遍历每一层 + Collection<Long> parentIds = Collections.singleton(id); + for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 + // 查询当前层,所有的子应用菜单 + List<AppMenuDO> menus = appMenuService.selectListByParentId(parentIds); + // 1. 如果没有子菜单,则结束遍历 + if (CollUtil.isEmpty(menus)) { + break; + } + // 2. 如果有子应用菜单,继续遍历 + children.addAll(menus); + parentIds = convertSet(menus, AppMenuDO::getId); + } +// children = appMenuService.filterDisableMenus(children); + return success(AppConvert.INSTANCE.buildMenuTree(id, children)); + } + + @Override + public CommonResult<List<AppRespDTO>> getAppList() { + List<AppDO> list = appService.getList(); + list.sort(Comparator.comparing(AppDO::getOrderNum)); + return success(BeanUtils.toBean(list, AppRespDTO.class)); + } +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppController.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppController.java index c0a75be..5438a35 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppController.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppController.java @@ -6,6 +6,7 @@ import com.iailab.framework.common.pojo.PageResult; import com.iailab.framework.common.util.object.BeanUtils; import com.iailab.framework.excel.core.util.ExcelUtils; +import com.iailab.module.system.api.app.dto.AppMenuRespDTO; import com.iailab.module.system.controller.admin.app.vo.AppPageReqVO; import com.iailab.module.system.controller.admin.app.vo.AppRespVO; import com.iailab.module.system.controller.admin.app.vo.AppSaveReqVO; @@ -71,11 +72,28 @@ @GetMapping("/page") @Operation(summary = "获得分页") @PreAuthorize("@ss.hasPermission('system:app:query')") - public CommonResult<PageResult<AppRespVO>> getTenantPage(@Valid AppPageReqVO pageVO) { + public CommonResult<PageResult<AppRespVO>> getAppPage(@Valid AppPageReqVO pageVO) { PageResult<AppDO> pageResult = appService.getPage(pageVO); return success(BeanUtils.toBean(pageResult, AppRespVO.class)); } + @GetMapping("/getAppList") + @Operation(summary = "获得应用列表") + @PreAuthorize("@ss.hasPermission('system:app-menu:query')") + public CommonResult<List<AppRespVO>> getAppList() { + List<AppDO> appDOS = appService.getList(); + return success(BeanUtils.toBean(appDOS, AppRespVO.class)); + } + +// @GetMapping("/getAppMenu") +// @Operation(summary = "获得应用菜单列表") +// @PreAuthorize("@ss.hasPermission('system:app-menu:query')") +// @Parameter(name = "id", description = "ID", required = true, example = "1024") +// public CommonResult<List<AppRespVO>> getAppMenu(@RequestParam("id") Long id) { +// List<AppMenuRespDTO> appDOS = appService.getAppMenu(id); +// return success(BeanUtils.toBean(appDOS, AppRespVO.class)); +// } + @GetMapping("/export-excel") @Operation(summary = "导出租户 Excel") @PreAuthorize("@ss.hasPermission('system:tenant:export')") diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppGroupController.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppGroupController.java new file mode 100644 index 0000000..e31e9c6 --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppGroupController.java @@ -0,0 +1,83 @@ +package com.iailab.module.system.controller.admin.app; + +import com.iailab.framework.common.pojo.CommonResult; +import com.iailab.framework.common.pojo.PageResult; +import com.iailab.framework.common.util.object.BeanUtils; +import com.iailab.module.system.controller.admin.app.vo.*; +import com.iailab.module.system.dal.dataobject.app.AppGroupDO; +import com.iailab.module.system.service.app.AppGroupService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import java.util.List; + +import static com.iailab.framework.common.pojo.CommonResult.success; + +/** + * @author Houzhongjian + * @Description + * @createTime 2024年09月20日 + */ +@Tag(name = "管理后台 - 应用分组") +@RestController +@RequestMapping("/system/app-group") +public class AppGroupController { + + @Resource + private AppGroupService appGroupService; + + @PostMapping("/create") + @Operation(summary = "创建应用分组") + @PreAuthorize("@ss.hasPermission('system:app-group:create')") + public CommonResult<Long> createApp(@Valid @RequestBody AppGroupSaveReqVO createReqVO) { + return success(appGroupService.create(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新应用分组") + @PreAuthorize("@ss.hasPermission('system:app-group:update')") + public CommonResult<Boolean> updateApp(@Valid @RequestBody AppGroupSaveReqVO updateReqVO) { + appGroupService.update(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除应用分组") + @Parameter(name = "id", description = "ID", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:app-group:delete')") + public CommonResult<Boolean> deleteAppGroup(@RequestParam("id") Long id) { + appGroupService.delete(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得应用分组") + @Parameter(name = "id", description = "ID", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:app-group:query')") + public CommonResult<AppGroupRespVO> getInfo(@RequestParam("id") Long id) { + AppGroupDO data = appGroupService.getInfo(id); + return success(BeanUtils.toBean(data, AppGroupRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得分页") + @PreAuthorize("@ss.hasPermission('system:app-group:query')") + public CommonResult<PageResult<AppGroupRespVO>> getAppGroupPage(@Valid AppGroupPageReqVO pageVO) { + PageResult<AppGroupDO> pageResult = appGroupService.getPage(pageVO); + return success(BeanUtils.toBean(pageResult, AppGroupRespVO.class)); + } + + @GetMapping("/getAppGroupList") + @Operation(summary = "获得应用分组列表") + @PreAuthorize("@ss.hasPermission('system:app-group:query')") + public CommonResult<List<AppGroupRespVO>> getAppList() { + List<AppGroupDO> appGroupDOS = appGroupService.getList(); + return success(BeanUtils.toBean(appGroupDOS, AppGroupRespVO.class)); + } +} \ No newline at end of file diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppMenuController.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppMenuController.java new file mode 100644 index 0000000..5a3623a --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppMenuController.java @@ -0,0 +1,87 @@ +//package com.iailab.module.system.controller.admin.app; +// +//import com.iailab.framework.common.enums.CommonStatusEnum; +//import com.iailab.framework.common.pojo.CommonResult; +//import com.iailab.framework.common.util.object.BeanUtils; +//import com.iailab.module.system.controller.admin.app.vo.AppMenuRespVO; +//import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; +//import com.iailab.module.system.controller.admin.permission.vo.menu.MenuSaveVO; +//import com.iailab.module.system.controller.admin.permission.vo.menu.MenuSimpleRespVO; +//import com.iailab.module.system.dal.dataobject.app.AppMenuDO; +//import com.iailab.module.system.service.app.AppMenuService; +//import io.swagger.v3.oas.annotations.Operation; +//import io.swagger.v3.oas.annotations.Parameter; +//import io.swagger.v3.oas.annotations.tags.Tag; +//import org.springframework.security.access.prepost.PreAuthorize; +//import org.springframework.validation.annotation.Validated; +//import org.springframework.web.bind.annotation.*; +// +//import javax.annotation.Resource; +//import javax.validation.Valid; +//import java.util.Comparator; +//import java.util.List; +// +//import static com.iailab.framework.common.pojo.CommonResult.success; +// +//@Tag(name = "应用菜单") +//@RestController +//@RequestMapping("/system/app-menu") +//@Validated +//public class AppMenuController { +// +// @Resource +// private AppMenuService appMenuService; +// +// @PostMapping("/create") +// @Operation(summary = "创建菜单") +// @PreAuthorize("@ss.hasPermission('system:app-menu:create')") +// public CommonResult<Long> createMenu(@Valid @RequestBody MenuSaveVO createReqVO) { +// Long menuId = appMenuService.createMenu(createReqVO); +// return success(menuId); +// } +// +// @PutMapping("/update") +// @Operation(summary = "修改菜单") +// @PreAuthorize("@ss.hasPermission('system:app-menu:update')") +// public CommonResult<Boolean> updateMenu(@Valid @RequestBody MenuSaveVO updateReqVO) { +// appMenuService.updateMenu(updateReqVO); +// return success(true); +// } +// +// @DeleteMapping("/delete") +// @Operation(summary = "删除菜单") +// @Parameter(name = "id", description = "菜单编号", required= true, example = "1024") +// @PreAuthorize("@ss.hasPermission('system:app-menu:delete')") +// public CommonResult<Boolean> deleteMenu(@RequestParam("id") Long id) { +// appMenuService.deleteMenu(id); +// return success(true); +// } +// +// @GetMapping("/list") +// @Operation(summary = "获取菜单列表", description = "用于【菜单管理】界面") +// @PreAuthorize("@ss.hasPermission('system:app-menu:query')") +// public CommonResult<List<AppMenuRespVO>> getMenuList(MenuListReqVO reqVO) { +// List<AppMenuDO> list = appMenuService.getMenuList(reqVO); +// list.sort(Comparator.comparing(AppMenuDO::getSort)); +// return success(BeanUtils.toBean(list, AppMenuRespVO.class)); +// } +// +// @GetMapping({"/list-all-simple", "simple-list"}) +// @Operation(summary = "获取菜单精简信息列表", description = "只包含被开启的菜单,用于【角色分配菜单】功能的选项。" + +// "在多租户的场景下,会只返回租户所在套餐有的菜单") +// public CommonResult<List<MenuSimpleRespVO>> getSimpleMenuList() { +// List<AppMenuDO> list = appMenuService.getMenuListByTenant( +// new MenuListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus())); +// list.sort(Comparator.comparing(AppMenuDO::getSort)); +// return success(BeanUtils.toBean(list, MenuSimpleRespVO.class)); +// } +// +// @GetMapping("/get") +// @Operation(summary = "获取菜单信息") +// @PreAuthorize("@ss.hasPermission('system:app-menu:query')") +// public CommonResult<AppMenuRespVO> getMenu(Long id) { +// AppMenuDO menu = appMenuService.getMenu(id); +// return success(BeanUtils.toBean(menu, AppMenuRespVO.class)); +// } +// +//} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppGroupPageReqVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppGroupPageReqVO.java new file mode 100644 index 0000000..1151c61 --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppGroupPageReqVO.java @@ -0,0 +1,23 @@ +package com.iailab.module.system.controller.admin.app.vo; + +import com.iailab.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * @author Houzhongjian + * @Description + * @createTime 2024年09月20日 + */ +@Schema(description = "管理后台 - 应用分组分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AppGroupPageReqVO extends PageParam { + + private String code; + + private String name; +} \ No newline at end of file diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppGroupRespVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppGroupRespVO.java new file mode 100644 index 0000000..8d25a50 --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppGroupRespVO.java @@ -0,0 +1,48 @@ +package com.iailab.module.system.controller.admin.app.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * @author Houzhongjian + * @Description + * @createTime 2024年09月20日 + */ +@Schema(description = "管理后台 - 应用分组 Response VO") +@Data +@ExcelIgnoreUnannotated +public class AppGroupRespVO { + + @Schema(description = "应用分组id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("应用分组id") + private Long id; + + @Schema(description = "应用分组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用分组编号") + @ExcelProperty("应用分组编号") + private String code; + + @Schema(description = "应用分组名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用分组名称") + @ExcelProperty("应用分组名称") + private String name; + + @Schema(description = "应用分组图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用分组图标") + @ExcelProperty("应用分组图标") + private String icon; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "排序") + @ExcelProperty("排序") + private Integer sort; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "备注") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppGroupSaveReqVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppGroupSaveReqVO.java new file mode 100644 index 0000000..08afc59 --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppGroupSaveReqVO.java @@ -0,0 +1,36 @@ +package com.iailab.module.system.controller.admin.app.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * @author PanZhibao + * @Description + * @createTime 2024年08月17日 + */ +@Schema(description = "管理后台 - 应用创建/修改 Request VO") +@Data +public class AppGroupSaveReqVO { + + @Schema(description = "ID") + private Long id; + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "应用编号不能为空") + private String code; + + @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "应用名称不能为空") + private String name; + + @Schema(description = "应用图标", example = "") + private String icon; + + @Schema(description = "排序", example = "") + private Integer sort; + + @Schema(description = "备注", example = "") + private String remark; +} \ No newline at end of file diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuListReqVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuListReqVO.java new file mode 100644 index 0000000..dabee4a --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuListReqVO.java @@ -0,0 +1,16 @@ +package com.iailab.module.system.controller.admin.app.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "应用菜单列表 Request VO") +@Data +public class AppMenuListReqVO { + + @Schema(description = "菜单名称,模糊匹配", example = "平台") + private String name; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuRespVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuRespVO.java new file mode 100644 index 0000000..6eaccb4 --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuRespVO.java @@ -0,0 +1,69 @@ +package com.iailab.module.system.controller.admin.app.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; + +@Schema(description = "应用菜单信息 Response VO") +@Data +public class AppMenuRespVO { + + @Schema(description = "菜单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "平台") + @NotBlank(message = "菜单名称不能为空") + @Size(max = 50, message = "菜单名称长度不能超过50个字符") + private String name; + + @Schema(description = "权限标识,仅菜单类型为按钮时,才需要传递", example = "sys:menu:add") + @Size(max = 100) + private String permission; + + @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "菜单类型不能为空") + private Integer type; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "父菜单 ID 不能为空") + private Long parentId; + + @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post") + @Size(max = 200, message = "路由地址不能超过200个字符") + private String path; + + @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list") + private String icon; + + @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index") + @Size(max = 200, message = "组件路径不能超过255个字符") + private String component; + + @Schema(description = "组件名", example = "SystemUser") + private String componentName; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "是否可见", example = "false") + private Boolean visible; + + @Schema(description = "是否缓存", example = "false") + private Boolean keepAlive; + + @Schema(description = "是否总是显示", example = "false") + private Boolean alwaysShow; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuSaveVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuSaveVO.java new file mode 100644 index 0000000..57dd66b --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuSaveVO.java @@ -0,0 +1,65 @@ +package com.iailab.module.system.controller.admin.app.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Schema(description = "应用菜单创建/修改 Request VO") +@Data +public class AppMenuSaveVO { + + @Schema(description = "菜单编号", example = "1024") + private Long id; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "平台") + @NotBlank(message = "菜单名称不能为空") + @Size(max = 50, message = "菜单名称长度不能超过50个字符") + private String name; + + @Schema(description = "权限标识,仅菜单类型为按钮时,才需要传递", example = "sys:menu:add") + @Size(max = 100) + private String permission; + + @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "菜单类型不能为空") + private Integer type; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "父菜单 ID 不能为空") + private Long parentId; + + @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post") + @Size(max = 200, message = "路由地址不能超过200个字符") + private String path; + + @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list") + private String icon; + + @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index") + @Size(max = 200, message = "组件路径不能超过255个字符") + private String component; + + @Schema(description = "组件名", example = "SystemUser") + private String componentName; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "是否可见", example = "false") + private Boolean visible; + + @Schema(description = "是否缓存", example = "false") + private Boolean keepAlive; + + @Schema(description = "是否总是显示", example = "false") + private Boolean alwaysShow; + +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuSimpleRespVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuSimpleRespVO.java new file mode 100644 index 0000000..5f8162b --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppMenuSimpleRespVO.java @@ -0,0 +1,22 @@ +package com.iailab.module.system.controller.admin.app.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "应用菜单精简信息 Response VO") +@Data +public class AppMenuSimpleRespVO { + + @Schema(description = "菜单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "平台") + private String name; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long parentId; + + @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppRespVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppRespVO.java index b7431b6..7a14ec9 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppRespVO.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppRespVO.java @@ -2,6 +2,7 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableField; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -17,8 +18,8 @@ @ExcelIgnoreUnannotated public class AppRespVO { - @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @ExcelProperty("应用编号") + @Schema(description = "应用ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("应用ID") private Long id; @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用编号") @@ -28,6 +29,10 @@ @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用名称") @ExcelProperty("应用名称") private String appName; + + @Schema(description = "应用类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用类型") + @ExcelProperty("应用类型") + private Integer type; @Schema(description = "应用域名", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用域名") @ExcelProperty("应用域名") @@ -80,4 +85,21 @@ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") private LocalDateTime createTime; + + @Schema(description = "租户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "租户ID") + @ExcelProperty("开发者ID") + private Long tenantId; + + @Schema(description = "应用菜单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用菜单ID") + private Long appMenuId; + + @Schema(description = "应用分组ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用分组ID") + private Long groupId; + + /** + * 应用类型(1-系统菜单, 2-应用菜单) + */ + @TableField(exist = false) + private Integer appType; + } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppSaveReqVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppSaveReqVO.java index 8e11b46..95924ca 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppSaveReqVO.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/vo/AppSaveReqVO.java @@ -1,5 +1,6 @@ package com.iailab.module.system.controller.admin.app.vo; +import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -24,6 +25,10 @@ @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "应用名称不能为空") private String appName; + + @Schema(description = "应用类型", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("应用类型") + private Integer type; @Schema(description = "应用域名", example = "") private String appDomain; @@ -60,4 +65,10 @@ @Schema(description = "备注", example = "") private String remark; + + @Schema(description = "租户ID", example = "") + private Long tenantId; + + @Schema(description = "分组ID", example = "") + private Long groupId; } \ No newline at end of file diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java index 9aa2241..1637ed5 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java @@ -8,11 +8,14 @@ import com.iailab.framework.security.config.SecurityProperties; import com.iailab.framework.security.core.util.SecurityFrameworkUtils; import com.iailab.module.system.controller.admin.auth.vo.*; +import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; import com.iailab.module.system.convert.auth.AuthConvert; +import com.iailab.module.system.dal.dataobject.app.AppDO; import com.iailab.module.system.dal.dataobject.permission.MenuDO; import com.iailab.module.system.dal.dataobject.permission.RoleDO; import com.iailab.module.system.dal.dataobject.user.AdminUserDO; import com.iailab.module.system.enums.logger.LoginLogTypeEnum; +import com.iailab.module.system.service.app.AppService; import com.iailab.module.system.service.auth.AdminAuthService; import com.iailab.module.system.service.permission.MenuService; import com.iailab.module.system.service.permission.PermissionService; @@ -38,6 +41,7 @@ import static com.iailab.framework.common.pojo.CommonResult.success; import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet; import static com.iailab.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static com.iailab.framework.tenant.core.context.TenantContextHolder.getTenantId; @Tag(name = "管理后台 - 认证") @@ -59,9 +63,10 @@ private PermissionService permissionService; @Resource private SocialClientService socialClientService; - @Resource private SecurityProperties securityProperties; + @Resource + private AppService appService; @PostMapping("/login") @PermitAll @@ -116,6 +121,34 @@ return success(AuthConvert.INSTANCE.convert(user, roles, menuList)); } + @GetMapping("/get-app-permission-info") + @Operation(summary = "获取登录用户的app权限信息") + public CommonResult<AuthPermissionInfoRespVO> getAppPermissionInfo() { + // 1.1 获得用户信息 + AdminUserDO user = userService.getUser(getLoginUserId()); + if (user == null) { + return success(null); + } + + // 1.2 获得角色列表 + Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId()); + if (CollUtil.isEmpty(roleIds)) { + return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList())); + } + List<RoleDO> roles = roleService.getRoleList(roleIds); + roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色 + + // 1.3 获得应用菜单列表 + MenuListReqVO reqVO = new MenuListReqVO(); + List<MenuDO> appMenuList = menuService.getAppMenuList(reqVO); + Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId)); + List<MenuDO> menuList = menuService.getMenuList(menuIds); + menuList.retainAll(appMenuList); + menuList = menuService.filterDisableMenus(menuList); + // 2. 拼接结果返回 + return success(AuthConvert.INSTANCE.convertAppMenu(user, roles, menuList)); + } + // ========== 短信登录相关 ========== @PostMapping("/sms-login") diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenController.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenController.java index 44791bf..a1fe484 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenController.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenController.java @@ -11,6 +11,7 @@ import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO; import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; +import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenLoginReqVO; import com.iailab.module.system.convert.oauth2.OAuth2OpenConvert; import com.iailab.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; import com.iailab.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; @@ -84,25 +85,16 @@ @PostMapping("/token") @PermitAll @Operation(summary = "获得访问令牌", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用") - @Parameters({ - @Parameter(name = "grant_type", required = true, description = "授权类型", example = "code"), - @Parameter(name = "code", description = "授权范围", example = "userinfo.read"), - @Parameter(name = "redirect_uri", description = "重定向 URI", example = "https://www.baidu.com"), - @Parameter(name = "state", description = "状态", example = "1"), - @Parameter(name = "username", example = "tudou"), - @Parameter(name = "password", example = "cai"), // 多个使用空格分隔 - @Parameter(name = "scope", example = "user_info"), - @Parameter(name = "refresh_token", example = "123424233"), - }) public CommonResult<OAuth2OpenAccessTokenRespVO> postAccessToken(HttpServletRequest request, - @RequestParam("grant_type") String grantType, - @RequestParam(value = "code", required = false) String code, // 授权码模式 - @RequestParam(value = "redirect_uri", required = false) String redirectUri, // 授权码模式 - @RequestParam(value = "state", required = false) String state, // 授权码模式 - @RequestParam(value = "username", required = false) String username, // 密码模式 - @RequestParam(value = "password", required = false) String password, // 密码模式 - @RequestParam(value = "scope", required = false) String scope, // 密码模式 - @RequestParam(value = "refresh_token", required = false) String refreshToken) { // 刷新模式 + @RequestBody OAuth2OpenLoginReqVO openLoginReqVO) { + String code = openLoginReqVO.getCode(); + String scope = openLoginReqVO.getScope(); + String grantType = openLoginReqVO.getGrantType(); + String redirectUri = openLoginReqVO.getRedirectUri(); + String state = openLoginReqVO.getState(); + String username = openLoginReqVO.getUsername(); + String password = openLoginReqVO.getPassword(); + String refreshToken = openLoginReqVO.getRefreshToken(); List<String> scopes = OAuth2Utils.buildScopes(scope); // 1.1 校验授权类型 OAuth2GrantTypeEnum grantTypeEnum = OAuth2GrantTypeEnum.getByGrantType(grantType); diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java index bf5ba85..d297a21 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java @@ -12,21 +12,20 @@ @AllArgsConstructor public class OAuth2OpenAccessTokenRespVO { + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long userId; + @Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") - @JsonProperty("access_token") private String accessToken; @Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "nice") - @JsonProperty("refresh_token") private String refreshToken; @Schema(description = "令牌类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "bearer") - @JsonProperty("token_type") private String tokenType; @Schema(description = "过期时间,单位:秒", requiredMode = Schema.RequiredMode.REQUIRED, example = "42430") - @JsonProperty("expires_in") - private Long expiresIn; + private Long expiresTime; @Schema(description = "授权范围,如果多个授权范围,使用空格分隔", example = "user_info") private String scope; diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenLoginReqVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenLoginReqVO.java new file mode 100644 index 0000000..f67ff9e --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenLoginReqVO.java @@ -0,0 +1,54 @@ +package com.iailab.module.system.controller.admin.oauth2.vo.open; + +import cn.hutool.core.util.StrUtil; +import com.iailab.framework.common.validation.InEnum; +import com.iailab.module.system.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; + +@Schema(description = "管理后台 - 账号密码授权登录 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class OAuth2OpenLoginReqVO { + + @Schema(description = "授权类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "password") + private String grantType; + + //授权码模式 + @Schema(description = "授权范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private String code; + + @Schema(description = "重定向 URI", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private String redirectUri; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private String state; + + //密码模式 + @Schema(description = "授权范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private String scope; + + @Schema(description = "账号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "iailabyuanma") + @Length(min = 4, max = 16, message = "账号长度为 4-16 位") + @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") + private String username; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "buzhidao") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + + //刷新模式 + @Schema(description = "刷新token", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private String refreshToken; + +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/MenuController.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/MenuController.java index d7eba44..67553f1 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/MenuController.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/MenuController.java @@ -40,10 +40,26 @@ return success(menuId); } + @PostMapping("/createAppMenu") + @Operation(summary = "创建菜单") + @PreAuthorize("@ss.hasPermission('system:app-menu:create')") + public CommonResult<Long> createAppMenu(@Valid @RequestBody MenuSaveVO createReqVO) { + Long menuId = menuService.createMenu(createReqVO); + return success(menuId); + } + @PutMapping("/update") @Operation(summary = "修改菜单") @PreAuthorize("@ss.hasPermission('system:menu:update')") public CommonResult<Boolean> updateMenu(@Valid @RequestBody MenuSaveVO updateReqVO) { + menuService.updateMenu(updateReqVO); + return success(true); + } + + @PutMapping("/updateAppMenu") + @Operation(summary = "修改菜单") + @PreAuthorize("@ss.hasPermission('system:app-menu:update')") + public CommonResult<Boolean> updateAppMenu(@Valid @RequestBody MenuSaveVO updateReqVO) { menuService.updateMenu(updateReqVO); return success(true); } @@ -57,11 +73,30 @@ return success(true); } + @DeleteMapping("/deleteAppMenu") + @Operation(summary = "删除菜单") + @Parameter(name = "id", description = "菜单编号", required= true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:app-menu:delete')") + public CommonResult<Boolean> deleteAppMenu(@RequestParam("id") Long id) { + menuService.deleteMenu(id); + return success(true); + } + + @GetMapping("/list") @Operation(summary = "获取菜单列表", description = "用于【菜单管理】界面") @PreAuthorize("@ss.hasPermission('system:menu:query')") public CommonResult<List<MenuRespVO>> getMenuList(MenuListReqVO reqVO) { List<MenuDO> list = menuService.getMenuList(reqVO); + list.sort(Comparator.comparing(MenuDO::getSort)); + return success(BeanUtils.toBean(list, MenuRespVO.class)); + } + + @GetMapping("/app-menu-list") + @Operation(summary = "获取应用菜单列表", description = "用于【应用菜单】界面") + @PreAuthorize("@ss.hasPermission('system:app-menu:query')") + public CommonResult<List<MenuRespVO>> getAppMenuList(MenuListReqVO reqVO) { + List<MenuDO> list = menuService.getAppMenuList(reqVO); list.sort(Comparator.comparing(MenuDO::getSort)); return success(BeanUtils.toBean(list, MenuRespVO.class)); } @@ -76,6 +111,16 @@ return success(BeanUtils.toBean(list, MenuSimpleRespVO.class)); } + @GetMapping({"simple-app-menus"}) + @Operation(summary = "获取应用菜单精简信息列表", description = "只包含被开启的菜单,用于【角色分配菜单】功能的选项。" + + "在多租户的场景下,会只返回租户所在套餐有的菜单") + public CommonResult<List<MenuSimpleRespVO>> getSimpleAppMenuList() { + List<MenuDO> list = menuService.getAppMenuListByTenant( + new MenuListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus())); + list.sort(Comparator.comparing(MenuDO::getSort)); + return success(BeanUtils.toBean(list, MenuSimpleRespVO.class)); + } + @GetMapping("/get") @Operation(summary = "获取菜单信息") @PreAuthorize("@ss.hasPermission('system:menu:query')") @@ -84,4 +129,12 @@ return success(BeanUtils.toBean(menu, MenuRespVO.class)); } + @GetMapping("/getAppMenu") + @Operation(summary = "获取菜单信息") + @PreAuthorize("@ss.hasPermission('system:app-menu:query')") + public CommonResult<MenuRespVO> getAppMenu(Long id) { + MenuDO menu = menuService.getMenu(id); + return success(BeanUtils.toBean(menu, MenuRespVO.class)); + } + } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/PermissionController.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/PermissionController.java index 26ff774..0bf9e24 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/PermissionController.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/PermissionController.java @@ -43,6 +43,14 @@ return success(permissionService.getRoleMenuListByRoleId(roleId)); } + @Operation(summary = "获得角色拥有的菜单编号") + @Parameter(name = "roleId", description = "角色编号", required = true) + @GetMapping("/list-role-app-menus") + @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") + public CommonResult<Set<Long>> getRoleAppMenuList(Long roleId) { + return success(permissionService.getRoleAppMenuListByRoleId(roleId)); + } + @PostMapping("/assign-role-menu") @Operation(summary = "赋予角色菜单") @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") @@ -55,6 +63,15 @@ return success(true); } + @PostMapping("/assign-role-app-menu") + @Operation(summary = "赋予角色菜单") + @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") + public CommonResult<Boolean> assignRoleAppMenu(@Validated @RequestBody PermissionAssignRoleMenuReqVO reqVO) { + // 执行菜单的分配 + permissionService.assignRoleAppMenu(reqVO.getRoleId(), reqVO.getMenuIds()); + return success(true); + } + @PostMapping("/assign-role-data-scope") @Operation(summary = "赋予角色数据权限") @PreAuthorize("@ss.hasPermission('system:permission:assign-role-data-scope')") diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/vo/menu/MenuRespVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/vo/menu/MenuRespVO.java index f6916ae..a986432 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/vo/menu/MenuRespVO.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/vo/menu/MenuRespVO.java @@ -66,4 +66,7 @@ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") private LocalDateTime createTime; + @Schema(description = "应用ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Long appId; + } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/vo/menu/MenuSaveVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/vo/menu/MenuSaveVO.java index a9f5e24..7068a12 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/vo/menu/MenuSaveVO.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/vo/menu/MenuSaveVO.java @@ -62,4 +62,7 @@ @Schema(description = "是否总是显示", example = "false") private Boolean alwaysShow; + @Schema(description = "应用ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Long appId; + } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/tenant/TenantController.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/tenant/TenantController.java index eebfc3b..1e0aede 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/tenant/TenantController.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/tenant/TenantController.java @@ -95,6 +95,14 @@ return success(BeanUtils.toBean(pageResult, TenantRespVO.class)); } + @GetMapping("/simple-list") + @Operation(summary = "获得租户精简列表") + @PreAuthorize("@ss.hasPermission('system:tenant:query')") + public CommonResult<List<TenantSimpleRespVO>> getSimpleTenant() { + List<TenantDO> listResult = tenantService.getSimpleTenant(); + return success(BeanUtils.toBean(listResult, TenantSimpleRespVO.class)); + } + @GetMapping("/export-excel") @Operation(summary = "导出租户 Excel") @PreAuthorize("@ss.hasPermission('system:tenant:export')") diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/app/AppConvert.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/app/AppConvert.java new file mode 100644 index 0000000..a05c3cc --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/app/AppConvert.java @@ -0,0 +1,60 @@ +package com.iailab.module.system.convert.app; + +import cn.hutool.core.collection.CollUtil; +import com.iailab.module.system.api.app.dto.AppMenuRespDTO; +import com.iailab.module.system.dal.dataobject.app.AppMenuDO; +import com.iailab.module.system.enums.permission.MenuTypeEnum; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; +import org.slf4j.LoggerFactory; + +import java.util.*; + +import static com.iailab.framework.common.util.collection.CollectionUtils.filterList; + +@Mapper +public interface AppConvert { + + AppConvert INSTANCE = Mappers.getMapper(AppConvert.class); + + AppMenuRespDTO convertTreeNode(AppMenuDO menu); + + /** + * 将菜单列表,构建成菜单树 + * + * @param menuList 菜单列表 + * @return 菜单树 + */ + default List<AppMenuRespDTO> buildMenuTree(Long id, List<AppMenuDO> menuList) { + if (CollUtil.isEmpty(menuList)) { + return Collections.emptyList(); + } + // 移除按钮 + menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType())); + // 排序,保证菜单的有序性 + menuList.sort(Comparator.comparing(AppMenuDO::getSort)); + + // 构建菜单树 + // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 + Map<Long, AppMenuRespDTO> treeNodeMap = new LinkedHashMap<>(); + menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AppConvert.INSTANCE.convertTreeNode(menu))); + // 处理父子关系 + treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(id)).forEach(childNode -> { + // 获得父节点 + AppMenuRespDTO parentNode = treeNodeMap.get(childNode.getParentId()); + if (parentNode == null) { + LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]", + childNode.getId(), childNode.getParentId()); + return; + } + // 将自己添加到父节点中 + if (parentNode.getChildren() == null) { + parentNode.setChildren(new ArrayList<>()); + } + parentNode.getChildren().add(childNode); + }); + // 获得到所有的根节点 + return filterList(treeNodeMap.values(), node -> id.equals(node.getParentId())); + } + +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java index bbf1c50..446a341 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java @@ -28,7 +28,7 @@ AuthLoginRespVO convert(OAuth2AccessTokenDO bean); - default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) { + default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) { return AuthPermissionInfoRespVO.builder() .user(BeanUtils.toBean(user, AuthPermissionInfoRespVO.UserVO.class)) .roles(convertSet(roleList, RoleDO::getCode)) @@ -36,6 +36,17 @@ .permissions(convertSet(menuList, MenuDO::getPermission)) // 菜单树 .menus(buildMenuTree(menuList)) + .build(); + } + + default AuthPermissionInfoRespVO convertAppMenu(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) { + return AuthPermissionInfoRespVO.builder() + .user(BeanUtils.toBean(user, AuthPermissionInfoRespVO.UserVO.class)) + .roles(convertSet(roleList, RoleDO::getCode)) + // 权限标识信息 + .permissions(convertSet(menuList, MenuDO::getPermission)) + // 菜单树 + .menus(buildAppMenuTree(menuList)) .build(); } @@ -51,7 +62,7 @@ if (CollUtil.isEmpty(menuList)) { return Collections.emptyList(); } - // 移除按钮 + // 移除按钮和应用菜单 menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType())); // 排序,保证菜单的有序性 menuList.sort(Comparator.comparing(MenuDO::getSort)); @@ -79,6 +90,87 @@ return filterList(treeNodeMap.values(), node -> ID_ROOT.equals(node.getParentId())); } + /** + * 将菜单列表,构建成菜单树 + * + * @param menuList 菜单列表 + * @return 菜单树 + */ + default List<AuthPermissionInfoRespVO.MenuVO> buildAppMenuTree(List<MenuDO> menuList) { + if (CollUtil.isEmpty(menuList)) { + return Collections.emptyList(); + } + // 移除按钮和应用菜单 + menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType())); + // 排序,保证菜单的有序性 + menuList.sort(Comparator.comparing(MenuDO::getSort)); + + // 构建菜单树 + // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 + Map<Long, AuthPermissionInfoRespVO.MenuVO> treeNodeMap = new LinkedHashMap<>(); + menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu))); + // 处理父子关系 + treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(ID_ROOT)).forEach(childNode -> { + // 获得父节点 + AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getParentId()); + if (parentNode == null) { + LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]", + childNode.getId(), childNode.getParentId()); + return; + } + // 将自己添加到父节点中 + if (parentNode.getChildren() == null) { + parentNode.setChildren(new ArrayList<>()); + } + parentNode.getChildren().add(childNode); + }); + // 获得到所有的根节点 + return filterList(treeNodeMap.values(), node -> ID_ROOT.equals(node.getParentId())); + } + + /** + * 将菜单列表,构建成菜单树 + * + * @param menuList 菜单列表 + * @return 菜单树 + */ + default List<AuthPermissionInfoRespVO.MenuVO> buildMenuTree(List<MenuDO> menuList, Long id, String parentPath) { + if (CollUtil.isEmpty(menuList)) { + return Collections.emptyList(); + } + // 移除按钮 + menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType())); + // 排序,保证菜单的有序性 + menuList.sort(Comparator.comparing(MenuDO::getSort)); + + // 构建菜单树 + // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 + Map<Long, AuthPermissionInfoRespVO.MenuVO> treeNodeMap = new LinkedHashMap<>(); + menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu))); + // 处理父子关系 + treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(id)).forEach(childNode -> { + // 获得父节点 + AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getParentId()); + if (parentNode == null) { + LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]", + childNode.getId(), childNode.getParentId()); + return; + } + // 将自己添加到父节点中 + if (parentNode.getChildren() == null) { + parentNode.setChildren(new ArrayList<>()); + } + parentNode.getChildren().add(childNode); + + }); + // 获得到所有的根节点 + List<AuthPermissionInfoRespVO.MenuVO> menuVOS = filterList(treeNodeMap.values(), node -> id.equals(node.getParentId())); + menuVOS.stream().forEach(menuVO -> { + menuVO.setPath(parentPath + "/" + menuVO.getPath()); + }); + return menuVOS; + } + SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialLoginReqVO reqVO); SmsCodeSendReqDTO convert(AuthSmsSendReqVO reqVO); diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/oauth2/OAuth2OpenConvert.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/oauth2/OAuth2OpenConvert.java index fec67ac..fc97c28 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/oauth2/OAuth2OpenConvert.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/oauth2/OAuth2OpenConvert.java @@ -28,7 +28,6 @@ default OAuth2OpenAccessTokenRespVO convert(OAuth2AccessTokenDO bean) { OAuth2OpenAccessTokenRespVO respVO = BeanUtils.toBean(bean, OAuth2OpenAccessTokenRespVO.class); respVO.setTokenType(SecurityFrameworkUtils.AUTHORIZATION_BEARER.toLowerCase()); - respVO.setExpiresIn(OAuth2Utils.getExpiresIn(bean.getExpiresTime())); respVO.setScope(OAuth2Utils.buildScopeStr(bean.getScopes())); return respVO; } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/app/AppDO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/app/AppDO.java index 2198bc7..d3b27c1 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/app/AppDO.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/app/AppDO.java @@ -1,6 +1,7 @@ package com.iailab.module.system.dal.dataobject.app; import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.iailab.framework.mybatis.core.dataobject.BaseDO; @@ -38,6 +39,11 @@ * 应用名称 */ private String appName; + + /** + * 应用类型 + */ + private Integer type; /** * 应用域名 @@ -99,4 +105,26 @@ */ private String remark; + /** + * 租户ID + */ + private Long tenantId; + + /** + * 分组ID + */ + private Long groupId; + + /** + * 应用类型(1-系统菜单, 2-应用菜单) + */ + @TableField(exist = false) + private Integer appType; + + /** + * 应用菜单id + */ + @TableField(exist = false) + private Long appMenuId; + } \ No newline at end of file diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/app/AppGroupDO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/app/AppGroupDO.java new file mode 100644 index 0000000..9c50371 --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/app/AppGroupDO.java @@ -0,0 +1,57 @@ +package com.iailab.module.system.dal.dataobject.app; + +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.iailab.framework.mybatis.core.dataobject.BaseDO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分组分组表 + * + * @author Houzhongjian + * @Description + * @createTime 2024年09月20日 + */ +@TableName("system_app_group") +@KeySequence("system_app_group_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class AppGroupDO extends BaseDO { + + public static final Long PARENT_ID_ROOT = 0L; + + /** + * ID + */ + @TableId + private Long id; + + /** + * 分组编号 + */ + private String code; + + /** + * 分组名称 + */ + private String name; + + /** + * 分组图标 + */ + private String icon; + + /** + * 排序 + */ + private Integer sort; + + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/app/AppMenuDO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/app/AppMenuDO.java new file mode 100644 index 0000000..969b8d2 --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/app/AppMenuDO.java @@ -0,0 +1,114 @@ +package com.iailab.module.system.dal.dataobject.app; + +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.iailab.framework.common.enums.CommonStatusEnum; +import com.iailab.framework.mybatis.core.dataobject.BaseDO; +import com.iailab.framework.tenant.core.db.TenantBaseDO; +import com.iailab.module.system.enums.permission.MenuTypeEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 菜单 DO + * + * @author ruoyi + */ +@TableName("system_app_menu") +@KeySequence("system_app_menu_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class AppMenuDO extends BaseDO { + + /** + * 菜单编号 - 根节点 + */ + public static final Long ID_ROOT = 0L; + + /** + * 菜单编号 + */ + @TableId + private Long id; + /** + * 菜单名称 + */ + private String name; + /** + * 权限标识 + * + * 一般格式为:${系统}:${模块}:${操作} + * 例如说:system:admin:add,即 system 服务的添加管理员。 + * + * 当我们把该 MenuDO 赋予给角色后,意味着该角色有该资源: + * - 对于后端,配合 @PreAuthorize 注解,配置 API 接口需要该权限,从而对 API 接口进行权限控制。 + * - 对于前端,配合前端标签,配置按钮是否展示,避免用户没有该权限时,结果可以看到该操作。 + */ + private String permission; + /** + * 菜单类型 + * + * 枚举 {@link MenuTypeEnum} + */ + private Integer type; + /** + * 显示顺序 + */ + private Integer sort; + /** + * 父菜单ID + */ + private Long parentId; + /** + * 路由地址 + * + * 如果 path 为 http(s) 时,则它是外链 + */ + private String path; + /** + * 菜单图标 + */ + private String icon; + /** + * 组件路径 + */ + private String component; + /** + * 组件名 + */ + private String componentName; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 是否可见 + * + * 只有菜单、目录使用 + * 当设置为 true 时,该菜单不会展示在侧边栏,但是路由还是存在。例如说,一些独立的编辑页面 /edit/1024 等等 + */ + private Boolean visible; + /** + * 是否缓存 + * + * 只有菜单、目录使用,否使用 Vue 路由的 keep-alive 特性 + * 注意:如果开启缓存,则必须填写 {@link #componentName} 属性,否则无法缓存 + */ + private Boolean keepAlive; + /** + * 是否总是显示 + * + * 如果为 false 时,当该菜单只有一个子菜单时,不展示自己,直接展示子菜单 + */ + private Boolean alwaysShow; + + /** + * 应用ID + */ + private Long appId; + + +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/permission/MenuDO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/permission/MenuDO.java index ae0465b..fd8dc73 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/permission/MenuDO.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/dataobject/permission/MenuDO.java @@ -104,4 +104,15 @@ */ private Boolean alwaysShow; + /** + * 应用ID + */ + private Long appId; + + /** + * 租户ID + */ + private Long tenantId; + + } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/app/AppGroupMapper.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/app/AppGroupMapper.java new file mode 100644 index 0000000..a3dbc64 --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/app/AppGroupMapper.java @@ -0,0 +1,24 @@ +package com.iailab.module.system.dal.mysql.app; + +import com.iailab.framework.common.pojo.PageResult; +import com.iailab.framework.mybatis.core.mapper.BaseMapperX; +import com.iailab.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.iailab.framework.tenant.core.aop.TenantIgnore; +import com.iailab.module.system.controller.admin.app.vo.AppGroupPageReqVO; +import com.iailab.module.system.dal.dataobject.app.AppGroupDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * @author Houzhongjian + * @Description + * @createTime 2024年09月10日 + */ +@Mapper +public interface AppGroupMapper extends BaseMapperX<AppGroupDO> { + default PageResult<AppGroupDO> selectPage(AppGroupPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX<AppGroupDO>() + .likeIfPresent(AppGroupDO::getCode, reqVO.getCode()) + .likeIfPresent(AppGroupDO::getName, reqVO.getName()) + .orderByDesc(AppGroupDO::getId)); + } +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/app/AppMenuMapper.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/app/AppMenuMapper.java new file mode 100644 index 0000000..a0fc545 --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/app/AppMenuMapper.java @@ -0,0 +1,37 @@ +package com.iailab.module.system.dal.mysql.app; + +import com.iailab.framework.mybatis.core.mapper.BaseMapperX; +import com.iailab.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; +import com.iailab.module.system.dal.dataobject.app.AppMenuDO; +import com.iailab.module.system.dal.dataobject.dept.DeptDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface AppMenuMapper extends BaseMapperX<AppMenuDO> { + + default AppMenuDO selectByParentIdAndName(Long parentId, String name) { + return selectOne(AppMenuDO::getParentId, parentId, AppMenuDO::getName, name); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(AppMenuDO::getParentId, parentId); + } + + default List<AppMenuDO> selectListByParentId(Collection<Long> parentIds) { + return selectList(AppMenuDO::getParentId, parentIds); + } + + default List<AppMenuDO> selectList(MenuListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX<AppMenuDO>() + .likeIfPresent(AppMenuDO::getName, reqVO.getName()) + .eqIfPresent(AppMenuDO::getStatus, reqVO.getStatus())); + } + + default List<AppMenuDO> selectListByPermission(String permission) { + return selectList(AppMenuDO::getPermission, permission); + } +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/permission/MenuMapper.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/permission/MenuMapper.java index 488688e..670d3ed 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/permission/MenuMapper.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/permission/MenuMapper.java @@ -6,6 +6,7 @@ import com.iailab.module.system.dal.dataobject.permission.MenuDO; import org.apache.ibatis.annotations.Mapper; +import java.util.Collection; import java.util.List; @Mapper @@ -25,7 +26,18 @@ .eqIfPresent(MenuDO::getStatus, reqVO.getStatus())); } + default List<MenuDO> selectAppMenuList(Long tenantId, MenuListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX<MenuDO>() + .likeIfPresent(MenuDO::getName, reqVO.getName()) + .eqIfPresent(MenuDO::getStatus, reqVO.getStatus()) + .eq(MenuDO::getTenantId, tenantId)); + } + default List<MenuDO> selectListByPermission(String permission) { return selectList(MenuDO::getPermission, permission); } + + default List<MenuDO> selectListByParentId(Collection<Long> parentIds) { + return selectList(MenuDO::getParentId, parentIds); + } } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/user/AdminUserMapper.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/user/AdminUserMapper.java index e0a47b9..b178be9 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/user/AdminUserMapper.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/dal/mysql/user/AdminUserMapper.java @@ -1,8 +1,10 @@ package com.iailab.module.system.dal.mysql.user; +import com.baomidou.dynamic.datasource.annotation.Master; import com.iailab.framework.common.pojo.PageResult; import com.iailab.framework.mybatis.core.mapper.BaseMapperX; import com.iailab.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.iailab.framework.tenant.core.db.dynamic.TenantDS; import com.iailab.module.system.controller.admin.user.vo.user.UserPageReqVO; import com.iailab.module.system.dal.dataobject.user.AdminUserDO; import org.apache.ibatis.annotations.Mapper; @@ -11,6 +13,7 @@ import java.util.List; @Mapper +@Master public interface AdminUserMapper extends BaseMapperX<AdminUserDO> { default AdminUserDO selectByUsername(String username) { diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppGroupService.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppGroupService.java new file mode 100644 index 0000000..6391ba9 --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppGroupService.java @@ -0,0 +1,31 @@ +package com.iailab.module.system.service.app; + +import com.iailab.framework.common.pojo.PageResult; +import com.iailab.module.system.controller.admin.app.vo.AppGroupPageReqVO; +import com.iailab.module.system.controller.admin.app.vo.AppGroupSaveReqVO; +import com.iailab.module.system.controller.admin.app.vo.AppPageReqVO; +import com.iailab.module.system.dal.dataobject.app.AppDO; +import com.iailab.module.system.dal.dataobject.app.AppGroupDO; + +import java.util.List; + +/** + * @author Houzhongjian + * @Description + * @createTime 2024年09月20日 + */ +public interface AppGroupService { + + Long create(AppGroupSaveReqVO createReqVO); + + Long update(AppGroupSaveReqVO createReqVO); + + void delete(Long id); + + AppGroupDO getInfo(Long id); + + PageResult<AppGroupDO> getPage(AppGroupPageReqVO pageReqVO); + + List<AppGroupDO> getList(); + +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppGroupServiceImpl.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppGroupServiceImpl.java new file mode 100644 index 0000000..318481b --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppGroupServiceImpl.java @@ -0,0 +1,72 @@ +package com.iailab.module.system.service.app; + +import com.iailab.framework.common.pojo.PageResult; +import com.iailab.framework.common.util.object.BeanUtils; +import com.iailab.framework.tenant.core.aop.TenantIgnore; +import com.iailab.module.system.controller.admin.app.vo.AppGroupPageReqVO; +import com.iailab.module.system.controller.admin.app.vo.AppGroupSaveReqVO; +import com.iailab.module.system.dal.dataobject.app.AppGroupDO; +import com.iailab.module.system.dal.mysql.app.AppGroupMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; + +/** + * @author Houzhongjian + * @Description + * @createTime 2024年09月20日 + */ +@Service +@Slf4j +public class AppGroupServiceImpl implements AppGroupService { + + @Resource + private AppGroupMapper appGroupMapper; + + + @Override + @Transactional(rollbackFor = Exception.class) + @TenantIgnore + public Long create(AppGroupSaveReqVO createReqVO) { + AppGroupDO appGroup = BeanUtils.toBean(createReqVO, AppGroupDO.class); + appGroupMapper.insert(appGroup); + return appGroup.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @TenantIgnore + public Long update(AppGroupSaveReqVO createReqVO) { + AppGroupDO appGroup = BeanUtils.toBean(createReqVO, AppGroupDO.class); + appGroupMapper.updateById(appGroup); + return appGroup.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @TenantIgnore + public void delete(Long id) { + AppGroupDO appGroup = new AppGroupDO(); + appGroup.setId(id); + appGroupMapper.deleteById(id); + } + + @Override + public AppGroupDO getInfo(Long id) { + return appGroupMapper.selectById(id); + } + + @Override + public PageResult<AppGroupDO> getPage(AppGroupPageReqVO pageReqVO) { + return appGroupMapper.selectPage(pageReqVO); + } + + @Override + public List<AppGroupDO> getList(){ + return appGroupMapper.selectList(); + } + +} \ No newline at end of file diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppMenuService.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppMenuService.java new file mode 100644 index 0000000..53aab58 --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppMenuService.java @@ -0,0 +1,118 @@ +package com.iailab.module.system.service.app; + + +import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; +import com.iailab.module.system.controller.admin.permission.vo.menu.MenuSaveVO; +import com.iailab.module.system.dal.dataobject.app.AppMenuDO; + +import java.util.Collection; +import java.util.List; + +/** + * 应用菜单 Service 接口 + * + * @author iailab + */ +public interface AppMenuService { + + /** + * 创建应用菜单 + * + * @param createReqVO 应用菜单信息 + * @return 创建出来的应用菜单编号 + */ + Long createMenu(MenuSaveVO createReqVO); + + /** + * 更新应用菜单 + * + * @param updateReqVO 应用菜单信息 + */ + void updateMenu(MenuSaveVO updateReqVO); + + /** + * 删除应用菜单 + * + * @param id 应用菜单编号 + */ + void deleteMenu(Long id); + + /** + * 获得所有应用菜单列表 + * + * @return 应用菜单列表 + */ + List<AppMenuDO> getMenuList(); + + /** + * 获得所有应用菜单列表 + * + * @return 应用菜单列表(API使用) + */ + List<AppMenuDO> getMenuList(Integer type); + + /** + * 基于租户,筛选应用菜单列表 + * 注意,如果是系统租户,返回的还是全应用菜单 + * + * @return 应用菜单列表(API使用) + */ + List<AppMenuDO> getMenuListByTenant(Integer type); + + /** + * 根据父菜单ID查询所有子菜单 + * + * @return 应用菜单列表(API使用) + */ + List<AppMenuDO> selectListByParentId(Collection<Long> parentIds); + + /** + * 基于租户,筛选应用菜单列表 + * 注意,如果是系统租户,返回的还是全应用菜单 + * + * @param reqVO 筛选条件请求 VO + * @return 应用菜单列表 + */ + List<AppMenuDO> getMenuListByTenant(MenuListReqVO reqVO); + + /** + * 过滤掉关闭的应用菜单及其子应用菜单 + * + * @param list 应用菜单列表 + * @return 过滤后的应用菜单列表 + */ + List<AppMenuDO> filterDisableMenus(List<AppMenuDO> list); + + /** + * 筛选应用菜单列表 + * + * @param reqVO 筛选条件请求 VO + * @return 应用菜单列表 + */ + List<AppMenuDO> getMenuList(MenuListReqVO reqVO); + + /** + * 获得权限对应的应用菜单编号数组 + * + * @param permission 权限标识 + * @return 数组 + */ + List<Long> getMenuIdListByPermissionFromCache(String permission); + + /** + * 获得应用菜单 + * + * @param id 应用菜单编号 + * @return 应用菜单 + */ + AppMenuDO getMenu(Long id); + + /** + * 获得应用菜单数组 + * + * @param ids 应用菜单编号数组 + * @return 应用菜单数组 + */ + List<AppMenuDO> getMenuList(Collection<Long> ids); + +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppMenuServiceImpl.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppMenuServiceImpl.java new file mode 100644 index 0000000..25ccd1f --- /dev/null +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppMenuServiceImpl.java @@ -0,0 +1,281 @@ +package com.iailab.module.system.service.app; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Lists; +import com.iailab.framework.common.enums.CommonStatusEnum; +import com.iailab.framework.common.util.object.BeanUtils; +import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; +import com.iailab.module.system.controller.admin.permission.vo.menu.MenuSaveVO; +import com.iailab.module.system.dal.dataobject.app.AppMenuDO; +import com.iailab.module.system.dal.mysql.app.AppMenuMapper; +import com.iailab.module.system.dal.redis.RedisKeyConstants; +import com.iailab.module.system.enums.permission.MenuTypeEnum; +import com.iailab.module.system.service.tenant.TenantService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.*; + +import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.iailab.framework.common.util.collection.CollectionUtils.convertList; +import static com.iailab.framework.common.util.collection.CollectionUtils.convertMap; +import static com.iailab.module.system.dal.dataobject.app.AppMenuDO.ID_ROOT; +import static com.iailab.module.system.enums.ErrorCodeConstants.*; + + +/** + * 菜单 Service 实现 + * + * @author iailab + */ +@Service +@Slf4j +public class AppMenuServiceImpl implements AppMenuService { + + @Resource + private AppMenuMapper appMenuMapper; + @Resource + @Lazy // 延迟,避免循环依赖报错 + private TenantService tenantService; + + @Override + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#createReqVO.permission", + condition = "#createReqVO.permission != null") + public Long createMenu(MenuSaveVO createReqVO) { + // 校验父菜单存在 + validateParentMenu(createReqVO.getParentId(), null); + // 校验菜单(自己) + validateMenu(createReqVO.getParentId(), createReqVO.getName(), null); + + // 插入数据库 + AppMenuDO menu = BeanUtils.toBean(createReqVO, AppMenuDO.class); + initMenuProperty(menu); + appMenuMapper.insert(menu); + // 返回 + return menu.getId(); + } + + @Override + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为 permission 如果变更,涉及到新老两个 permission。直接清理,简单有效 + public void updateMenu(MenuSaveVO updateReqVO) { + // 校验更新的菜单是否存在 + if (appMenuMapper.selectById(updateReqVO.getId()) == null) { + throw exception(MENU_NOT_EXISTS); + } + // 校验父菜单存在 + validateParentMenu(updateReqVO.getParentId(), updateReqVO.getId()); + // 校验菜单(自己) + validateMenu(updateReqVO.getParentId(), updateReqVO.getName(), updateReqVO.getId()); + + // 更新到数据库 + AppMenuDO updateObj = BeanUtils.toBean(updateReqVO, AppMenuDO.class); + initMenuProperty(updateObj); + appMenuMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为此时不知道 id 对应的 permission 是多少。直接清理,简单有效 + public void deleteMenu(Long id) { + // 校验是否还有子菜单 + if (appMenuMapper.selectCountByParentId(id) > 0) { + throw exception(MENU_EXISTS_CHILDREN); + } + // 校验删除的菜单是否存在 + if (appMenuMapper.selectById(id) == null) { + throw exception(MENU_NOT_EXISTS); + } + // 标记删除 + appMenuMapper.deleteById(id); + } + + @Override + public List<AppMenuDO> getMenuList() { + return appMenuMapper.selectList(); + } + + @Override + public List<AppMenuDO> getMenuList(Integer type) { + LambdaQueryWrapper<AppMenuDO> queryWrapper = new LambdaQueryWrapper<>(); + if (type == 1) { + queryWrapper.eq(AppMenuDO::getType, type); + } + return appMenuMapper.selectList(queryWrapper); + } + + @Override + public List<AppMenuDO> getMenuListByTenant(Integer type) { + // 查询所有菜单,并过滤掉关闭的节点 + List<AppMenuDO> menus = getMenuList(type); + // 开启多租户的情况下,需要过滤掉未开通的菜单 + tenantService.handleTenantMenu(menuIds -> menus.removeIf(menu -> !CollUtil.contains(menuIds, menu.getId()))); + return menus; + } + + @Override + public List<AppMenuDO> selectListByParentId(Collection<Long> parentIds) { + return appMenuMapper.selectListByParentId(parentIds); + } + + @Override + public List<AppMenuDO> getMenuListByTenant(MenuListReqVO reqVO) { + // 查询所有菜单,并过滤掉关闭的节点 + List<AppMenuDO> menus = getMenuList(reqVO); + // 开启多租户的情况下,需要过滤掉未开通的菜单 + tenantService.handleTenantMenu(menuIds -> menus.removeIf(menu -> !CollUtil.contains(menuIds, menu.getId()))); + return menus; + } + + @Override + public List<AppMenuDO> filterDisableMenus(List<AppMenuDO> menuList) { + if (CollUtil.isEmpty(menuList)){ + return Collections.emptyList(); + } + Map<Long, AppMenuDO> menuMap = convertMap(menuList, AppMenuDO::getId); + + // 遍历 menu 菜单,查找不是禁用的菜单,添加到 enabledMenus 结果 + List<AppMenuDO> enabledMenus = new ArrayList<>(); + Set<Long> disabledMenuCache = new HashSet<>(); // 存下递归搜索过被禁用的菜单,防止重复的搜索 + for (AppMenuDO menu : menuList) { + if (isMenuDisabled(menu, menuMap, disabledMenuCache)) { + continue; + } + enabledMenus.add(menu); + } + return enabledMenus; + } + + private boolean isMenuDisabled(AppMenuDO node, Map<Long, AppMenuDO> menuMap, Set<Long> disabledMenuCache) { + // 如果已经判定是禁用的节点,直接结束 + if (disabledMenuCache.contains(node.getId())) { + return true; + } + + // 1. 遍历到 parentId 为根节点,则无需判断 + Long parentId = node.getParentId(); + if (ObjUtil.equal(parentId, ID_ROOT)) { + if (CommonStatusEnum.isDisable(node.getStatus())) { + disabledMenuCache.add(node.getId()); + return true; + } + return false; + } + + // 2. 继续遍历 parent 节点 + AppMenuDO parent = menuMap.get(parentId); + if (parent == null || isMenuDisabled(parent, menuMap, disabledMenuCache)) { + disabledMenuCache.add(node.getId()); + return true; + } + return false; + } + + @Override + public List<AppMenuDO> getMenuList(MenuListReqVO reqVO) { + return appMenuMapper.selectList(reqVO); + } + + @Override + @Cacheable(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#permission") + public List<Long> getMenuIdListByPermissionFromCache(String permission) { + List<AppMenuDO> menus = appMenuMapper.selectListByPermission(permission); + return convertList(menus, AppMenuDO::getId); + } + + @Override + public AppMenuDO getMenu(Long id) { + return appMenuMapper.selectById(id); + } + + @Override + public List<AppMenuDO> getMenuList(Collection<Long> ids) { + // 当 ids 为空时,返回一个空的实例对象 + if (CollUtil.isEmpty(ids)) { + return Lists.newArrayList(); + } + return appMenuMapper.selectBatchIds(ids); + } + + /** + * 校验父菜单是否合法 + * <p> + * 1. 不能设置自己为父菜单 + * 2. 父菜单不存在 + * 3. 父菜单必须是 {@link MenuTypeEnum#MENU} 菜单类型 + * + * @param parentId 父菜单编号 + * @param childId 当前菜单编号 + */ + @VisibleForTesting + void validateParentMenu(Long parentId, Long childId) { + if (parentId == null || ID_ROOT.equals(parentId)) { + return; + } + // 不能设置自己为父菜单 + if (parentId.equals(childId)) { + throw exception(MENU_PARENT_ERROR); + } + AppMenuDO menu = appMenuMapper.selectById(parentId); + // 父菜单不存在 + if (menu == null) { + throw exception(MENU_PARENT_NOT_EXISTS); + } + // 父菜单必须是目录或者菜单类型 + if (!MenuTypeEnum.DIR.getType().equals(menu.getType()) + && !MenuTypeEnum.MENU.getType().equals(menu.getType())) { + throw exception(MENU_PARENT_NOT_DIR_OR_MENU); + } + } + + /** + * 校验菜单是否合法 + * <p> + * 1. 校验相同父菜单编号下,是否存在相同的菜单名 + * + * @param name 菜单名字 + * @param parentId 父菜单编号 + * @param id 菜单编号 + */ + @VisibleForTesting + void validateMenu(Long parentId, String name, Long id) { + AppMenuDO menu = appMenuMapper.selectByParentIdAndName(parentId, name); + if (menu == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的菜单 + if (id == null) { + throw exception(MENU_NAME_DUPLICATE); + } + if (!menu.getId().equals(id)) { + throw exception(MENU_NAME_DUPLICATE); + } + } + + /** + * 初始化菜单的通用属性。 + * <p> + * 例如说,只有目录或者菜单类型的菜单,才设置 icon + * + * @param menu 菜单 + */ + private void initMenuProperty(AppMenuDO menu) { + // 菜单为按钮类型时,无需 component、icon、path 属性,进行置空 + if (MenuTypeEnum.BUTTON.getType().equals(menu.getType())) { + menu.setComponent(""); + menu.setComponentName(""); + menu.setIcon(""); + menu.setPath(""); + } + } + +} diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppService.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppService.java index 8c9bd4e..e903e4f 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppService.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppService.java @@ -5,6 +5,8 @@ import com.iailab.module.system.controller.admin.app.vo.AppSaveReqVO; import com.iailab.module.system.dal.dataobject.app.AppDO; +import java.util.List; + /** * @author PanZhibao * @Description @@ -21,4 +23,11 @@ AppDO getInfo(Long id); PageResult<AppDO> getPage(AppPageReqVO pageReqVO); + + List<AppDO> getList(); + + AppDO getAppByTenantId(Long tenantId); + +// List<AppMenuRespDTO> getAppMenu(Long id); + } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppServiceImpl.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppServiceImpl.java index cbfe760..c090de3 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppServiceImpl.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppServiceImpl.java @@ -1,15 +1,40 @@ package com.iailab.module.system.service.app; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.iailab.framework.common.pojo.PageResult; import com.iailab.framework.common.util.object.BeanUtils; +import com.iailab.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.iailab.framework.security.core.util.SecurityFrameworkUtils; +import com.iailab.framework.tenant.core.aop.TenantIgnore; import com.iailab.module.system.controller.admin.app.vo.AppPageReqVO; import com.iailab.module.system.controller.admin.app.vo.AppSaveReqVO; import com.iailab.module.system.dal.dataobject.app.AppDO; +import com.iailab.module.system.dal.dataobject.permission.MenuDO; +import com.iailab.module.system.dal.dataobject.permission.RoleDO; +import com.iailab.module.system.dal.dataobject.permission.RoleMenuDO; +import com.iailab.module.system.dal.dataobject.tenant.TenantDO; +import com.iailab.module.system.dal.dataobject.tenant.TenantPackageDO; import com.iailab.module.system.dal.mysql.app.AppMapper; +import com.iailab.module.system.dal.mysql.permission.MenuMapper; +import com.iailab.module.system.dal.mysql.permission.RoleMapper; +import com.iailab.module.system.dal.mysql.permission.RoleMenuMapper; +import com.iailab.module.system.dal.mysql.tenant.TenantMapper; +import com.iailab.module.system.dal.mysql.tenant.TenantPackageMapper; +import com.iailab.module.system.enums.permission.MenuTypeEnum; +import com.iailab.module.system.service.permission.PermissionService; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ObjectUtils; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.util.*; + +import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.iailab.framework.tenant.core.context.TenantContextHolder.getTenantId; +import static com.iailab.module.system.enums.ErrorCodeConstants.MENU_EXISTS_CHILDREN; +import static com.iailab.module.system.enums.ErrorCodeConstants.MENU_NOT_EXISTS; /** * @author PanZhibao @@ -23,23 +48,54 @@ @Resource private AppMapper appMapper; + @Resource + private MenuMapper menuMapper; + + @Resource + private RoleMapper roleMapper; + + @Resource + private RoleMenuMapper roleMenuMapper; + + @Resource + private PermissionService permissionService; + + @Resource + private TenantPackageMapper tenantPackageMapper; + + @Resource + private TenantMapper tenantMapper; + @Override + @Transactional(rollbackFor = Exception.class) + @TenantIgnore public Long create(AppSaveReqVO createReqVO) { AppDO app = BeanUtils.toBean(createReqVO, AppDO.class); appMapper.insert(app); +// //为应用创建默认菜单并授权 + dealAppMenu(1, app); return app.getId(); } @Override + @Transactional(rollbackFor = Exception.class) + @TenantIgnore public Long update(AppSaveReqVO createReqVO) { AppDO app = BeanUtils.toBean(createReqVO, AppDO.class); appMapper.updateById(app); +// //修改默认菜单并授权 + dealAppMenu(2, app); return app.getId(); } @Override + @Transactional(rollbackFor = Exception.class) + @TenantIgnore public void delete(Long id) { + AppDO appDO = new AppDO(); + appDO.setId(id); + dealAppMenu(3, appDO); appMapper.deleteById(id); } @@ -53,4 +109,164 @@ return appMapper.selectPage(pageReqVO); } + @Override + public List<AppDO> getList() { + Long tenantId = getTenantId(); + LambdaQueryWrapperX<MenuDO> menuDOLambdaQueryWrapperX = new LambdaQueryWrapperX<>(); + menuDOLambdaQueryWrapperX.eq(MenuDO::getParentId, 0) + .eq(MenuDO::getAppId, 0); + if (tenantId != 1) { + //非系统租户查租户套餐 + TenantDO tenantDO = tenantMapper.selectById(tenantId); + TenantPackageDO tenantPackageDO = tenantPackageMapper.selectById(tenantDO.getPackageId()); + menuDOLambdaQueryWrapperX.in(MenuDO::getId, tenantPackageDO.getMenuIds()); + } + //查询系统应用菜单 +// List<MenuDO> menuDOS = menuMapper.selectList(menuDOLambdaQueryWrapperX); +// List<AppDO> systemApps = convertMenuToApp(menuDOS); + //创建一个系统管理应用菜单 + AppDO aDo = new AppDO(); + aDo.setAppType(1); + aDo.setAppName("系统管理"); + aDo.setOrderNum(0); + List<AppDO> systemApps = new ArrayList<>(); + systemApps.add(aDo); + List<AppDO> appDOS = appMapper.selectList(); + //暂时先遍历处理应用菜单和应用类型 + appDOS.stream().forEach(appDO -> { + List<MenuDO> menuDOS = menuMapper.selectList(new LambdaQueryWrapper<MenuDO>().eq(MenuDO::getParentId, 0) + .eq(MenuDO::getAppId, appDO.getId())); + appDO.setAppMenuId(menuDOS.get(0).getId()); + appDO.setAppType(2); + }); + systemApps.addAll(appDOS); + return systemApps; + } + + @Override + public AppDO getAppByTenantId(Long tenantId) { + //暂时支持一个租户对应一个应用 + List<AppDO> appDOS = appMapper.selectList(new LambdaQueryWrapper<AppDO>().eq(AppDO::getTenantId, tenantId)); + if(ObjectUtils.isNotEmpty(appDOS)) { + return appDOS.get(0); + } else { + AppDO appDO = new AppDO(); + appDO.setTenantId(tenantId); + appDO.setId(0L); + return appDO; + } + } + +// @Override +// public List<MenuRespDTO> getAppMenu(Long id) { +// +// List<MenuDO> children = new LinkedList<>(); +// // 遍历每一层 +// Collection<Long> parentIds = Collections.singleton(id); +// for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 +// // 查询当前层,所有的子应用菜单 +// List<MenuDO> menus = menuMapper.selectListByParentId(parentIds); +// // 1. 如果没有子菜单,则结束遍历 +// if (CollUtil.isEmpty(menus)) { +// break; +// } +// // 2. 如果有子应用菜单,继续遍历 +// children.addAll(menus); +// parentIds = convertSet(menus, MenuDO::getId); +// } +// children = menuService.filterDisableMenus(children); +// return AuthConvert.INSTANCE.buildMenuTree(id, children); +// +// } + + private void dealAppMenu(Integer type, AppDO app){ + String loginUserNickname = SecurityFrameworkUtils.getLoginUserNickname(); + MenuDO menuDO = new MenuDO(); + menuDO.setAppId(app.getId()); + menuDO.setName(app.getAppName()); + menuDO.setType(MenuTypeEnum.DIR.getType()); + menuDO.setSort(app.getOrderNum()); + menuDO.setPath("/" + app.getAppCode()); + menuDO.setTenantId(app.getTenantId()); + if(type == 1){ + menuDO.setCreator(loginUserNickname); + menuDO.setCreateTime(app.getCreateTime()); + menuMapper.insert(menuDO); + //内置租户角色分配菜单 + assignRoleMenu(menuDO.getId(), app.getTenantId()); + } else if(type == 2){ + LambdaUpdateWrapper<MenuDO> updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(MenuDO::getAppId, app.getId()); + updateWrapper.eq(MenuDO::getParentId, 0L); + List<MenuDO> menuDOS = menuMapper.selectList(updateWrapper); + if(menuDOS.size() > 0){ + menuDO.setUpdater(loginUserNickname); + menuDO.setUpdateTime(app.getUpdateTime()); + menuMapper.update(menuDO, updateWrapper); + } else { + menuDO.setCreator(loginUserNickname); + menuDO.setCreateTime(app.getCreateTime()); + menuMapper.insert(menuDO); + //内置租户角色分配菜单 + assignRoleMenu(menuDO.getId(), app.getTenantId()); + } + } else if(type == 3){ + //删除租户、角色权限 + app = appMapper.selectById(app.getId()); + LambdaQueryWrapperX<MenuDO> menuWrapper = new LambdaQueryWrapperX<>(); + menuWrapper.eq(MenuDO::getAppId, app.getId()); + menuWrapper.eq(MenuDO::getType, MenuTypeEnum.DIR.getType()); + MenuDO menu = menuMapper.selectOne(menuWrapper); + TenantDO tenantDO = tenantMapper.selectById(app.getTenantId()); + TenantPackageDO tenantPackageDO = tenantPackageMapper.selectById(tenantDO.getPackageId()); + Set<Long> menuIds = tenantPackageDO.getMenuIds(); + menuIds.remove(menu.getId()); + // 校验是否还有子菜单 + if (menuMapper.selectCountByParentId(menu.getId()) > 0) { + throw exception(MENU_EXISTS_CHILDREN); + } + // 校验删除的菜单是否存在 + if (menuMapper.selectById(menu.getId()) == null) { + throw exception(MENU_NOT_EXISTS); + } + // 标记删除 + menuMapper.deleteById(menu.getId()); + // 删除授予给角色的权限 + permissionService.processMenuDeleted(menu.getId()); + //删除菜单 + menuMapper.delete(menuWrapper); + } + } + + private void assignRoleMenu(Long menuId, Long tenantId) { + //查询内置租户管理员 + LambdaQueryWrapperX<RoleDO> roleQueryWrapper = new LambdaQueryWrapperX<>(); + roleQueryWrapper.eq(RoleDO::getCode, "tenant_admin"); + roleQueryWrapper.eq(RoleDO::getTenantId, tenantId); + RoleDO roleDO = roleMapper.selectOne(roleQueryWrapper); + RoleMenuDO entity = new RoleMenuDO(); + entity.setRoleId(roleDO.getId()); + entity.setMenuId(menuId); + entity.setTenantId(tenantId); + roleMenuMapper.insert(entity); + TenantDO tenantDO = tenantMapper.selectById(tenantId); + TenantPackageDO tenantPackageDO = tenantPackageMapper.selectById(tenantDO.getPackageId()); + Set<Long> menuIds = tenantPackageDO.getMenuIds(); + menuIds.add(menuId); + tenantPackageMapper.updateById(tenantPackageDO); + } + + private List<AppDO> convertMenuToApp(List<MenuDO> menuDOS) { + List<AppDO> appDOS = new ArrayList<>(); + menuDOS.stream().forEach(menuDO -> { + AppDO appDO = new AppDO(); + appDO.setAppName(menuDO.getName()); + appDO.setOrderNum(menuDO.getSort()); + appDO.setAppMenuId(menuDO.getId()); + appDO.setAppType(1); + appDOS.add(appDO); + }); + return appDOS; + } + } \ No newline at end of file diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuService.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuService.java index 705bd83..2ab458b 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuService.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuService.java @@ -54,6 +54,15 @@ List<MenuDO> getMenuListByTenant(MenuListReqVO reqVO); /** + * 基于租户,筛选应用菜单列表 + * 注意,如果是系统租户,返回的还是全菜单 + * + * @param reqVO 筛选条件请求 VO + * @return 应用菜单列表 + */ + List<MenuDO> getAppMenuListByTenant(MenuListReqVO reqVO); + + /** * 过滤掉关闭的菜单及其子菜单 * * @param list 菜单列表 @@ -70,6 +79,14 @@ List<MenuDO> getMenuList(MenuListReqVO reqVO); /** + * 筛选菜单列表 + * + * @param reqVO 筛选条件请求 VO + * @return 菜单列表 + */ + List<MenuDO> getAppMenuList(MenuListReqVO reqVO); + + /** * 获得权限对应的菜单编号数组 * * @param permission 权限标识 diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuServiceImpl.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuServiceImpl.java index b93065a..17d7e40 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuServiceImpl.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuServiceImpl.java @@ -8,12 +8,20 @@ import com.iailab.framework.common.util.object.BeanUtils; import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; import com.iailab.module.system.controller.admin.permission.vo.menu.MenuSaveVO; +import com.iailab.module.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; +import com.iailab.module.system.dal.dataobject.app.AppDO; import com.iailab.module.system.dal.dataobject.permission.MenuDO; +import com.iailab.module.system.dal.dataobject.permission.RoleDO; +import com.iailab.module.system.dal.dataobject.tenant.TenantDO; +import com.iailab.module.system.dal.dataobject.tenant.TenantPackageDO; import com.iailab.module.system.dal.mysql.permission.MenuMapper; import com.iailab.module.system.dal.redis.RedisKeyConstants; import com.iailab.module.system.enums.permission.MenuTypeEnum; +import com.iailab.module.system.service.app.AppService; +import com.iailab.module.system.service.tenant.TenantPackageService; import com.iailab.module.system.service.tenant.TenantService; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ObjectUtils; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.annotation.Lazy; @@ -26,6 +34,7 @@ import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.iailab.framework.common.util.collection.CollectionUtils.convertList; import static com.iailab.framework.common.util.collection.CollectionUtils.convertMap; +import static com.iailab.framework.tenant.core.context.TenantContextHolder.getTenantId; import static com.iailab.module.system.dal.dataobject.permission.MenuDO.ID_ROOT; import static com.iailab.module.system.enums.ErrorCodeConstants.*; @@ -47,9 +56,19 @@ @Lazy // 延迟,避免循环依赖报错 private TenantService tenantService; + @Resource + private TenantPackageService tenantPackageService; + + @Resource + private AppService appService; + + @Resource + private RoleService roleService; + @Override @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#createReqVO.permission", condition = "#createReqVO.permission != null") + @Transactional(rollbackFor = Exception.class) public Long createMenu(MenuSaveVO createReqVO) { // 校验父菜单存在 validateParentMenu(createReqVO.getParentId(), null); @@ -59,7 +78,15 @@ // 插入数据库 MenuDO menu = BeanUtils.toBean(createReqVO, MenuDO.class); initMenuProperty(menu); + + //菜单归属租户和应用 + Long tenantId = getTenantId(); + menu.setTenantId(tenantId); + menu.setAppId(createReqVO.getAppId()); menuMapper.insert(menu); + if(tenantId != 1L) { + dealPermission(menu); + } // 返回 return menu.getId(); } @@ -67,6 +94,7 @@ @Override @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, allEntries = true) // allEntries 清空所有缓存,因为 permission 如果变更,涉及到新老两个 permission。直接清理,简单有效 + @Transactional(rollbackFor = Exception.class) public void updateMenu(MenuSaveVO updateReqVO) { // 校验更新的菜单是否存在 if (menuMapper.selectById(updateReqVO.getId()) == null) { @@ -80,6 +108,11 @@ // 更新到数据库 MenuDO updateObj = BeanUtils.toBean(updateReqVO, MenuDO.class); initMenuProperty(updateObj); + //菜单归属租户和应用 + Long tenantId = getTenantId(); + AppDO appDO = appService.getAppByTenantId(tenantId); + updateObj.setTenantId(tenantId); + updateObj.setAppId(appDO.getId()); menuMapper.updateById(updateObj); } @@ -111,6 +144,15 @@ public List<MenuDO> getMenuListByTenant(MenuListReqVO reqVO) { // 查询所有菜单,并过滤掉关闭的节点 List<MenuDO> menus = getMenuList(reqVO); + // 开启多租户的情况下,需要过滤掉未开通的菜单 + tenantService.handleTenantMenu(menuIds -> menus.removeIf(menu -> !CollUtil.contains(menuIds, menu.getId()))); + return menus; + } + + @Override + public List<MenuDO> getAppMenuListByTenant(MenuListReqVO reqVO) { + // 查询所有菜单,并过滤掉关闭的节点 + List<MenuDO> menus = getAppMenuList(reqVO); // 开启多租户的情况下,需要过滤掉未开通的菜单 tenantService.handleTenantMenu(menuIds -> menus.removeIf(menu -> !CollUtil.contains(menuIds, menu.getId()))); return menus; @@ -163,6 +205,13 @@ @Override public List<MenuDO> getMenuList(MenuListReqVO reqVO) { return menuMapper.selectList(reqVO); + } + + @Override + public List<MenuDO> getAppMenuList(MenuListReqVO reqVO) { + // 获取 tenantId + Long tenantId = getTenantId(); + return menuMapper.selectAppMenuList(tenantId, reqVO); } @Override @@ -258,4 +307,20 @@ } } + /** + * 新创建菜单赋权给租户管理员 + */ + + private void dealPermission(MenuDO menu) { + Long tenantId = menu.getTenantId(); + RoleDO role = roleService.getTenantAdminRole(tenantId); + TenantDO tenant = tenantService.getTenant(tenantId); + TenantPackageDO tenantPackage = tenantPackageService.getTenantPackage(tenant.getPackageId()); + Set<Long> menuIds = tenantPackage.getMenuIds(); + menuIds.add(menu.getId()); + tenantPackage.setMenuIds(menuIds); + tenantPackageService.updateTenantPackage(BeanUtils.toBean(tenantPackage, TenantPackageSaveReqVO.class)); + permissionService.assignRoleMenu(role.getId(), menuIds); + } + } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionService.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionService.java index 6bcb967..dfa9825 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionService.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionService.java @@ -44,6 +44,14 @@ void assignRoleMenu(Long roleId, Set<Long> menuIds); /** + * 设置角色应用菜单 + * + * @param roleId 角色编号 + * @param menuIds 菜单编号集合 + */ + void assignRoleAppMenu(Long roleId, Set<Long> menuIds); + + /** * 处理角色删除时,删除关联授权数据 * * @param roleId 角色编号 @@ -68,6 +76,16 @@ } /** + * 获得角色拥有的应用菜单编号集合 + * + * @param roleId 角色编号 + * @return 菜单编号集合 + */ + default Set<Long> getRoleAppMenuListByRoleId(Long roleId) { + return getRoleAppMenuListByRoleId(singleton(roleId)); + } + + /** * 获得角色们拥有的菜单编号集合 * * @param roleIds 角色编号数组 @@ -76,6 +94,14 @@ Set<Long> getRoleMenuListByRoleId(Collection<Long> roleIds); /** + * 获得角色们拥有的应用菜单编号集合 + * + * @param roleIds 角色编号数组 + * @return 菜单编号集合 + */ + Set<Long> getRoleAppMenuListByRoleId(Collection<Long> roleIds); + + /** * 获得拥有指定菜单的角色编号数组,从缓存中获取 * * @param menuId 菜单编号 diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionServiceImpl.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionServiceImpl.java index ad8e0a9..a4deaf4 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionServiceImpl.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionServiceImpl.java @@ -8,15 +8,22 @@ import com.iailab.framework.common.util.collection.CollectionUtils; import com.iailab.framework.datapermission.core.annotation.DataPermission; import com.iailab.module.system.api.permission.dto.DeptDataPermissionRespDTO; +import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; +import com.iailab.module.system.dal.dataobject.app.AppDO; import com.iailab.module.system.dal.dataobject.permission.MenuDO; import com.iailab.module.system.dal.dataobject.permission.RoleDO; import com.iailab.module.system.dal.dataobject.permission.RoleMenuDO; import com.iailab.module.system.dal.dataobject.permission.UserRoleDO; +import com.iailab.module.system.dal.dataobject.tenant.TenantDO; +import com.iailab.module.system.dal.dataobject.tenant.TenantPackageDO; import com.iailab.module.system.dal.mysql.permission.RoleMenuMapper; import com.iailab.module.system.dal.mysql.permission.UserRoleMapper; import com.iailab.module.system.dal.redis.RedisKeyConstants; import com.iailab.module.system.enums.permission.DataScopeEnum; +import com.iailab.module.system.service.app.AppService; import com.iailab.module.system.service.dept.DeptService; +import com.iailab.module.system.service.tenant.TenantPackageService; +import com.iailab.module.system.service.tenant.TenantService; import com.iailab.module.system.service.user.AdminUserService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.google.common.annotations.VisibleForTesting; @@ -35,6 +42,7 @@ import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet; import static com.iailab.framework.common.util.json.JsonUtils.toJsonString; +import static com.iailab.framework.tenant.core.context.TenantContextHolder.getTenantId; /** * 权限 Service 实现类 @@ -58,6 +66,13 @@ private DeptService deptService; @Resource private AdminUserService userService; + @Resource + private TenantService tenantService; + @Resource + private TenantPackageService tenantPackageService; + @Resource + private AppService appService; + @Override public boolean hasAnyPermissions(Long userId, String... permissions) { @@ -155,6 +170,37 @@ } } + // ========== 角色-菜单的相关方法 ========== + + @Override + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快 + public void assignRoleAppMenu(Long roleId, Set<Long> menuIds) { + // 获得角色拥有应用菜单编号 + MenuListReqVO reqVO = new MenuListReqVO(); + List<MenuDO> appMenuList = menuService.getAppMenuList(reqVO); + Set<Long> appMenuIds = convertSet(appMenuList, MenuDO::getId); + Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); + dbMenuIds.retainAll(appMenuIds); + // 计算新增和删除的菜单编号 + Set<Long> menuIdList = CollUtil.emptyIfNull(menuIds); + Collection<Long> createMenuIds = CollUtil.subtract(menuIdList, dbMenuIds); + Collection<Long> deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIdList); + // 执行新增和删除。对于已经授权的菜单,不用做任何处理 + if (CollUtil.isNotEmpty(createMenuIds)) { + roleMenuMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> { + RoleMenuDO entity = new RoleMenuDO(); + entity.setRoleId(roleId); + entity.setMenuId(menuId); + return entity; + })); + } + if (CollUtil.isNotEmpty(deleteMenuIds)) { + roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds); + } + } + @Override @Transactional(rollbackFor = Exception.class) @Caching(evict = { @@ -181,16 +227,32 @@ if (CollUtil.isEmpty(roleIds)) { return Collections.emptySet(); } - - // 如果是管理员的情况下,获取全部菜单编号 - if (roleService.hasAnySuperAdmin(roleIds)) { - return convertSet(menuService.getMenuList(), MenuDO::getId); - } - // 如果是非管理员的情况下,获得拥有的菜单编号 return convertSet(roleMenuMapper.selectListByRoleId(roleIds), RoleMenuDO::getMenuId); } @Override + public Set<Long> getRoleAppMenuListByRoleId(Collection<Long> roleIds) { + if (CollUtil.isEmpty(roleIds)) { + return Collections.emptySet(); + } + + // 如果是管理员的情况下,获取全部应用菜单编号 + if (roleService.hasAnySuperAdmin(roleIds)) { + MenuListReqVO reqVO = new MenuListReqVO(); + return convertSet(menuService.getAppMenuList(reqVO), MenuDO::getId); + } + // 如果是非管理员的情况下,获得拥有的应用菜单编号 + // 获取 tenantId + Long tenantId = getTenantId(); + TenantDO tenant = tenantService.getTenant(tenantId); + TenantPackageDO tenantPackage = tenantPackageService.getTenantPackage(tenant.getPackageId()); + Set<Long> menuIds = tenantPackage.getMenuIds(); + Set<Long> longs = convertSet(roleMenuMapper.selectListByRoleId(roleIds), RoleMenuDO::getMenuId); + longs.retainAll(menuIds); + return longs; + } + + @Override @Cacheable(value = RedisKeyConstants.MENU_ROLE_ID_LIST, key = "#menuId") public Set<Long> getMenuRoleIdListByMenuIdFromCache(Long menuId) { return convertSet(roleMenuMapper.selectListByMenuId(menuId), RoleMenuDO::getRoleId); diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/RoleService.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/RoleService.java index ebeb949..0c9e8d4 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/RoleService.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/RoleService.java @@ -130,4 +130,6 @@ RoleDO getRoleByName(String name); void insert(RoleDO role); + + RoleDO getTenantAdminRole(Long tenantId); } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/RoleServiceImpl.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/RoleServiceImpl.java index b4ae471..d77d9b3 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/RoleServiceImpl.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/RoleServiceImpl.java @@ -269,4 +269,12 @@ return SpringUtil.getBean(getClass()); } + /** + * 查询租户管理员 + */ + public RoleDO getTenantAdminRole(Long tenantId) { + RoleDO roleDO = roleMapper.selectOne(new LambdaQueryWrapperX<RoleDO>().eq(RoleDO::getType, 1L).eq(RoleDO::getTenantId, tenantId)); + return roleDO; + } + } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/tenant/TenantService.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/tenant/TenantService.java index 35fc598..fba01cb 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/tenant/TenantService.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/tenant/TenantService.java @@ -66,6 +66,13 @@ PageResult<TenantDO> getTenantPage(TenantPageReqVO pageReqVO); /** + * 获得租户列表 + * + * @return 租户列表 + */ + List<TenantDO> getSimpleTenant(); + + /** * 获得名字对应的租户 * * @param name 租户名 diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/tenant/TenantServiceImpl.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/tenant/TenantServiceImpl.java index f0e3da3..4a6154e 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/tenant/TenantServiceImpl.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/tenant/TenantServiceImpl.java @@ -37,6 +37,7 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Set; @@ -246,6 +247,11 @@ } @Override + public List<TenantDO> getSimpleTenant() { + return tenantMapper.selectList(); + } + + @Override public TenantDO getTenantByName(String name) { return tenantMapper.selectByName(name); } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/user/AdminUserServiceImpl.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/user/AdminUserServiceImpl.java index 3c2648e..cfa0743 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/user/AdminUserServiceImpl.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/user/AdminUserServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.StrUtil; +import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.iailab.framework.common.enums.CommonStatusEnum; import com.iailab.framework.common.exception.ServiceException; import com.iailab.framework.common.pojo.PageResult; @@ -85,7 +86,7 @@ private ConfigApi configApi; @Override - @Transactional(rollbackFor = Exception.class) + @DSTransactional @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.id}}", success = SYSTEM_USER_CREATE_SUCCESS) public Long createUser(UserSaveReqVO createReqVO) { @@ -116,7 +117,7 @@ } @Override - @Transactional(rollbackFor = Exception.class) + @DSTransactional @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", success = SYSTEM_USER_UPDATE_SUCCESS) public void updateUser(UserSaveReqVO updateReqVO) { -- Gitblit v1.9.3